2 * X11 physical font objects
4 * Copyright 1997 Alex Korobka
6 * TODO: Mapping algorithm tweaks, FO_SYNTH_... flags (ExtTextOut() will
7 * have to be changed for that), dynamic font loading (FreeType).
16 #include <sys/types.h>
20 #include <X11/Xatom.h>
29 #define X_PFONT_MAGIC (0xFADE0000)
30 #define X_FMC_MAGIC (0x0000CAFE)
32 #define MAX_FONT_FAMILIES 128
33 #define MAX_LFD_LENGTH 256
35 #define MAX_FONT_SIZE 5000 /* Max size in pixels */
37 #define REMOVE_SUBSETS 1
38 #define UNMARK_SUBSETS 0
40 #define DEF_SCALABLE_HEIGHT 24
41 #define DEF_SCALABLE_DP 240
43 #define FF_FAMILY (FF_MODERN | FF_SWISS | FF_ROMAN | FF_DECORATIVE | FF_SCRIPT)
45 typedef struct __fontAlias
49 struct __fontAlias
* next
;
58 /* Font alias table - these 2 aliases are always present */
59 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
61 static fontAlias __aliasTable
[2] = {
62 { NULL
, "Helv", &__aliasTable
[1] },
63 { NULL
, "Tms Rmn", NULL
}
66 static fontAlias
*aliasTable
= __aliasTable
;
68 /* Optional built-in aliases, they are installed only when X
69 * cannot supply us with original MS fonts */
70 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
72 static int faTemplateNum
= 4;
73 static aliasTemplate faTemplate
[4] = {
74 { NULL
, "MS Sans Serif" },
76 { "-adobe-times-", "Times New Roman" },
77 { "-adobe-helvetica-", "Arial" }
80 UINT16 XTextCaps
= TC_OP_CHARACTER
| TC_OP_STROKE
|
81 TC_CP_STROKE
| TC_CR_ANY
|
82 TC_SA_DOUBLE
| TC_SA_INTEGER
| TC_SA_CONTIN
|
83 TC_UA_ABLE
| TC_SO_ABLE
| TC_RA_ABLE
;
85 /* X11R6 adds TC_SF_X_YINDEP, maybe more... */
87 static const char* INIWinePrefix
= "/.wine";
88 static const char* INIFontMetrics
= "/.cachedmetrics.";
89 static const char* INIFontSection
= "fonts";
90 static const char* INIAliasSection
= "Alias";
91 static const char* INIIgnoreSection
= "Ignore";
92 static const char* INIDefault
= "Default";
93 static const char* INIDefaultFixed
= "DefaultFixed";
94 static const char* INIResolution
= "Resolution";
95 static const char* INIGlobalMetrics
= "FontMetrics";
96 static const char* INIDefaultSerif
= "DefaultSerif";
97 static const char* INIDefaultSansSerif
= "DefaultSansSerif";
99 static const char* LFDSeparator
= "*-";
101 /* suffix tables, must be less than 254 entries long */
103 static LPSTR suffx_iso
[] = { "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8",
104 "-9", "-10", "-11", "-12", "-13", "-14", "-15", NULL
};
105 static LPSTR suffx_iso646
[] = { "-irv", NULL
};
106 static LPSTR suffx_microsoft
[] = { "-cp1252", "-cp1251", "-cp1250", "-cp1253", "-cp1254", "-cp1255",
107 "-cp1256", "-cp1257", "-fontspecific", "-symbol", NULL
};
108 static LPSTR suffx_viscii
[] = { "-1", NULL
};
109 static LPSTR suffx_ansi
[] = { "-0", NULL
};
110 static LPSTR suffx_koi8
[] = { "-ru", "-r", NULL
};
111 static LPSTR suffx_null
[] = { NULL
};
113 /* charset mapping tables, have to have the same number of entries as corresponding suffix tables */
115 static BYTE chset_iso8859
[] = { ANSI_CHARSET
, EE_CHARSET
, ISO3_CHARSET
, ISO4_CHARSET
, RUSSIAN_CHARSET
,
116 ARABIC_CHARSET
, GREEK_CHARSET
, HEBREW_CHARSET
, TURKISH_CHARSET
, BALTIC_CHARSET
,
117 THAI_CHARSET
, SYMBOL_CHARSET
, SYMBOL_CHARSET
, SYMBOL_CHARSET
, ANSI_CHARSET
,
119 static BYTE chset_iso646
[] = { ANSI_CHARSET
, SYMBOL_CHARSET
};
120 static BYTE chset_microsoft
[] = { ANSI_CHARSET
, RUSSIAN_CHARSET
, EE_CHARSET
, GREEK_CHARSET
, TURKISH_CHARSET
,
121 HEBREW_CHARSET
, ARABIC_CHARSET
, BALTIC_CHARSET
, SYMBOL_CHARSET
, SYMBOL_CHARSET
,
123 static BYTE chset_ansi
[] = { ANSI_CHARSET
, ANSI_CHARSET
};
124 static BYTE chset_koi8
[] = { KOI8_CHARSET
, KOI8_CHARSET
, KOI8_CHARSET
};
125 static BYTE chset_tcvn
[] = { TCVN_CHARSET
, TCVN_CHARSET
};
126 static BYTE chset_tis620
[] = { THAI_CHARSET
};
127 static BYTE chset_fontspecific
[] = { SYMBOL_CHARSET
};
128 static BYTE chset_viscii
[] = { VISCII_CHARSET
, VISCII_CHARSET
};
136 } fontEncodingTemplate
;
138 /* Note: we can attach additional encoding mappings to the end
139 * of this table at runtime.
142 static fontEncodingTemplate __fETTable
[10] = {
143 { "iso8859", &suffx_iso
, &chset_iso8859
, &__fETTable
[1] },
144 { "iso646.1991", &suffx_iso646
, &chset_iso646
, &__fETTable
[2] },
145 { "microsoft", &suffx_microsoft
, &chset_microsoft
, &__fETTable
[3] },
146 { "ansi", &suffx_ansi
, &chset_ansi
, &__fETTable
[4] },
147 { "ascii", &suffx_ansi
, &chset_ansi
, &__fETTable
[5] },
148 { "fontspecific", &suffx_null
, &chset_fontspecific
, &__fETTable
[6] },
149 { "koi8", &suffx_koi8
, &chset_koi8
, &__fETTable
[7] },
150 { "tcvn", &suffx_ansi
, &chset_tcvn
, &__fETTable
[8] },
151 { "tis620", &suffx_null
, &chset_tis620
, &__fETTable
[9] },
152 { "viscii1.1", &suffx_viscii
, &chset_viscii
, NULL
}
154 static fontEncodingTemplate
* fETTable
= __fETTable
;
156 static unsigned DefResolution
= 0;
158 static CRITICAL_SECTION crtsc_fonts_X11
;
160 static fontResource
* fontList
= NULL
;
161 static fontObject
* fontCache
= NULL
; /* array */
162 static int fontCacheSize
= FONTCACHE
;
163 static int fontLF
= -1, fontMRU
= -1; /* last free, most recently used */
165 #define __PFONT(pFont) ( fontCache + ((UINT32)(pFont) & 0x0000FFFF) )
166 #define CHECK_PFONT(pFont) ( (((UINT32)(pFont) & 0xFFFF0000) == X_PFONT_MAGIC) &&\
167 (((UINT32)(pFont) & 0x0000FFFF) < fontCacheSize) )
169 static INT32
XFONT_IsSubset(fontInfo
*, fontInfo
*);
170 static void XFONT_CheckFIList(fontResource
*, fontInfo
*, int subset_action
);
171 static void XFONT_GrowFreeList(int start
, int end
);
172 static void XFONT_RemoveFontResource(fontResource
** ppfr
);
175 static Atom RAW_ASCENT
;
176 static Atom RAW_DESCENT
;
178 /***********************************************************************
179 * Helper macros from X distribution
182 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
183 (((cs)->rbearing|(cs)->lbearing| \
184 (cs)->ascent|(cs)->descent) == 0))
186 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
189 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
190 if (fs->per_char == NULL) { \
191 cs = &fs->min_bounds; \
193 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
194 if (CI_NONEXISTCHAR(cs)) cs = def; \
199 #define CI_GET_DEFAULT_INFO(fs,cs) \
200 CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
202 /***********************************************************************
205 static UINT16
__lfCheckSum( LPLOGFONT16 plf
)
207 CHAR font
[LF_FACESIZE
];
211 #define ptr ((UINT16*)plf)
212 for( i
= 0; i
< 9; i
++ ) checksum
^= *ptr
++;
215 #define ptr ((CHAR*)plf)
216 do { font
[i
++] = tolower(*ptr
++); } while (( i
< LF_FACESIZE
) && (*ptr
) && (*ptr
!=' '));
217 for( ptr
= font
, i
>>= 1; i
> 0; i
-- )
219 #define ptr ((UINT16*)plf)
225 static UINT16
__genericCheckSum( const void *ptr
, int size
)
227 unsigned int checksum
= 0;
228 const char *p
= (const char *)ptr
;
230 checksum
^= (checksum
<< 3) + (checksum
>> 29) + *p
++;
232 return checksum
& 0xffff;
235 /*************************************************************************
236 * LFD parse/compose routines
238 static char* LFD_Advance(LPSTR lpFont
, UINT16 uParmsNo
)
243 for( ; j
< uParmsNo
&& *lpch
; lpch
++ ) if( *lpch
== LFDSeparator
[1] ) j
++;
247 static void LFD_GetWeight( fontInfo
* fi
, LPSTR lpStr
, int j
)
249 if( j
== 1 && *lpStr
== '0' )
250 fi
->fi_flags
|= FI_POLYWEIGHT
;
253 if( !strncasecmp( "bold", lpStr
, 4) )
254 fi
->df
.dfWeight
= FW_BOLD
;
255 else if( !strncasecmp( "demi", lpStr
, 4) )
257 fi
->fi_flags
|= FI_FW_DEMI
;
258 fi
->df
.dfWeight
= FW_DEMIBOLD
;
260 else if( !strncasecmp( "book", lpStr
, 4) )
262 fi
->fi_flags
|= FI_FW_BOOK
;
263 fi
->df
.dfWeight
= FW_REGULAR
;
268 if( !strncasecmp( "light", lpStr
, 5) )
269 fi
->df
.dfWeight
= FW_LIGHT
;
270 else if( !strncasecmp( "black", lpStr
, 5) )
271 fi
->df
.dfWeight
= FW_BLACK
;
273 else if( j
== 6 && !strncasecmp( "medium", lpStr
, 6) )
274 fi
->df
.dfWeight
= FW_REGULAR
;
275 else if( j
== 8 && !strncasecmp( "demibold", lpStr
, 8) )
276 fi
->df
.dfWeight
= FW_DEMIBOLD
;
278 fi
->df
.dfWeight
= FW_DONTCARE
; /* FIXME: try to get something
279 * from the weight property */
282 static int LFD_GetSlant( fontInfo
* fi
, LPSTR lpStr
, int l
)
286 switch( tolower( *lpStr
) )
288 case '0': fi
->fi_flags
|= FI_POLYSLANT
; /* haven't seen this one yet */
290 case 'r': fi
->df
.dfItalic
= 0;
293 fi
->fi_flags
|= FI_OBLIQUE
;
294 case 'i': fi
->df
.dfItalic
= 1;
302 /*************************************************************************
307 * Fill in some fields in the fontInfo struct.
309 static int LFD_InitFontInfo( fontInfo
* fi
, LPSTR lpstr
)
312 int i
, j
, dec_style_check
, scalability
;
314 fontEncodingTemplate
* boba
;
316 memset(fi
, 0, sizeof(fontInfo
) );
319 lpch
= LFD_Advance( lpstr
, 1);
320 if( !*lpch
) return FALSE
;
321 j
= lpch
- lpstr
- 1;
322 LFD_GetWeight( fi
, lpstr
, j
);
325 lpch
= LFD_Advance( lpstr
= lpch
, 1);
326 if( !*lpch
) return FALSE
;
327 j
= lpch
- lpstr
- 1;
328 dec_style_check
= LFD_GetSlant( fi
, lpstr
, j
);
331 lpch
= LFD_Advance( lpstr
= lpch
, 1);
332 if( !*lpch
) return FALSE
;
333 if( strncasecmp( "normal", lpstr
, 6) ) /* XXX 'narrow', 'condensed', etc... */
334 dec_style_check
= TRUE
;
336 fi
->fi_flags
|= FI_NORMAL
;
339 lpch
= LFD_Advance( lpstr
= lpch
, 1);
340 if( !*lpch
) return FALSE
;
341 j
= lpch
- lpstr
- 1;
342 if( j
> 3 ) /* find out is there "sans" or "script" */
347 if( strstr(lpstr
, "sans") )
349 fi
->df
.dfPitchAndFamily
|= FF_SWISS
;
352 if( strstr(lpstr
, "script") )
354 fi
->df
.dfPitchAndFamily
|= FF_SCRIPT
;
357 if( !j
&& dec_style_check
)
358 fi
->df
.dfPitchAndFamily
|= FF_DECORATIVE
;
359 *(lpch
- 1) = LFDSeparator
[1];
362 /* pixel height, decipoint height, and res_x */
364 for( i
= scalability
= 0; i
< 3; i
++ )
366 lpch
= LFD_Advance( lpstr
= lpch
, 1);
367 if( !*lpch
) return FALSE
;
368 if( lpch
- lpstr
== 1 || lpch
- lpstr
> 4 ) return FALSE
; /* ridiculous */
371 if( !(tmp
[i
] = atoi(lpstr
)) ) scalability
++;
372 *(lpch
- 1) = LFDSeparator
[1];
374 if( scalability
== 3 ) /* Type1 */
376 fi
->fi_flags
|= FI_SCALABLE
;
377 fi
->lfd_height
= DEF_SCALABLE_HEIGHT
; fi
->lfd_decipoints
= DEF_SCALABLE_DP
;
378 fi
->lfd_resolution
= DefResolution
;
380 else if( scalability
== 0 ) /* Bitmap */
382 fi
->lfd_height
= tmp
[0]; fi
->lfd_decipoints
= tmp
[1];
383 fi
->lfd_resolution
= tmp
[2];
385 else return FALSE
; /* #$%^!!! X11R6 mutant garbage */
387 /* res_y - skip, spacing - */
388 lpstr
= LFD_Advance( lpch
, 1);
391 case '\0': return FALSE
;
393 case 'p': fi
->fi_flags
|= FI_VARIABLEPITCH
;
395 case 'c': fi
->df
.dfPitchAndFamily
|= FF_MODERN
;
396 fi
->fi_flags
|= FI_FIXEDEX
;
398 case 'm': fi
->fi_flags
|= FI_FIXEDPITCH
;
401 fi
->df
.dfPitchAndFamily
|= DEFAULT_PITCH
| FF_DONTCARE
;
403 lpstr
= LFD_Advance(lpstr
, 1);
404 if( !*lpstr
) return FALSE
;
406 /* average width - */
407 lpch
= LFD_Advance( lpstr
, 1);
408 if( !*lpch
) return FALSE
;
409 if( lpch
- lpstr
== 1 || lpch
- lpstr
> 4 ) return FALSE
; /* ridiculous */
411 if( !(fi
->lfd_width
= atoi(lpstr
)) && !scalability
) return FALSE
;
412 *(lpch
- 1) = LFDSeparator
[1];
414 /* charset registry, charset encoding - */
415 if( strstr(lpch
, "jisx") ||
416 strstr(lpch
, "ksc") ||
417 strstr(lpch
, "gb2312") ||
418 strstr(lpch
, "big5") ||
419 strstr(lpch
, "unicode") ) return FALSE
; /* 2-byte stuff */
421 fi
->df
.dfCharSet
= ANSI_CHARSET
;
423 for( i
= 0, boba
= fETTable
; boba
; boba
= boba
->next
, i
++ )
425 tmp
[0] = strlen( boba
->prefix
);
426 if( !strncasecmp( lpch
, boba
->prefix
, tmp
[0] ) )
428 if( lpch
[tmp
[0]] == '-' )
430 lpstr
= lpch
+ tmp
[0];
431 for( j
= 0; (*(boba
->psuffix
))[j
]; j
++ )
433 tmp
[1] = strlen( (*(boba
->psuffix
))[j
] );
434 if( !strncasecmp( lpstr
, (*(boba
->psuffix
))[j
], tmp
[1] ) )
436 fi
->df
.dfCharSet
= (*(boba
->pcharset
))[j
];
440 /* Note : LFD_ComposeLFD will produce 'prefix-*' encoding *
441 * if (*(boba->psuffix))[j] is NULL here */
445 for( j
= 0; (*(boba
->psuffix
))[j
] ; j
++ );
446 fi
->df
.dfCharSet
= (*(boba
->pcharset
))[j
];
447 j
= lpch
[tmp
[0]] ? 254 : 255;
452 if( !boba
) return FALSE
;
454 /* i - index into fETTable
455 * j - index into suffix array for fETTable[i]
457 * 254 - weird suffix (i.e. no '-' right after prefix )
458 * 255 - no suffix at all.
461 fi
->fi_encoding
= 256 * (UINT16
)i
+ (UINT16
)j
;
467 /*************************************************************************
470 * Note: uRelax is a treatment not a cure. Font mapping algorithm
471 * should be bulletproof enough to allow us to avoid hacks like
472 * if( uRelax == 200 ) even despite LFD being so braindead.
474 static BOOL32
LFD_ComposeLFD( fontObject
* fo
,
475 INT32 height
, LPSTR lpLFD
, UINT32 uRelax
)
477 fontEncodingTemplate
* boba
;
478 int i
, h
, w
, ch
, point
= 0;
481 char h_string
[64], point_string
[64];
483 *(lpLFD
+MAX_LFD_LENGTH
-1)=0;
484 lstrcpy32A( lpLFD
, fo
->fr
->resource
);
487 switch( fo
->fi
->df
.dfWeight
)
490 strcat( lpLFD
, "bold" ); break;
492 if( fo
->fi
->fi_flags
& FI_FW_BOOK
)
493 strcat( lpLFD
, "book" );
495 strcat( lpLFD
, "medium" );
498 strcat( lpLFD
, "demi" );
499 if( !( fo
->fi
->fi_flags
& FI_FW_DEMI
) )
500 strcat ( lpLFD
, "bold" );
503 strcat( lpLFD
, "black" ); break;
505 strcat( lpLFD
, "light" ); break;
507 strcat( lpLFD
, "*" );
511 if( fo
->fi
->df
.dfItalic
)
512 if( fo
->fi
->fi_flags
& FI_OBLIQUE
)
513 strcat( lpLFD
, "-o" );
515 strcat( lpLFD
, "-i" );
517 strcat( lpLFD
, (uRelax
< 2) ? "-r" : "-*" );
519 /* add width style and skip serifs */
520 if( fo
->fi
->fi_flags
& FI_NORMAL
)
521 strcat( lpLFD
, "-normal-*-");
523 strcat( lpLFD
, "-*-*-" );
525 /* add pixelheight, pointheight, and resolution
527 * FIXME: fill in lpXForm and lpPixmap for rotated fonts
529 if( fo
->fo_flags
& FO_SYNTH_HEIGHT
) h
= fo
->fi
->lfd_height
;
530 else h
= (fo
->fi
->lfd_height
* height
) / fo
->fi
->df
.dfPixHeight
;
532 if( XTextCaps
& TC_SF_X_YINDEP
)
534 if( fo
->lf
.lfWidth
&& !(fo
->fo_flags
& FO_SYNTH_WIDTH
) )
535 point
= (fo
->fi
->lfd_decipoints
* fo
->lf
.lfWidth
) / fo
->fi
->df
.dfAvgWidth
;
537 if( fo
->fi
->fi_flags
& FI_SCALABLE
) /* adjust h/w ratio */
538 point
= h
* 72 * 10 / fo
->fi
->lfd_resolution
;
541 /* handle rotated fonts */
542 if (fo
->lf
.lfEscapement
) {
543 /* escapement is in tenths of degrees, theta is in radians */
544 double theta
= M_PI
*fo
->lf
.lfEscapement
/1800.;
545 double h_matrix
[4] = {h
*cos(theta
), h
*sin(theta
), -h
*sin(theta
), h
*cos(theta
)};
546 double point_matrix
[4] = {point
*cos(theta
), point
*sin(theta
), -point
*sin(theta
), point
*cos(theta
)};
548 sprintf(h_string
, "[%+f%+f%+f%+f]", h_matrix
[0], h_matrix
[1], h_matrix
[2], h_matrix
[3]);
549 sprintf(point_string
, "[%+f%+f%+f%+f]", point_matrix
[0], point_matrix
[1], point_matrix
[2], point_matrix
[3]);
550 while ((s
= strchr(h_string
, '-'))) *s
='~';
551 while ((s
= strchr(point_string
, '-'))) *s
='~';
553 sprintf(h_string
, "%d", h
);
554 sprintf(point_string
, "%d", point
);
558 /* spacing and width */
560 if( fo
->fi
->fi_flags
& FI_FIXEDPITCH
)
561 w
= ( fo
->fi
->fi_flags
& FI_FIXEDEX
) ? 'c' : 'm';
563 w
= ( fo
->fi
->fi_flags
& FI_VARIABLEPITCH
) ? 'p' : LFDSeparator
[0];
567 i
= fo
->fi
->fi_encoding
>> 8;
568 for( boba
= fETTable
; i
; i
--, boba
= boba
->next
);
570 strcpy( lpEncoding
, boba
->prefix
);
572 i
= fo
->fi
->fi_encoding
& 255;
575 case 254: strcat( lpEncoding
, "*" );
579 if( (*(boba
->psuffix
))[i
] )
580 strcat( lpEncoding
, (*(boba
->psuffix
))[i
] );
582 strcat( lpEncoding
, "-*" );
585 case 255: /* no suffix */
588 lpch
= lpLFD
+ lstrlen32A(lpLFD
);
589 ch
= (fo
->fi
->fi_flags
& FI_SCALABLE
) ? '0' : LFDSeparator
[0];
593 /* RealizeFont() will call us repeatedly with increasing uRelax
594 * until XLoadFont() succeeds. */
599 sprintf( lpch
, "%s-%s-%i-%c-%c-*-%s", h_string
,
601 fo
->fi
->lfd_resolution
, ch
, w
, lpEncoding
);
607 case 2: /* 2 will have replaced an 'r' in slant by '*' */
608 sprintf( lpch
, "%s-*-%i-%c-%c-*-%s", h_string
,
609 fo
->fi
->lfd_resolution
, ch
, w
, lpEncoding
);
613 sprintf( lpch
, "%s-*-%i-%c-*-*-%s",
614 h_string
, fo
->fi
->lfd_resolution
, ch
, lpEncoding
);
618 sprintf( lpch
, "%i-*-%i-%c-*-*-%s", fo
->fi
->lfd_height
,
619 fo
->fi
->lfd_resolution
, ch
, lpEncoding
);
623 sprintf( lpch
, "%i-*-*-*-*-*-%s", fo
->fi
->lfd_height
, lpEncoding
);
627 sprintf( lpch
, "%i-*-*-*-*-*-*-*", fo
->fi
->lfd_height
);
630 /* to avoid an infinite loop; those will allways match */
632 sprintf( lpLFD
, "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1" );
635 sprintf( lpLFD
, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" );
639 TRACE(font
,"\tLFD(uRelax=%d): %s\n", uRelax
, lpLFD
);
640 assert(*(lpLFD
+MAX_LFD_LENGTH
-1)==0); /* check if overwrittem */
645 /***********************************************************************
648 * font info - http://www.microsoft.com/kb/articles/q65/1/23.htm
649 * Windows font metrics - http://www.microsoft.com/kb/articles/q32/6/67.htm
651 static BOOL32
XFONT_GetLeading( LPIFONTINFO16 pFI
, XFontStruct
* x_fs
, INT32
*
652 pIL
, INT32
* pEL
, XFONTTRANS
*XFT
)
654 unsigned long height
;
655 unsigned min
= (unsigned char)pFI
->dfFirstChar
;
656 unsigned max
= (unsigned char)pFI
->dfLastChar
;
657 BOOL32 bHaveCapHeight
= (pFI
->dfCharSet
== ANSI_CHARSET
&& 'X' >= min
&& 'X' <= max
);
662 Atom RAW_CAP_HEIGHT
= TSXInternAtom(display
, "RAW_CAP_HEIGHT", TRUE
);
663 if(TSXGetFontProperty(x_fs
, RAW_CAP_HEIGHT
, &height
))
665 (INT32
)(XFT
->pixelsize
/ 1000.0 * height
);
668 return bHaveCapHeight
&& x_fs
->per_char
;
671 if( TSXGetFontProperty(x_fs
, XA_CAP_HEIGHT
, &height
) == FALSE
)
675 height
= x_fs
->per_char
['X' - min
].ascent
;
677 if (x_fs
->ascent
>= x_fs
->max_bounds
.ascent
)
678 height
= x_fs
->max_bounds
.ascent
;
681 height
= x_fs
->ascent
;
683 *pEL
= x_fs
->max_bounds
.ascent
- height
;
686 height
= x_fs
->min_bounds
.ascent
;
689 *pIL
= x_fs
->ascent
- height
;
690 return (bHaveCapHeight
&& x_fs
->per_char
);
693 static INT32
XFONT_GetAvgCharWidth( LPIFONTINFO16 pFI
, XFontStruct
* x_fs
,
696 unsigned min
= (unsigned char)pFI
->dfFirstChar
;
697 unsigned max
= (unsigned char)pFI
->dfLastChar
;
702 for( j
= 0, width
= 0, chars
= 0, max
-= min
; j
<= max
; j
++ )
703 if( !CI_NONEXISTCHAR(x_fs
->per_char
+ j
) )
706 width
+= x_fs
->per_char
[j
].width
;
708 width
+= x_fs
->per_char
[j
].attributes
*
709 XFT
->pixelsize
/ 1000.0;
712 return (width
/ chars
);
715 return x_fs
->min_bounds
.width
;
718 static INT32
XFONT_GetMaxCharWidth(fontObject
*pfo
)
720 unsigned min
= (unsigned char)pfo
->fs
->min_char_or_byte2
;
721 unsigned max
= (unsigned char)pfo
->fs
->max_char_or_byte2
;
724 return abs(pfo
->fs
->max_bounds
.width
);
726 if( pfo
->fs
->per_char
)
729 for( j
= 0, maxwidth
= 0, max
-= min
; j
<= max
; j
++ )
730 if( !CI_NONEXISTCHAR(pfo
->fs
->per_char
+ j
) )
731 if(maxwidth
< pfo
->fs
->per_char
[j
].attributes
)
732 maxwidth
= pfo
->fs
->per_char
[j
].attributes
;
734 maxwidth
*= pfo
->lpX11Trans
->pixelsize
/ 1000.0;
737 return pfo
->foAvgCharWidth
;
740 /***********************************************************************
741 * XFONT_SetFontMetric
745 * Initializes IFONTINFO16. dfHorizRes and dfVertRes must be already set.
747 static void XFONT_SetFontMetric(fontInfo
* fi
, fontResource
* fr
, XFontStruct
* xfs
)
752 fi
->df
.dfFirstChar
= (BYTE
)(min
= xfs
->min_char_or_byte2
);
753 fi
->df
.dfLastChar
= (BYTE
)(max
= xfs
->max_char_or_byte2
);
755 fi
->df
.dfDefaultChar
= (BYTE
)xfs
->default_char
;
756 fi
->df
.dfBreakChar
= (BYTE
)(( ' ' < min
|| ' ' > max
) ? xfs
->default_char
: ' ');
758 fi
->df
.dfPixHeight
= (INT16
)((fi
->df
.dfAscent
= (INT16
)xfs
->ascent
) + xfs
->descent
);
759 fi
->df
.dfPixWidth
= (xfs
->per_char
) ? 0 : xfs
->min_bounds
.width
;
760 fi
->df
.dfMaxWidth
= (INT16
)abs(xfs
->max_bounds
.width
);
762 if( XFONT_GetLeading( &fi
->df
, xfs
, &il
, &el
, NULL
) )
763 fi
->df
.dfAvgWidth
= (INT16
)xfs
->per_char
['X' - min
].width
;
765 fi
->df
.dfAvgWidth
= (INT16
)XFONT_GetAvgCharWidth( &fi
->df
, xfs
, NULL
);
767 fi
->df
.dfInternalLeading
= (INT16
)il
;
768 fi
->df
.dfExternalLeading
= (INT16
)el
;
770 fi
->df
.dfPoints
= (INT16
)(((INT32
)(fi
->df
.dfPixHeight
-
771 fi
->df
.dfInternalLeading
) * 72 + (fi
->df
.dfVertRes
>> 1)) / fi
->df
.dfVertRes
);
773 if( xfs
->min_bounds
.width
!= xfs
->max_bounds
.width
)
774 fi
->df
.dfPitchAndFamily
|= TMPF_FIXED_PITCH
; /* au contraire! */
775 if( fi
->fi_flags
& FI_SCALABLE
)
777 fi
->df
.dfType
= DEVICE_FONTTYPE
;
778 fi
->df
.dfPitchAndFamily
|= TMPF_DEVICE
;
780 else if( fi
->fi_flags
& FI_TRUETYPE
)
781 fi
->df
.dfType
= TRUETYPE_FONTTYPE
;
783 fi
->df
.dfType
= RASTER_FONTTYPE
;
785 fi
->df
.dfFace
= fr
->lfFaceName
;
788 /***********************************************************************
789 * XFONT_GetTextMetric
791 * GetTextMetrics() back end.
793 static void XFONT_GetTextMetric( fontObject
* pfo
, LPTEXTMETRIC32A pTM
)
795 LPIFONTINFO16 pdf
= &pfo
->fi
->df
;
797 if( ! pfo
->lpX11Trans
) {
798 pTM
->tmAscent
= pfo
->fs
->ascent
;
799 pTM
->tmDescent
= pfo
->fs
->descent
;
801 pTM
->tmAscent
= pfo
->lpX11Trans
->ascent
;
802 pTM
->tmDescent
= pfo
->lpX11Trans
->descent
;
804 pTM
->tmHeight
= pTM
->tmAscent
+ pTM
->tmDescent
;
806 pTM
->tmAveCharWidth
= pfo
->foAvgCharWidth
;
807 pTM
->tmMaxCharWidth
= pfo
->foMaxCharWidth
;
809 pTM
->tmInternalLeading
= pfo
->foInternalLeading
;
810 pTM
->tmExternalLeading
= pdf
->dfExternalLeading
;
812 pTM
->tmStruckOut
= (pfo
->fo_flags
& FO_SYNTH_STRIKEOUT
)
813 ? 1 : pdf
->dfStrikeOut
;
814 pTM
->tmUnderlined
= (pfo
->fo_flags
& FO_SYNTH_UNDERLINE
)
815 ? 1 : pdf
->dfUnderline
;
818 if( pfo
->fo_flags
& FO_SYNTH_ITALIC
)
820 pTM
->tmOverhang
+= pTM
->tmHeight
/3;
823 pTM
->tmItalic
= pdf
->dfItalic
;
825 pTM
->tmWeight
= pdf
->dfWeight
;
826 if( pfo
->fo_flags
& FO_SYNTH_BOLD
)
829 pTM
->tmWeight
+= 100;
832 *(INT32
*)&pTM
->tmFirstChar
= *(INT32
*)&pdf
->dfFirstChar
;
834 pTM
->tmCharSet
= pdf
->dfCharSet
;
835 pTM
->tmPitchAndFamily
= pdf
->dfPitchAndFamily
;
837 pTM
->tmDigitizedAspectX
= pdf
->dfHorizRes
;
838 pTM
->tmDigitizedAspectY
= pdf
->dfVertRes
;
841 /***********************************************************************
842 * XFONT_GetFontMetric
844 * Retrieve font metric info (enumeration).
846 static UINT32
XFONT_GetFontMetric( fontInfo
* pfi
, LPENUMLOGFONTEX16 pLF
,
847 LPNEWTEXTMETRIC16 pTM
)
849 memset( pLF
, 0, sizeof(*pLF
) );
850 memset( pTM
, 0, sizeof(*pTM
) );
852 #define plf ((LPLOGFONT16)pLF)
853 plf
->lfHeight
= pTM
->tmHeight
= pfi
->df
.dfPixHeight
;
854 plf
->lfWidth
= pTM
->tmAveCharWidth
= pfi
->df
.dfAvgWidth
;
855 plf
->lfWeight
= pTM
->tmWeight
= pfi
->df
.dfWeight
;
856 plf
->lfItalic
= pTM
->tmItalic
= pfi
->df
.dfItalic
;
857 plf
->lfUnderline
= pTM
->tmUnderlined
= pfi
->df
.dfUnderline
;
858 plf
->lfStrikeOut
= pTM
->tmStruckOut
= pfi
->df
.dfStrikeOut
;
859 plf
->lfCharSet
= pTM
->tmCharSet
= pfi
->df
.dfCharSet
;
861 /* convert pitch values */
863 pTM
->tmPitchAndFamily
= pfi
->df
.dfPitchAndFamily
;
864 plf
->lfPitchAndFamily
= (pfi
->df
.dfPitchAndFamily
& 0xF1) + 1;
866 lstrcpyn32A( plf
->lfFaceName
, pfi
->df
.dfFace
, LF_FACESIZE
);
869 pTM
->tmAscent
= pfi
->df
.dfAscent
;
870 pTM
->tmDescent
= pTM
->tmHeight
- pTM
->tmAscent
;
871 pTM
->tmInternalLeading
= pfi
->df
.dfInternalLeading
;
872 pTM
->tmMaxCharWidth
= pfi
->df
.dfMaxWidth
;
873 pTM
->tmDigitizedAspectX
= pfi
->df
.dfHorizRes
;
874 pTM
->tmDigitizedAspectY
= pfi
->df
.dfVertRes
;
876 *(INT32
*)&pTM
->tmFirstChar
= *(INT32
*)&pfi
->df
.dfFirstChar
;
878 /* return font type */
880 return pfi
->df
.dfType
;
884 /***********************************************************************
889 * dfPitchAndFamily flags for some common typefaces.
891 static BYTE
XFONT_FixupFlags( LPCSTR lfFaceName
)
893 switch( lfFaceName
[0] )
896 case 'H': if(!strcasecmp(lfFaceName
, "Helvetica") )
900 case 'C': if(!strcasecmp(lfFaceName
, "Courier") ||
901 !strcasecmp(lfFaceName
, "Charter") )
905 case 'P': if( !strcasecmp(lfFaceName
,"Palatino") )
909 case 'T': if(!strncasecmp(lfFaceName
, "Times", 5) )
913 case 'U': if(!strcasecmp(lfFaceName
, "Utopia") )
917 case 'Z': if(!strcasecmp(lfFaceName
, "Zapf Dingbats") )
918 return FF_DECORATIVE
;
924 /***********************************************************************
925 * XFONT_CheckResourceName
929 static BOOL32
XFONT_CheckResourceName( LPSTR resource
, LPCSTR name
, INT32 n
)
931 resource
= LFD_Advance( resource
, 2 );
933 return (!strncasecmp( resource
, name
, n
));
938 /***********************************************************************
943 * Build generic Windows aliases for X font names.
945 * -misc-fixed- -> "Fixed"
946 * -sony-fixed- -> "Sony Fixed", etc...
948 static void XFONT_WindowsNames( char* buffer
)
950 fontResource
* fr
, *pfr
;
954 const char* relocTable
[] = { INIDefaultFixed
, INIDefault
, NULL
};
956 for( fr
= fontList
; fr
; fr
= fr
->next
)
958 if( fr
->fr_flags
& FR_NAMESET
) continue; /* skip already assigned */
960 lpstr
= LFD_Advance(fr
->resource
, 2);
961 i
= LFD_Advance( lpstr
, 1 ) - lpstr
;
963 for( pfr
= fontList
; pfr
!= fr
; pfr
= pfr
->next
)
964 if( pfr
->fr_flags
& FR_NAMESET
)
965 if( XFONT_CheckResourceName( pfr
->resource
, lpstr
, i
) )
968 if( pfr
!= fr
) /* prepend vendor name */
969 lpstr
= fr
->resource
+ 1;
971 for( i
= 0, up
= 1, lpch
= fr
->lfFaceName
; *lpstr
&& i
< 32;
972 lpch
++, lpstr
++, i
++ )
974 if( *lpstr
== LFDSeparator
[1] || *lpstr
== ' ' )
979 else if( isalpha(*lpstr
) && up
)
981 *lpch
= toupper(*lpstr
);
986 while (*(lpch
- 1) == ' ') *(--lpch
) = '\0';
988 if( (bFamilyStyle
= XFONT_FixupFlags( fr
->lfFaceName
)) )
991 for( fi
= fr
->fi
; fi
; fi
= fi
->next
)
992 fi
->df
.dfPitchAndFamily
|= bFamilyStyle
;
995 TRACE(font
,"typeface \'%s\'\n", fr
->lfFaceName
);
997 fr
->fr_flags
|= FR_NAMESET
;
1000 for( up
= 0; relocTable
[up
]; up
++ )
1001 if( PROFILE_GetWineIniString( INIFontSection
, relocTable
[up
], "", buffer
, 128 ) )
1003 while( *buffer
&& isspace(*buffer
) ) buffer
++;
1004 for( fr
= NULL
, pfr
= fontList
; pfr
; pfr
= pfr
->next
)
1006 i
= strlen( pfr
->resource
);
1007 if( !strncasecmp( pfr
->resource
, buffer
, i
) )
1011 fr
->next
= pfr
->next
;
1012 pfr
->next
= fontList
;
1022 /***********************************************************************
1025 static fontAlias
* XFONT_CreateAlias( LPCSTR lpTypeFace
, LPCSTR lpAlias
)
1028 fontAlias
* pfa
= aliasTable
;
1032 /* check if we already got one */
1033 if( !strcasecmp( pfa
->faTypeFace
, lpAlias
) )
1035 TRACE(font
,"\tredundant alias '%s' -> '%s'\n",
1036 lpAlias
, lpTypeFace
);
1039 if( pfa
->next
) pfa
= pfa
->next
;
1043 j
= lstrlen32A(lpTypeFace
) + 1;
1044 pfa
->next
= HeapAlloc( SystemHeap
, 0, sizeof(fontAlias
) +
1045 j
+ lstrlen32A(lpAlias
) + 1 );
1046 if((pfa
= pfa
->next
))
1049 pfa
->faTypeFace
= (LPSTR
)(pfa
+ 1);
1050 lstrcpy32A( pfa
->faTypeFace
, lpTypeFace
);
1051 pfa
->faAlias
= pfa
->faTypeFace
+ j
;
1052 lstrcpy32A( pfa
->faAlias
, lpAlias
);
1054 TRACE(font
, "\tadded alias '%s' for %s\n", lpAlias
, lpTypeFace
);
1061 /***********************************************************************
1064 * Read user-defined aliases from wine.conf. Format is as follows
1066 * Alias# = [Windows font name],[LFD font name], <substitute original name>
1069 * Alias0 = Arial, -adobe-helvetica-
1070 * Alias1 = Times New Roman, -bitstream-courier-, 1
1073 * Note that from 081797 and on we have built-in alias templates that take
1074 * care of the necessary Windows typefaces.
1076 static void XFONT_LoadAliases( char** buffer
, int *buf_size
)
1078 char* lpResource
, *lpAlias
;
1079 char subsection
[32];
1081 BOOL32 bHaveAlias
= TRUE
, bSubst
= FALSE
;
1083 if( *buf_size
< 128 )
1085 *buffer
= HeapReAlloc(SystemHeap
, 0, *buffer
, 256 );
1090 if( j
< faTemplateNum
)
1092 /* built-in templates first */
1094 lpResource
= faTemplate
[j
].fatResource
;
1095 lpAlias
= faTemplate
[j
].fatAlias
;
1100 /* then WINE.CONF */
1102 wsprintf32A( subsection
, "%s%i", INIAliasSection
, i
++ );
1104 if( (bHaveAlias
= PROFILE_GetWineIniString( INIFontSection
,
1105 subsection
, "", *buffer
, 128 )) )
1108 while( isspace(*lpAlias
) ) lpAlias
++;
1109 lpResource
= PROFILE_GetStringItem( lpAlias
);
1110 bSubst
= (PROFILE_GetStringItem( lpResource
)) ? TRUE
: FALSE
;
1118 length
= strlen( lpAlias
);
1119 if( lpResource
&& length
)
1121 fontResource
* fr
, *frMatch
= NULL
;
1123 for (fr
= fontList
; fr
; fr
= fr
->next
)
1125 if( !strcasecmp( fr
->resource
, lpResource
) ) frMatch
= fr
;
1126 if( XFONT_CheckResourceName( fr
->resource
, lpAlias
, length
) )
1128 /* alias is not needed since the real font is present */
1129 frMatch
= NULL
; break;
1137 fontAlias
*pfa
, *prev
= NULL
;
1139 for(pfa
= aliasTable
; pfa
; pfa
= pfa
->next
)
1141 /* Remove lpAlias from aliasTable - we should free the old entry */
1142 if(!strcmp(lpAlias
, pfa
->faAlias
))
1145 prev
->next
= pfa
->next
;
1147 aliasTable
= pfa
->next
;
1150 /* Update any references to the substituted font in aliasTable */
1151 if(!strcmp(frMatch
->lfFaceName
,
1153 pfa
->faTypeFace
= HEAP_strdupA( SystemHeap
, 0,
1158 TRACE(font
, "\tsubstituted '%s' with %s\n",
1159 frMatch
->lfFaceName
, lpAlias
);
1161 lstrcpyn32A( frMatch
->lfFaceName
, lpAlias
, LF_FACESIZE
);
1162 frMatch
->fr_flags
|= FR_NAMESET
;
1166 /* create new entry in the alias table */
1167 XFONT_CreateAlias( frMatch
->lfFaceName
, lpAlias
);
1171 else ERR(font
, " malformed font alias '%s'\n", *buffer
);
1177 /***********************************************************************
1178 * XFONT_LoadPenalties
1180 * Removes specified fonts from the font table to prevent Wine from
1183 * Ignore# = [LFD font name]
1186 * Ignore0 = -misc-nil-
1187 * Ignore1 = -sun-open look glyph-
1191 static void XFONT_LoadPenalties( char** buffer
, int *buf_size
)
1194 char subsection
[32];
1196 if( *buf_size
< 128 )
1198 *buffer
= HeapReAlloc(SystemHeap
, 0, *buffer
, 256 );
1204 wsprintf32A( subsection
, "%s%i", INIIgnoreSection
, i
++ );
1206 if( PROFILE_GetWineIniString( INIFontSection
,
1207 subsection
, "", *buffer
, 255 ) )
1209 fontResource
** ppfr
;
1210 int length
= strlen( *buffer
);
1212 for( ppfr
= &fontList
; *ppfr
; ppfr
= &((*ppfr
)->next
))
1214 if( !strncasecmp( (*ppfr
)->resource
, *buffer
, length
) )
1216 TRACE(font
, "Ignoring '%s'\n", (*ppfr
)->resource
);
1218 XFONT_RemoveFontResource( ppfr
);
1228 /***********************************************************************
1229 * XFONT_UserMetricsCache
1231 * Returns expanded name for the ~/.wine/.cachedmetrics file.
1232 * Now it also appends the current value of the $DISPLAY varaible.
1234 static char* XFONT_UserMetricsCache( char* buffer
, int* buf_size
)
1239 pchDisplay
= getenv( "DISPLAY" );
1240 if( !pchDisplay
) pchDisplay
= "0";
1242 pwd
= getpwuid(getuid());
1243 if( pwd
&& pwd
->pw_dir
)
1245 int i
= strlen( pwd
->pw_dir
) + strlen( INIWinePrefix
) +
1246 strlen( INIFontMetrics
) + strlen( pchDisplay
) + 2;
1248 buffer
= (char*) HeapReAlloc( SystemHeap
, 0, buffer
, *buf_size
= i
);
1249 strcpy( buffer
, pwd
->pw_dir
);
1250 strcat( buffer
, INIWinePrefix
);
1251 strcat( buffer
, INIFontMetrics
);
1252 strcat( buffer
, pchDisplay
);
1253 } else buffer
[0] = '\0';
1258 /***********************************************************************
1259 * XFONT_ReadCachedMetrics
1263 static BOOL32
XFONT_ReadCachedMetrics( int fd
, int res
, unsigned x_checksum
, int x_count
)
1270 /* read checksums */
1271 read( fd
, &u
, sizeof(unsigned) );
1272 read( fd
, &i
, sizeof(int) );
1274 if( u
== x_checksum
&& i
== x_count
)
1276 off_t length
, offset
= 3 * sizeof(int);
1278 /* read total size */
1279 read( fd
, &i
, sizeof(int) );
1280 length
= lseek( fd
, 0, SEEK_END
);
1282 if( length
== (i
+ offset
) )
1284 lseek( fd
, offset
, SEEK_SET
);
1285 fontList
= (fontResource
*)HeapAlloc( SystemHeap
, 0, i
);
1288 fontResource
* pfr
= fontList
;
1289 fontInfo
* pfi
= NULL
;
1291 TRACE(font
,"Reading cached font metrics:\n");
1293 read( fd
, fontList
, i
); /* read all metrics at once */
1294 while( offset
< length
)
1296 offset
+= sizeof(fontResource
) + sizeof(fontInfo
);
1297 pfr
->fi
= pfi
= (fontInfo
*)(pfr
+ 1);
1301 if( offset
> length
||
1302 (int)(pfi
->next
) != j
++ ) goto fail
;
1304 pfi
->df
.dfFace
= pfr
->lfFaceName
;
1305 pfi
->df
.dfHorizRes
= pfi
->df
.dfVertRes
= res
;
1306 pfi
->df
.dfPoints
= (INT16
)(((INT32
)(pfi
->df
.dfPixHeight
-
1307 pfi
->df
.dfInternalLeading
) * 72 + (res
>> 1)) / res
);
1308 pfi
->next
= pfi
+ 1;
1310 if( j
> pfr
->fi_count
) break;
1313 offset
+= sizeof(fontInfo
);
1318 pfr
->next
= (fontResource
*)(pfi
+ 1);
1323 if( pfr
->next
== NULL
&&
1324 *(int*)(pfi
+ 1) == X_FMC_MAGIC
)
1326 /* read LFD stubs */
1327 char* lpch
= (char*)((int*)(pfi
+ 1) + 1);
1328 offset
+= sizeof(int);
1329 for( pfr
= fontList
; pfr
; pfr
= pfr
->next
)
1331 TRACE(font
,"\t%s, %i instances\n", lpch
, pfr
->fi_count
);
1332 pfr
->resource
= lpch
;
1335 if( ++offset
> length
) goto fail
;
1336 if( !*lpch
++ ) break;
1346 if( fontList
) HeapFree( SystemHeap
, 0, fontList
);
1353 /***********************************************************************
1354 * XFONT_WriteCachedMetrics
1358 static BOOL32
XFONT_WriteCachedMetrics( int fd
, unsigned x_checksum
, int x_count
, int n_ff
)
1367 /* font metrics file:
1371 * +0008 total size to load
1372 * +000C prepackaged font metrics
1375 * +...x + 4 LFD stubs
1378 write( fd
, &x_checksum
, sizeof(unsigned) );
1379 write( fd
, &x_count
, sizeof(int) );
1381 for( j
= i
= 0, pfr
= fontList
; pfr
; pfr
= pfr
->next
)
1383 i
+= strlen( pfr
->resource
) + 1;
1386 i
+= n_ff
* sizeof(fontResource
) + j
* sizeof(fontInfo
) + sizeof(int);
1387 write( fd
, &i
, sizeof(int) );
1389 TRACE(font
,"Writing font cache:\n");
1391 for( pfr
= fontList
; pfr
; pfr
= pfr
->next
)
1395 TRACE(font
,"\t%s, %i instances\n", pfr
->resource
, pfr
->fi_count
);
1397 i
= write( fd
, pfr
, sizeof(fontResource
) );
1398 if( i
== sizeof(fontResource
) )
1400 for( k
= 1, pfi
= pfr
->fi
; pfi
; pfi
= pfi
->next
)
1402 memcpy( &fi
, pfi
, sizeof(fi
) );
1404 fi
.df
.dfFace
= NULL
;
1405 fi
.next
= (fontInfo
*)k
; /* loader checks this */
1407 j
= write( fd
, &fi
, sizeof(fi
) );
1410 if( j
== sizeof(fontInfo
) ) continue;
1414 if( i
== sizeof(fontResource
) && j
== sizeof(fontInfo
) )
1416 i
= j
= X_FMC_MAGIC
;
1417 write( fd
, &i
, sizeof(int) );
1418 for( pfr
= fontList
; pfr
&& i
== j
; pfr
= pfr
->next
)
1420 i
= strlen( pfr
->resource
) + 1;
1421 j
= write( fd
, pfr
->resource
, i
);
1430 /***********************************************************************
1431 * XFONT_CheckIniSection
1435 * Examines wine.conf for old/invalid font entries and recommend changes to
1439 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
1440 * Original implementation.
1442 static void XFONT_CheckIniCallback(char const *, char const *, void *);
1444 static char const *fontmsgprologue
=
1446 " The following entries in the [fonts] section of the wine.conf file are\n"
1447 " obsolete or invalid:\n";
1449 static char const *fontmsgepilogue
=
1450 " These entries should be eliminated or updated.\n"
1451 " See the documentation/fonts file for more information.\n";
1453 static int XFONT_CheckIniSection()
1457 PROFILE_EnumerateWineIniSection("Fonts", &XFONT_CheckIniCallback
,
1460 MSG(fontmsgepilogue
);
1465 static void XFONT_CheckIniCallback(
1470 /* Ignore any keys that start with potential comment characters "'", '#',
1472 if(key
[0] == '\'' || key
[0] == '#' || key
[0] == ';' || key
[0] == '\0')
1475 /* Make sure this is a valid key */
1476 if((strncasecmp(key
, INIAliasSection
, 5) == 0) ||
1477 (strncasecmp(key
, INIIgnoreSection
, 6) == 0) ||
1478 (strcasecmp( key
, INIDefault
) == 0) ||
1479 (strcasecmp( key
, INIDefaultFixed
) == 0) ||
1480 (strcasecmp( key
, INIGlobalMetrics
) == 0) ||
1481 (strcasecmp( key
, INIResolution
) == 0) ||
1482 (strcasecmp( key
, INIDefaultSerif
) == 0) ||
1483 (strcasecmp( key
, INIDefaultSansSerif
) ==0) )
1485 /* Valid key; make sure the value doesn't contain a wildcard */
1486 if(strchr(value
, '*')) {
1487 if(*(int *)found
== 0) {
1488 MSG(fontmsgprologue
);
1492 MSG(" %s=%s [no wildcards allowed]\n", key
, value
);
1496 /* Not a valid key */
1497 if(*(int *)found
== 0) {
1498 MSG(fontmsgprologue
);
1502 MSG(" %s=%s [obsolete]\n", key
, value
);
1508 /***********************************************************************
1509 * XFONT_GetPointResolution()
1513 * Here we initialize DefResolution which is used in the
1514 * XFONT_Match() penalty function. We also load the point
1515 * resolution value (higher values result in larger fonts).
1517 static int XFONT_GetPointResolution( DeviceCaps
* pDevCaps
)
1519 int i
, j
, point_resolution
, num
= 3;
1520 int allowed_xfont_resolutions
[3] = { 72, 75, 100 };
1521 int best
= 0, best_diff
= 65536;
1523 DefResolution
= point_resolution
= PROFILE_GetWineIniInt( INIFontSection
, INIResolution
, 0 );
1524 if( !DefResolution
) DefResolution
= point_resolution
= pDevCaps
->logPixelsY
;
1525 else pDevCaps
->logPixelsX
= pDevCaps
->logPixelsY
= DefResolution
;
1527 for( i
= best
= 0; i
< num
; i
++ )
1529 j
= abs( DefResolution
- allowed_xfont_resolutions
[i
] );
1536 DefResolution
= allowed_xfont_resolutions
[best
];
1537 return point_resolution
;
1540 /***********************************************************************
1541 * XFONT_BuildDefaultAliases
1545 * Alias "Helv", and "Tms Rmn" to the DefaultSansSerif and DefaultSerif
1546 * fonts respectively. Create font alias templates for "MS Sans Serif"
1547 * and "MS Serif", also pointing to DefaultSansSerif and DefaultSerif.
1549 static int XFONT_BuildDefaultAliases( char** buffer
, int* buf_size
)
1552 aliasTemplate fatDefaultSerif
= { "-bitstream-charter-", "Charter" };
1553 aliasTemplate fatDefaultSansSerif
= { "-adobe-helvetica-", "Helvetica" };
1557 /* Make sure our buffer is big enough; update calling function's
1558 buf_size if we change it. */
1560 if( *buf_size
< 128 )
1562 *buffer
= HeapReAlloc( SystemHeap
, 0, *buffer
, 256 );
1566 /* Get the X11 name of the default serif font from the Wine INI file.
1567 (-bitstream-charter- is the default.) */
1569 PROFILE_GetWineIniString( INIFontSection
, INIDefaultSerif
,
1570 fatDefaultSerif
.fatResource
, *buffer
, 128 );
1572 /* Find the Windows typeface which corresponds to the X11 font. */
1574 for( fr
= fontList
; fr
; fr
= fr
->next
)
1575 if( !strcasecmp( fr
->resource
, *buffer
) ) break;
1577 /* Update the Alias Table entry for "Tms Rmn" with the default serif font's
1578 typeface. Update the Alias Template for "MS Serif" with the default
1579 serif font's X11 name. Note that this method leaves us dependant on
1580 the order of the Alias Table and the Alias Templates. Also, we don't
1581 check for or handle a situation in which -bitstream-charter- is not
1586 TRACE(font
, "Using \'%s\' as default serif font\n", fr
->lfFaceName
);
1587 aliasTable
[1].faTypeFace
= fr
->lfFaceName
;
1588 faTemplate
[1].fatResource
= fr
->resource
;
1592 WARN(font
, "No typeface found for \'%s\'; using \'%s\'\n", *buffer
,
1593 fatDefaultSerif
.fatAlias
);
1594 aliasTable
[1].faTypeFace
= fatDefaultSerif
.fatAlias
; /* Charter */
1595 faTemplate
[1].fatResource
= fatDefaultSerif
.fatResource
;
1598 /* Get the X11 name of the default sans serif font from the Wine INI file.
1599 (-adobe-helvetica- is the default.) */
1601 PROFILE_GetWineIniString (INIFontSection
, INIDefaultSansSerif
,
1602 fatDefaultSansSerif
.fatResource
, *buffer
, 128 );
1604 /* Find the Windows typeface which corresponds to the X11 font. */
1606 for( fr
= fontList
; fr
; fr
= fr
->next
)
1607 if ( !strcasecmp( fr
->resource
, *buffer
) ) break;
1609 /* Update the Alias Table entry for "Helv" with the default sans serif font's
1610 typeface. Update the Alias Template for "MS Sans Serif" with the
1611 default sans serif font's X11 name. Note that this method leaves us
1612 dependant on the order of the Alias Table and the Alias Templates.
1613 Also, we don't check for or handle a situation in which
1614 -adobe-helvetica- is not available. */
1618 TRACE(font
, "Using \'%s\' as default sans serif font\n", fr
->lfFaceName
);
1619 aliasTable
[0].faTypeFace
= fr
->lfFaceName
;
1620 faTemplate
[0].fatResource
= fr
->resource
;
1624 WARN(font
, "No typeface found for \'%s\'; using \'%s\'\n", *buffer
,
1625 fatDefaultSansSerif
.fatAlias
);
1626 aliasTable
[0].faTypeFace
= fatDefaultSansSerif
.fatAlias
; /* Helvetica */
1627 faTemplate
[0].fatResource
= fatDefaultSansSerif
.fatResource
;
1633 /***********************************************************************
1636 * Initialize font resource list and allocate font cache.
1638 BOOL32
X11DRV_FONT_Init( DeviceCaps
* pDevCaps
)
1641 fontResource
* fr
, *pfr
;
1643 unsigned x_checksum
;
1644 int i
, j
, res
, x_count
, fd
= -1, buf_size
= 0;
1645 char* lpstr
, *lpch
, *lpmetrics
, *buffer
;
1648 XFONT_CheckIniSection();
1650 res
= XFONT_GetPointResolution( pDevCaps
);
1652 x_pattern
= TSXListFonts(display
, "*", MAX_FONT_FAMILIES
* 16, &x_count
);
1654 TRACE(font
,"Font Mapper: initializing %i fonts [LPY=%i, XDR=%i, DR=%i]\n",
1655 x_count
, pDevCaps
->logPixelsY
, DefResolution
, res
);
1656 for( i
= x_checksum
= 0; i
< x_count
; i
++ )
1659 printf("%i\t: %s\n", i
, x_pattern
[i
] );
1662 j
= strlen( x_pattern
[i
] );
1663 if( j
) x_checksum
^= __genericCheckSum( x_pattern
[i
], j
);
1665 x_checksum
|= X_PFONT_MAGIC
;
1668 buffer
= HeapAlloc( SystemHeap
, 0, buf_size
);
1671 /* deal with systemwide font metrics cache */
1673 if( PROFILE_GetWineIniString( INIFontSection
, INIGlobalMetrics
, "", buffer
, 128 ) )
1674 fd
= open( buffer
, O_RDONLY
);
1676 if( XFONT_ReadCachedMetrics(fd
, res
, x_checksum
, x_count
) == FALSE
)
1679 buffer
= XFONT_UserMetricsCache( buffer
, &buf_size
);
1682 fd
= open( buffer
, O_RDONLY
);
1683 if( XFONT_ReadCachedMetrics(fd
, res
, x_checksum
, x_count
) == FALSE
)
1684 lpmetrics
= HEAP_strdupA( SystemHeap
, 0, buffer
); /* update later on */
1689 if( fontList
== NULL
) /* build metrics from scratch */
1694 for( i
= n_ff
= 0; i
< x_count
; i
++ )
1696 typeface
= lpch
= x_pattern
[i
];
1698 lpch
= LFD_Advance(typeface
, 3); /* extra '-' in the beginning */
1699 if( !*lpch
) continue;
1702 j
= lpch
- typeface
; /* resource name length */
1704 /* find a family to insert into */
1706 for( pfr
= NULL
, fr
= fontList
; fr
; fr
= fr
->next
)
1708 if( !strncasecmp(fr
->resource
, typeface
, j
) &&
1709 strlen(fr
->resource
) == j
) break;
1713 if( !fi
) fi
= (fontInfo
*) HeapAlloc(SystemHeap
, 0, sizeof(fontInfo
));
1715 if( !fr
) /* add new family */
1717 if( n_ff
>= MAX_FONT_FAMILIES
) break;
1718 if( !LFD_InitFontInfo( fi
, lpstr
) ) continue;
1721 fr
= (fontResource
*) HeapAlloc(SystemHeap
, 0, sizeof(fontResource
));
1722 memset(fr
, 0, sizeof(fontResource
));
1723 fr
->resource
= (char*) HeapAlloc(SystemHeap
, 0, j
+ 1 );
1724 lstrcpyn32A( fr
->resource
, typeface
, j
+ 1 );
1726 TRACE(font
," family: %s\n", fr
->resource
);
1728 if( pfr
) pfr
->next
= fr
;
1731 else if( !LFD_InitFontInfo( fi
, lpstr
) ) continue;
1733 /* check if we already have something better than "fi" */
1735 for( pfi
= fr
->fi
, j
= 0; pfi
&& j
<= 0; pfi
= pfi
->next
)
1736 if( (j
= XFONT_IsSubset( pfi
, fi
)) < 0 )
1737 pfi
->fi_flags
|= FI_SUBSET
; /* superseded by "fi" */
1738 if( j
> 0 ) continue;
1740 /* add new font instance "fi" to the "fr" font resource */
1742 if( fi
->fi_flags
& FI_SCALABLE
)
1744 /* set scalable font height to 24 to get an origin for extrapolation */
1746 j
= strlen(typeface
); j
+= 0x10;
1748 buffer
= (char*)HeapReAlloc( SystemHeap
, 0, buffer
, buf_size
= j
);
1750 lpch
= LFD_Advance(typeface
, 7);
1751 memcpy( buffer
, typeface
, (j
= lpch
- typeface
) );
1752 lpch
= LFD_Advance(lpch
, 4);
1753 sprintf( buffer
+ j
, "%d-%d-%d-*-%c-*-", fi
->lfd_height
,
1754 fi
->lfd_decipoints
, fi
->lfd_resolution
,
1755 (*lpch
== '-')?'*':*lpch
);
1756 lpch
= LFD_Advance(lpch
, 2);
1757 strcat( lpstr
= buffer
, lpch
);
1759 else lpstr
= typeface
;
1761 if( (x_fs
= TSXLoadQueryFont(display
, lpstr
)) )
1763 fi
->df
.dfHorizRes
= fi
->df
.dfVertRes
= res
;
1765 XFONT_SetFontMetric( fi
, fr
, x_fs
);
1766 TSXFreeFont( display
, x_fs
);
1768 TRACE(font
,"\t[% 2ipt] '%s'\n", fi
->df
.dfPoints
, typeface
);
1770 XFONT_CheckFIList( fr
, fi
, REMOVE_SUBSETS
);
1771 fi
= NULL
; /* preventing reuse */
1775 ERR(font
, "failed to load %s\n", lpstr
);
1777 XFONT_CheckFIList( fr
, fi
, UNMARK_SUBSETS
);
1781 if( lpmetrics
) /* update cached metrics */
1783 fd
= open( lpmetrics
, O_CREAT
| O_TRUNC
| O_RDWR
, 0644 ); /* -rw-r--r-- */
1784 if( XFONT_WriteCachedMetrics( fd
, x_checksum
, x_count
, n_ff
) == FALSE
)
1785 if( fd
) remove( lpmetrics
); /* couldn't write entire file */
1786 HeapFree( SystemHeap
, 0, lpmetrics
);
1790 if( fi
) HeapFree(SystemHeap
, 0, fi
);
1791 TSXFreeFontNames(x_pattern
);
1793 /* check if we're dealing with X11 R6 server */
1795 strcpy(buffer
, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
1796 if( (x_fs
= TSXLoadQueryFont(display
, buffer
)) )
1798 XTextCaps
|= TC_SF_X_YINDEP
;
1799 TSXFreeFont(display
, x_fs
);
1802 XFONT_WindowsNames( buffer
);
1803 XFONT_BuildDefaultAliases( &buffer
, &buf_size
);
1804 XFONT_LoadAliases( &buffer
, &buf_size
);
1805 XFONT_LoadPenalties( &buffer
, &buf_size
);
1806 HeapFree(SystemHeap
, 0, buffer
);
1808 InitializeCriticalSection( &crtsc_fonts_X11
);
1809 MakeCriticalSectionGlobal( &crtsc_fonts_X11
);
1811 /* fontList initialization is over, allocate X font cache */
1813 fontCache
= (fontObject
*) HeapAlloc(SystemHeap
, 0, fontCacheSize
* sizeof(fontObject
));
1814 XFONT_GrowFreeList(0, fontCacheSize
- 1);
1816 TRACE(font
,"done!\n");
1818 /* update text caps parameter */
1820 pDevCaps
->textCaps
= XTextCaps
;
1822 RAW_ASCENT
= TSXInternAtom(display
, "RAW_ASCENT", TRUE
);
1823 RAW_DESCENT
= TSXInternAtom(display
, "RAW_DESCENT", TRUE
);
1829 /***********************************************************************
1830 * XFONT_RemoveFontResource
1832 * Caller should check if the font resource is in use. If it is it should
1833 * set FR_REMOVED flag to delay removal until the resource is not in use
1836 void XFONT_RemoveFontResource( fontResource
** ppfr
)
1839 fontResource
* pfr
= *ppfr
;
1844 pfi
= pfr
->fi
->next
;
1845 HeapFree( SystemHeap
, 0, pfr
->fi
);
1848 HeapFree( SystemHeap
, 0, pfr
);
1851 /***********************************************************************
1854 * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1856 static INT32
XFONT_IsSubset(fontInfo
* match
, fontInfo
* fi
)
1860 /* 0 - keep both, 1 - keep match, -1 - keep fi */
1862 m
= (BYTE
*)&fi
->df
.dfPixWidth
- (BYTE
*)&fi
->df
.dfItalic
;
1863 if( memcmp(&match
->df
.dfItalic
, &fi
->df
.dfItalic
, m
)) return 0;
1865 if( (!((fi
->fi_flags
& FI_SCALABLE
) + (match
->fi_flags
& FI_SCALABLE
))
1866 && fi
->lfd_height
!= match
->lfd_height
) ||
1867 (!((fi
->fi_flags
& FI_POLYWEIGHT
) + (match
->fi_flags
& FI_POLYWEIGHT
))
1868 && fi
->df
.dfWeight
!= match
->df
.dfWeight
) ) return 0;
1870 m
= (int)(match
->fi_flags
& (FI_POLYWEIGHT
| FI_SCALABLE
)) -
1871 (int)(fi
->fi_flags
& (FI_SCALABLE
| FI_POLYWEIGHT
));
1873 if( m
== (FI_POLYWEIGHT
- FI_SCALABLE
) ||
1874 m
== (FI_SCALABLE
- FI_POLYWEIGHT
) ) return 0; /* keep both */
1875 else if( m
>= 0 ) return 1; /* 'match' is better */
1877 return -1; /* 'fi' is better */
1880 /***********************************************************************
1883 * Compute the matching score between the logical font and the device font.
1885 * contributions from highest to lowest:
1889 * family flags (only when the facename is not present)
1891 * weight, italics, underlines, strikeouts
1893 * NOTE: you can experiment with different penalty weights to see what happens.
1894 * http://premium.microsoft.com/msdn/library/techart/f365/f36b/f37b/d38b/sa8bf.htm
1896 static UINT32
XFONT_Match( fontMatch
* pfm
)
1898 fontInfo
* pfi
= pfm
->pfi
; /* device font to match */
1899 LPLOGFONT16 plf
= pfm
->plf
; /* wanted logical font */
1901 BOOL32 bR6
= pfm
->flags
& FO_MATCH_XYINDEP
; /* from TextCaps */
1902 BOOL32 bScale
= pfi
->fi_flags
& FI_SCALABLE
;
1905 TRACE(font
,"\t[ %-2ipt h=%-3i w=%-3i %s%s]\n", pfi
->df
.dfPoints
,
1906 pfi
->df
.dfPixHeight
, pfi
->df
.dfAvgWidth
,
1907 (pfi
->df
.dfWeight
> 400) ? "Bold " : "Normal ",
1908 (pfi
->df
.dfItalic
) ? "Italic" : "" );
1912 if( plf
->lfCharSet
== DEFAULT_CHARSET
)
1914 if( (pfi
->df
.dfCharSet
!= ANSI_CHARSET
) && (pfi
->df
.dfCharSet
!=DEFAULT_CHARSET
) )
1917 else if (plf
->lfCharSet
!= pfi
->df
.dfCharSet
) penalty
+= 0x200;
1919 /* FIXME: Hack to demote symbols and nil fonts. Should take into
1920 account if a program ever actually asked for this type of
1922 if ( (strcmp(pfm
->pfr
->lfFaceName
,"Symbol")==0) || (strcmp(pfm
->pfr
->lfFaceName
,"Nil")==0) )
1923 penalty
+= 0x200; /* very stiff penality */
1925 /* TMPF_FIXED_PITCH means exactly the opposite */
1927 if( plf
->lfPitchAndFamily
& FIXED_PITCH
)
1929 if( pfi
->df
.dfPitchAndFamily
& TMPF_FIXED_PITCH
) penalty
+= 0x100;
1931 else if( !(pfi
->df
.dfPitchAndFamily
& TMPF_FIXED_PITCH
) ) penalty
+= 0x2;
1933 if( plf
->lfHeight
> 0 )
1934 d
= (h
= pfi
->df
.dfPixHeight
) - plf
->lfHeight
;
1935 else if( plf
->lfHeight
< -1 )
1936 d
= (h
= pfi
->df
.dfPoints
) + plf
->lfHeight
;
1939 if( d
&& h
&& plf
->lfHeight
)
1941 UINT16 height
= ( plf
->lfHeight
> 0 ) ? plf
->lfHeight
1942 : ((-plf
->lfHeight
* pfi
->df
.dfPixHeight
) / h
);
1943 if( bScale
) pfm
->height
= height
;
1944 else if( (plf
->lfQuality
!= PROOF_QUALITY
) && bR6
)
1946 if( d
> 0 ) /* do not shrink raster fonts */
1948 pfm
->height
= pfi
->df
.dfPixHeight
;
1949 penalty
+= (pfi
->df
.dfPixHeight
- height
) * 0x4;
1951 else /* expand only in integer multiples */
1953 pfm
->height
= height
- height
%pfi
->df
.dfPixHeight
;
1954 penalty
+= (height
- pfm
->height
+ 1) * height
/ pfi
->df
.dfPixHeight
;
1957 else /* can't be scaled at all */
1959 if( plf
->lfQuality
!= PROOF_QUALITY
) pfm
->flags
|= FO_SYNTH_HEIGHT
;
1960 pfm
->height
= pfi
->df
.dfPixHeight
;
1961 penalty
+= (d
> 0)? d
* 0x8 : -d
* 0x10;
1964 else pfm
->height
= pfi
->df
.dfPixHeight
;
1966 if((pfm
->flags
& FO_MATCH_PAF
) &&
1967 (plf
->lfPitchAndFamily
& FF_FAMILY
) != (pfi
->df
.dfPitchAndFamily
& FF_FAMILY
) )
1972 if( bR6
&& bScale
) h
= 0;
1975 /* FIXME: not complete */
1977 pfm
->flags
|= FO_SYNTH_WIDTH
;
1978 h
= abs(plf
->lfWidth
- (pfm
->height
* pfi
->df
.dfAvgWidth
)/pfi
->df
.dfPixHeight
);
1980 penalty
+= h
* ( d
) ? 0x2 : 0x1 ;
1982 else if( !(pfi
->fi_flags
& FI_NORMAL
) ) penalty
++;
1984 if( plf
->lfWeight
!= FW_DONTCARE
)
1986 penalty
+= abs(plf
->lfWeight
- pfi
->df
.dfWeight
) / 40;
1987 if( plf
->lfWeight
> pfi
->df
.dfWeight
) pfm
->flags
|= FO_SYNTH_BOLD
;
1988 } else if( pfi
->df
.dfWeight
>= FW_BOLD
) penalty
++; /* choose normal by default */
1990 if( plf
->lfItalic
!= pfi
->df
.dfItalic
)
1993 pfm
->flags
|= FO_SYNTH_ITALIC
;
1996 if( plf
->lfUnderline
) pfm
->flags
|= FO_SYNTH_UNDERLINE
;
1997 if( plf
->lfStrikeOut
) pfm
->flags
|= FO_SYNTH_STRIKEOUT
;
1999 if( penalty
&& pfi
->lfd_resolution
!= DefResolution
)
2002 TRACE(font
," returning %i\n", penalty
);
2007 /***********************************************************************
2010 * Scan a particular font resource for the best match.
2012 static UINT32
XFONT_MatchFIList( fontMatch
* pfm
)
2014 BOOL32 skipRaster
= (pfm
->flags
& FO_MATCH_NORASTER
);
2015 UINT32 current_score
, score
= (UINT32
)(-1);
2016 UINT16 origflags
= pfm
->flags
; /* Preserve FO_MATCH_XYINDEP */
2017 fontMatch fm
= *pfm
;
2019 for( fm
.pfi
= pfm
->pfr
->fi
; fm
.pfi
&& score
; fm
.pfi
= fm
.pfi
->next
,
2020 fm
.flags
= origflags
)
2022 if( skipRaster
&& !(fm
.pfi
->fi_flags
& FI_SCALABLE
) )
2025 current_score
= XFONT_Match( &fm
);
2026 if( score
> current_score
)
2028 memcpy( pfm
, &fm
, sizeof(fontMatch
) );
2029 score
= current_score
;
2035 /***********************************************************************
2038 * REMOVE_SUBSETS - attach new fi and purge subsets
2039 * UNMARK_SUBSETS - remove subset flags from all fi entries
2041 static void XFONT_CheckFIList( fontResource
* fr
, fontInfo
* fi
, int action
)
2044 fontInfo
* pfi
, *prev
;
2046 for( prev
= NULL
, pfi
= fr
->fi
; pfi
; )
2048 if( action
== REMOVE_SUBSETS
)
2050 if( pfi
->fi_flags
& FI_SUBSET
)
2052 fontInfo
* subset
= pfi
;
2056 if( prev
) prev
->next
= pfi
= pfi
->next
;
2057 else fr
->fi
= pfi
= pfi
->next
;
2058 HeapFree( SystemHeap
, 0, subset
);
2062 else pfi
->fi_flags
&= ~FI_SUBSET
;
2068 if( action
== REMOVE_SUBSETS
) /* also add the superset */
2070 if( fi
->fi_flags
& FI_SCALABLE
)
2075 else if( prev
) prev
->next
= fi
; else fr
->fi
= fi
;
2079 if( i
) TRACE(font
,"\t purged %i subsets [%i]\n", i
, fr
->fi_count
);
2082 /***********************************************************************
2085 static fontResource
* XFONT_FindFIList( fontResource
* pfr
, const char* pTypeFace
)
2089 if( !strcasecmp( pfr
->lfFaceName
, pTypeFace
) ) break;
2095 /***********************************************************************
2096 * XFONT_MatchDeviceFont
2098 * Scan font resource tree.
2100 static BOOL32
XFONT_MatchDeviceFont( fontResource
* start
, fontMatch
* pfm
)
2102 fontResource
** ppfr
;
2103 fontMatch fm
= *pfm
;
2106 if( fm
.plf
->lfFaceName
[0] )
2111 for( fa
= aliasTable
; fa
; fa
= fa
->next
)
2112 if( !strcmp( fa
->faAlias
, fm
.plf
->lfFaceName
) )
2114 str
= fa
->faTypeFace
;
2117 fm
.pfr
= XFONT_FindFIList( start
, str
? str
: fm
.plf
->lfFaceName
);
2120 if( fm
.pfr
) /* match family */
2122 TRACE(font
, "%s\n", fm
.pfr
->lfFaceName
);
2124 if( fm
.pfr
->fr_flags
& FR_REMOVED
)
2128 XFONT_MatchFIList( &fm
);
2133 if( !pfm
->pfi
) /* match all available fonts */
2135 UINT32 current_score
, score
= (UINT32
)(-1);
2137 fm
.flags
|= FO_MATCH_PAF
;
2138 for( ppfr
= &fontList
; *ppfr
&& score
; ppfr
= &(*ppfr
)->next
)
2140 if( (*ppfr
)->fr_flags
& FR_REMOVED
)
2142 if( (*ppfr
)->fo_count
== 0 )
2143 XFONT_RemoveFontResource( ppfr
);
2149 TRACE(font
, "%s\n", fm
.pfr
->lfFaceName
);
2151 current_score
= XFONT_MatchFIList( &fm
);
2152 if( current_score
< score
)
2154 score
= current_score
;
2163 /***********************************************************************
2166 static void XFONT_GrowFreeList(int start
, int end
)
2168 /* add all entries from 'start' up to and including 'end' */
2170 memset( fontCache
+ start
, 0, (end
- start
+ 1) * sizeof(fontObject
) );
2172 fontCache
[end
].lru
= fontLF
;
2173 fontCache
[end
].count
= -1;
2175 while( start
< end
)
2177 fontCache
[start
].count
= -1;
2178 fontCache
[start
].lru
= start
+ 1;
2183 static fontObject
* XFONT_LookupCachedFont( LPLOGFONT16 plf
, UINT16
* checksum
)
2185 UINT16 cs
= __lfCheckSum( plf
);
2186 int i
= fontMRU
, prev
= -1;
2191 if( fontCache
[i
].lfchecksum
== cs
&&
2192 !(fontCache
[i
].fo_flags
& FO_REMOVED
) )
2194 /* FIXME: something more intelligent here */
2196 if( !memcmp( plf
, &fontCache
[i
].lf
,
2197 sizeof(LOGFONT16
) - LF_FACESIZE
) &&
2198 !strncasecmp( plf
->lfFaceName
, fontCache
[i
].lf
.lfFaceName
,
2201 /* remove temporarily from the lru list */
2204 fontCache
[prev
].lru
= fontCache
[i
].lru
;
2206 fontMRU
= (INT16
)fontCache
[i
].lru
;
2207 return (fontCache
+ i
);
2211 i
= (INT16
)fontCache
[i
].lru
;
2216 static fontObject
* XFONT_GetCacheEntry()
2222 int prev_i
, prev_j
, j
;
2224 TRACE(font
,"font cache is full\n");
2226 /* lookup the least recently used font */
2228 for( prev_i
= prev_j
= j
= -1, i
= fontMRU
; i
>= 0; i
= (INT16
)fontCache
[i
].lru
)
2230 if( fontCache
[i
].count
<= 0 &&
2231 !(fontCache
[i
].fo_flags
& FO_SYSTEM
) )
2239 if( j
>= 0 ) /* unload font */
2241 /* detach from the lru list */
2243 TRACE(font
,"\tfreeing entry %i\n", j
);
2245 fontCache
[j
].fr
->fo_count
--;
2248 fontCache
[prev_j
].lru
= fontCache
[j
].lru
;
2249 else fontMRU
= (INT16
)fontCache
[j
].lru
;
2251 /* FIXME: lpXForm, lpPixmap */
2252 if(fontCache
[j
].lpX11Trans
)
2253 HeapFree( SystemHeap
, 0, fontCache
[j
].lpX11Trans
);
2255 TSXFreeFont( display
, fontCache
[j
].fs
);
2257 memset( fontCache
+ j
, 0, sizeof(fontObject
) );
2258 return (fontCache
+ j
);
2260 else /* expand cache */
2262 fontObject
* newCache
;
2264 prev_i
= fontCacheSize
+ FONTCACHE
;
2266 TRACE(font
,"\tgrowing font cache from %i to %i\n", fontCacheSize
, prev_i
);
2268 if( (newCache
= (fontObject
*)HeapReAlloc(SystemHeap
, 0,
2269 fontCache
, prev_i
)) )
2272 fontCacheSize
= prev_i
;
2273 fontCache
= newCache
;
2274 XFONT_GrowFreeList( i
, fontCacheSize
- 1);
2280 /* detach from the free list */
2283 fontLF
= (INT16
)fontCache
[i
].lru
;
2284 fontCache
[i
].count
= 0;
2285 return (fontCache
+ i
);
2288 static int XFONT_ReleaseCacheEntry(fontObject
* pfo
)
2290 UINT32 u
= (UINT32
)(pfo
- fontCache
);
2292 if( u
< fontCacheSize
) return (--fontCache
[u
].count
);
2296 /**********************************************************************
2299 static BOOL32
XFONT_SetX11Trans( fontObject
*pfo
)
2305 TSXGetFontProperty( pfo
->fs
, XA_FONT
, &nameAtom
);
2306 fontName
= TSXGetAtomName( display
, nameAtom
);
2307 cp
= LFD_Advance( fontName
, 7 );
2313 while((cp
= strchr(cp
, '~')))
2316 #define PX pfo->lpX11Trans
2318 sscanf(start
, "[%f%f%f%f]", &PX
->a
, &PX
->b
, &PX
->c
, &PX
->d
);
2321 TSXGetFontProperty( pfo
->fs
, RAW_ASCENT
, &PX
->RAW_ASCENT
);
2322 TSXGetFontProperty( pfo
->fs
, RAW_DESCENT
, &PX
->RAW_DESCENT
);
2324 PX
->pixelsize
= hypot(PX
->a
, PX
->b
);
2325 PX
->ascent
= PX
->pixelsize
/ 1000.0 * PX
->RAW_ASCENT
;
2326 PX
->descent
= PX
->pixelsize
/ 1000.0 * PX
->RAW_DESCENT
;
2328 TRACE(font
, "[%f %f %f %f] RA = %ld RD = %ld\n", pfo
->lpX11Trans
->a
,
2329 pfo
->lpX11Trans
->b
, pfo
->lpX11Trans
->c
, pfo
->lpX11Trans
->d
,
2330 pfo
->lpX11Trans
->RAW_ASCENT
, pfo
->lpX11Trans
->RAW_DESCENT
);
2336 /***********************************************************************
2337 * X Device Font Objects
2339 static X_PHYSFONT
XFONT_RealizeFont( LPLOGFONT16 plf
)
2342 fontObject
* pfo
= XFONT_LookupCachedFont( plf
, &checksum
);
2346 fontMatch fm
= { NULL
, NULL
, 0, 0, plf
};
2349 if( XTextCaps
& TC_SF_X_YINDEP
) fm
.flags
= FO_MATCH_XYINDEP
;
2351 /* allocate new font cache entry */
2353 if( (pfo
= XFONT_GetCacheEntry()) )
2355 LPSTR lpLFD
= HeapAlloc( GetProcessHeap(), 0, MAX_LFD_LENGTH
);
2357 if( lpLFD
) /* initialize entry and load font */
2359 UINT32 uRelaxLevel
= 0;
2361 TRACE(font
,"(%u) '%s' h=%i weight=%i %s\n",
2362 plf
->lfCharSet
, plf
->lfFaceName
, plf
->lfHeight
,
2363 plf
->lfWeight
, (plf
->lfItalic
) ? "Italic" : "" );
2365 if(abs(plf
->lfHeight
) > MAX_FONT_SIZE
) {
2367 "plf->lfHeight = %d, this is probably not right. Setting to 100\n",
2369 plf
->lfHeight
= 100;
2372 XFONT_MatchDeviceFont( fontList
, &fm
);
2376 pfo
->fr
->fo_count
++;
2377 pfo
->fo_flags
= fm
.flags
& ~FO_MATCH_MASK
;
2379 memcpy( &pfo
->lf
, plf
, sizeof(LOGFONT16
) );
2380 pfo
->lfchecksum
= checksum
;
2384 LFD_ComposeLFD( pfo
, fm
.height
, lpLFD
, uRelaxLevel
++ );
2385 if( (pfo
->fs
= TSXLoadQueryFont( display
, lpLFD
)) ) break;
2386 } while( uRelaxLevel
);
2389 if(pfo
->lf
.lfEscapement
!= 0) {
2390 pfo
->lpX11Trans
= HeapAlloc(SystemHeap
, 0,
2391 sizeof(XFONTTRANS
));
2392 if(!XFONT_SetX11Trans( pfo
)) {
2393 HeapFree(SystemHeap
, 0, pfo
->lpX11Trans
);
2394 pfo
->lpX11Trans
= NULL
;
2398 if( XFONT_GetLeading( &pfo
->fi
->df
, pfo
->fs
, &i
, NULL
,
2401 if(!pfo
->lpX11Trans
)
2402 pfo
->foAvgCharWidth
=
2403 (INT16
)pfo
->fs
->per_char
['X' - pfo
->fs
->min_char_or_byte2
].width
;
2405 pfo
->foAvgCharWidth
=
2406 (INT16
)pfo
->fs
->per_char
['X' - pfo
->fs
->min_char_or_byte2
].attributes
2407 * pfo
->lpX11Trans
->pixelsize
/ 1000.0;
2409 pfo
->foAvgCharWidth
= (INT16
)XFONT_GetAvgCharWidth(
2410 &pfo
->fi
->df
, pfo
->fs
, pfo
->lpX11Trans
);
2411 pfo
->foMaxCharWidth
= (INT16
)XFONT_GetMaxCharWidth(pfo
);
2412 pfo
->foInternalLeading
= (INT16
)i
;
2414 /* FIXME: If we've got a soft font or
2415 * there are FO_SYNTH_... flags for the
2416 * non PROOF_QUALITY request, the engine
2417 * should rasterize characters into mono
2418 * pixmaps and store them in the pfo->lpPixmap
2419 * array (pfo->fs should be updated as well).
2420 * array (pfo->fs should be updated as well).
2421 * X11DRV_ExtTextOut() must be heavily modified
2422 * to support pixmap blitting and FO_SYNTH_...
2426 pfo
->lpPixmap
= NULL
;
2428 HeapFree( GetProcessHeap(), 0, lpLFD
);
2430 else /* attach back to the free list */
2434 fontLF
= (pfo
- fontCache
);
2439 if( !pfo
) /* couldn't get a new entry, get one of the cached fonts */
2441 UINT32 current_score
, score
= (UINT32
)(-1);
2443 i
= index
= fontMRU
;
2444 fm
.flags
|= FO_MATCH_PAF
;
2447 pfo
= fontCache
+ i
;
2448 fm
.pfr
= pfo
->fr
; fm
.pfi
= pfo
->fi
;
2450 current_score
= XFONT_Match( &fm
);
2451 if( current_score
< score
) index
= i
;
2455 pfo
= fontCache
+ index
;
2457 return (X_PHYSFONT
)(X_PFONT_MAGIC
| index
);
2461 /* attach at the head of the lru list */
2465 fontMRU
= (pfo
- fontCache
);
2467 TRACE(font
,"physfont %i\n", fontMRU
);
2469 return (X_PHYSFONT
)(X_PFONT_MAGIC
| fontMRU
);
2472 /***********************************************************************
2473 * XFONT_GetFontObject
2475 fontObject
* XFONT_GetFontObject( X_PHYSFONT pFont
)
2477 if( CHECK_PFONT(pFont
) ) return __PFONT(pFont
);
2481 /***********************************************************************
2482 * XFONT_GetFontStruct
2484 XFontStruct
* XFONT_GetFontStruct( X_PHYSFONT pFont
)
2486 if( CHECK_PFONT(pFont
) ) return __PFONT(pFont
)->fs
;
2490 /***********************************************************************
2493 LPIFONTINFO16
XFONT_GetFontInfo( X_PHYSFONT pFont
)
2495 if( CHECK_PFONT(pFont
) ) return &(__PFONT(pFont
)->fi
->df
);
2501 /* X11DRV Interface ****************************************************
2503 * Exposed via the dc->funcs dispatch table. *
2505 ***********************************************************************/
2506 /***********************************************************************
2507 * X11DRV_FONT_SelectObject
2509 HFONT32
X11DRV_FONT_SelectObject( DC
* dc
, HFONT32 hfont
, FONTOBJ
* font
)
2511 HFONT32 hPrevFont
= 0;
2513 X11DRV_PDEVICE
*physDev
= (X11DRV_PDEVICE
*)dc
->physDev
;
2515 EnterCriticalSection( &crtsc_fonts_X11
);
2517 if( CHECK_PFONT(physDev
->font
) )
2518 XFONT_ReleaseCacheEntry( __PFONT(physDev
->font
) );
2520 /* FIXME: do we need to pass anything back from here? */
2521 memcpy(&lf
,&font
->logfont
,sizeof(lf
));
2522 lf
.lfWidth
= font
->logfont
.lfWidth
* dc
->vportExtX
/dc
->wndExtX
;
2523 lf
.lfHeight
= font
->logfont
.lfHeight
* dc
->vportExtY
/dc
->wndExtY
;
2525 physDev
->font
= XFONT_RealizeFont( &lf
);
2526 hPrevFont
= dc
->w
.hFont
;
2527 dc
->w
.hFont
= hfont
;
2529 LeaveCriticalSection( &crtsc_fonts_X11
);
2535 /***********************************************************************
2537 * X11DRV_EnumDeviceFonts
2539 BOOL32
X11DRV_EnumDeviceFonts( DC
* dc
, LPLOGFONT16 plf
,
2540 DEVICEFONTENUMPROC proc
, LPARAM lp
)
2544 fontResource
* pfr
= fontList
;
2547 if( plf
->lfFaceName
[0] )
2549 /* enum all entries in this resource */
2550 pfr
= XFONT_FindFIList( pfr
, plf
->lfFaceName
);
2554 for( pfi
= pfr
->fi
; pfi
; pfi
= pfi
->next
)
2556 /* Note: XFONT_GetFontMetric() will have to
2557 release the crit section, font list will
2558 have to be retraversed on return */
2560 if( (b
= (*proc
)( (LPENUMLOGFONT16
)&lf
, &tm
,
2561 XFONT_GetFontMetric( pfi
, &lf
, &tm
), lp
)) )
2567 else /* enum first entry in each resource */
2568 for( ; pfr
; pfr
= pfr
->next
)
2572 if( (b
= (*proc
)( (LPENUMLOGFONT16
)&lf
, &tm
,
2573 XFONT_GetFontMetric( pfr
->fi
, &lf
, &tm
), lp
)) )
2582 /***********************************************************************
2583 * X11DRV_GetTextExtentPoint
2585 BOOL32
X11DRV_GetTextExtentPoint( DC
*dc
, LPCSTR str
, INT32 count
,
2588 X11DRV_PDEVICE
*physDev
= (X11DRV_PDEVICE
*)dc
->physDev
;
2589 fontObject
* pfo
= XFONT_GetFontObject( physDev
->font
);
2591 if( !pfo
->lpX11Trans
) {
2592 int dir
, ascent
, descent
;
2595 TSXTextExtents( pfo
->fs
, str
, count
, &dir
, &ascent
, &descent
, &info
);
2596 size
->cx
= abs((info
.width
+ dc
->w
.breakRem
+ count
*
2597 dc
->w
.charExtra
) * dc
->wndExtX
/ dc
->vportExtX
);
2598 size
->cy
= abs((pfo
->fs
->ascent
+ pfo
->fs
->descent
) *
2599 dc
->wndExtY
/ dc
->vportExtY
);
2603 float x
= 0.0, y
= 0.0;
2604 for(i
= 0; i
< count
; i
++) {
2605 x
+= pfo
->fs
->per_char
?
2606 pfo
->fs
->per_char
[str
[i
] - pfo
->fs
->min_char_or_byte2
].attributes
:
2607 pfo
->fs
->min_bounds
.attributes
;
2609 y
= pfo
->lpX11Trans
->RAW_ASCENT
+ pfo
->lpX11Trans
->RAW_DESCENT
;
2610 TRACE(font
, "x = %f y = %f\n", x
, y
);
2611 x
*= pfo
->lpX11Trans
->pixelsize
/ 1000.0;
2612 y
*= pfo
->lpX11Trans
->pixelsize
/ 1000.0;
2613 size
->cx
= fabsf((x
+ dc
->w
.breakRem
+ count
* dc
->w
.charExtra
) *
2614 dc
->wndExtX
/ dc
->vportExtX
);
2615 size
->cy
= fabsf(y
* dc
->wndExtY
/ dc
->vportExtY
);
2623 /***********************************************************************
2624 * X11DRV_GetTextMetrics
2626 BOOL32
X11DRV_GetTextMetrics(DC
*dc
, TEXTMETRIC32A
*metrics
)
2628 X11DRV_PDEVICE
*physDev
= (X11DRV_PDEVICE
*)dc
->physDev
;
2630 if( CHECK_PFONT(physDev
->font
) )
2632 fontObject
* pfo
= __PFONT(physDev
->font
);
2633 XFONT_GetTextMetric( pfo
, metrics
);
2641 /***********************************************************************
2642 * X11DRV_GetCharWidth
2644 BOOL32
X11DRV_GetCharWidth( DC
*dc
, UINT32 firstChar
, UINT32 lastChar
,
2647 X11DRV_PDEVICE
*physDev
= (X11DRV_PDEVICE
*)dc
->physDev
;
2648 fontObject
* pfo
= XFONT_GetFontObject( physDev
->font
);
2654 if (pfo
->fs
->per_char
== NULL
)
2655 for (i
= firstChar
; i
<= lastChar
; i
++)
2657 *buffer
++ = pfo
->fs
->min_bounds
.attributes
*
2658 pfo
->lpX11Trans
->pixelsize
/ 1000.0;
2660 *buffer
++ = pfo
->fs
->min_bounds
.width
;
2663 XCharStruct
*cs
, *def
;
2664 static XCharStruct __null_char
= { 0, 0, 0, 0, 0, 0 };
2666 CI_GET_CHAR_INFO(pfo
->fs
, pfo
->fs
->default_char
, &__null_char
,
2669 for (i
= firstChar
; i
<= lastChar
; i
++)
2671 if (i
>= pfo
->fs
->min_char_or_byte2
&&
2672 i
<= pfo
->fs
->max_char_or_byte2
)
2674 cs
= &pfo
->fs
->per_char
[(i
- pfo
->fs
->min_char_or_byte2
)];
2675 if (CI_NONEXISTCHAR(cs
)) cs
= def
;
2678 *buffer
++ = MAX(cs
->attributes
, 0) *
2679 pfo
->lpX11Trans
->pixelsize
/ 1000.0;
2681 *buffer
++ = MAX(cs
->width
, 0 );
2690 /***********************************************************************
2692 * Font Resource API *
2694 ***********************************************************************/
2695 /***********************************************************************
2696 * AddFontResource16 (GDI.119)
2698 * Can be either .FON, or .FNT, or .TTF, or .FOT font file.
2700 * FIXME: Load header and find the best-matching font in the fontList;
2701 * fixup dfPoints if all metrics are identical, otherwise create
2702 * new fontAlias. When soft font support is ready this will
2703 * simply create a new fontResource ('filename' will go into
2704 * the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE
2707 INT16 WINAPI
AddFontResource16( LPCSTR filename
)
2709 return AddFontResource32A( filename
);
2713 /***********************************************************************
2714 * AddFontResource32A (GDI32.2)
2716 INT32 WINAPI
AddFontResource32A( LPCSTR str
)
2718 FIXME(font
, "(%s): stub\n", debugres_a(str
));
2723 /***********************************************************************
2724 * AddFontResource32W (GDI32.4)
2726 INT32 WINAPI
AddFontResource32W( LPCWSTR str
)
2728 FIXME(font
, "(%s): stub\n", debugres_w(str
) );
2732 /***********************************************************************
2733 * RemoveFontResource16 (GDI.136)
2735 BOOL16 WINAPI
RemoveFontResource16( SEGPTR str
)
2737 FIXME(font
, "(%s): stub\n", debugres_a(PTR_SEG_TO_LIN(str
)));
2742 /***********************************************************************
2743 * RemoveFontResource32A (GDI32.284)
2745 BOOL32 WINAPI
RemoveFontResource32A( LPCSTR str
)
2747 /* This is how it should look like */
2749 fontResource** ppfr;
2750 BOOL32 retVal = FALSE;
2752 EnterCriticalSection( &crtsc_fonts_X11 );
2753 for( ppfr = &fontList; *ppfr; ppfr = &(*ppfr)->next )
2754 if( !strcasecmp( (*ppfr)->lfFaceName, str ) )
2756 if(((*ppfr)->fr_flags & (FR_SOFTFONT | FR_SOFTRESOURCE)) &&
2757 (*ppfr)->hOwnerProcess == GetCurrentProcess() )
2759 if( (*ppfr)->fo_count )
2760 (*ppfr)->fr_flags |= FR_REMOVED;
2762 XFONT_RemoveFontResource( ppfr );
2766 LeaveCriticalSection( &crtsc_fontList );
2769 FIXME(font
, "(%s): stub\n", debugres_a(str
));
2774 /***********************************************************************
2775 * RemoveFontResource32W (GDI32.286)
2777 BOOL32 WINAPI
RemoveFontResource32W( LPCWSTR str
)
2779 FIXME(font
, "(%s): stub\n", debugres_w(str
) );