Recovery of release 990110 after disk crash.
[wine.git] / graphics / x11drv / xfont.c
bloba36a5c091b82357af39683f7bd4c20b23e84f16a
1 /*
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).
8 */
10 #include <ctype.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <pwd.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include "ts_xlib.h"
20 #include <X11/Xatom.h>
21 #include <math.h>
22 #include <assert.h>
23 #include "heap.h"
24 #include "options.h"
25 #include "x11font.h"
26 #include "font.h"
27 #include "debug.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
47 LPSTR faTypeFace;
48 LPSTR faAlias;
49 struct __fontAlias* next;
50 } fontAlias;
52 typedef struct
54 LPSTR fatResource;
55 LPSTR fatAlias;
56 } aliasTemplate;
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" },
75 { NULL, "MS 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,
118 SYMBOL_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,
122 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 };
130 typedef struct __fet
132 LPSTR prefix;
133 LPSTR (*psuffix)[];
134 BYTE (*pcharset)[];
135 struct __fet* next;
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) \
188 cs = def; \
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; \
192 } else { \
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 /***********************************************************************
203 * Checksums
205 static UINT16 __lfCheckSum( LPLOGFONT16 plf )
207 CHAR font[LF_FACESIZE];
208 UINT16 checksum = 0;
209 UINT16 i;
211 #define ptr ((UINT16*)plf)
212 for( i = 0; i < 9; i++ ) checksum ^= *ptr++;
213 #undef ptr
214 i = 0;
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-- )
218 #undef ptr
219 #define ptr ((UINT16*)plf)
220 checksum ^= *ptr++;
221 #undef ptr
222 return checksum;
225 static UINT16 __genericCheckSum( const void *ptr, int size )
227 unsigned int checksum = 0;
228 const char *p = (const char *)ptr;
229 while (size-- > 0)
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)
240 int j = 0;
241 char* lpch = lpFont;
243 for( ; j < uParmsNo && *lpch; lpch++ ) if( *lpch == LFDSeparator[1] ) j++;
244 return lpch;
247 static void LFD_GetWeight( fontInfo* fi, LPSTR lpStr, int j)
249 if( j == 1 && *lpStr == '0' )
250 fi->fi_flags |= FI_POLYWEIGHT;
251 else if( j == 4 )
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;
266 else if( j == 5 )
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;
277 else
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)
284 if( l == 1 )
286 switch( tolower( *lpStr ) )
288 case '0': fi->fi_flags |= FI_POLYSLANT; /* haven't seen this one yet */
289 default:
290 case 'r': fi->df.dfItalic = 0;
291 break;
292 case 'o':
293 fi->fi_flags |= FI_OBLIQUE;
294 case 'i': fi->df.dfItalic = 1;
295 break;
297 return 0;
299 return 1;
302 /*************************************************************************
303 * LFD_InitFontInfo
305 * INIT ONLY
307 * Fill in some fields in the fontInfo struct.
309 static int LFD_InitFontInfo( fontInfo* fi, LPSTR lpstr )
311 LPSTR lpch;
312 int i, j, dec_style_check, scalability;
313 UINT16 tmp[3];
314 fontEncodingTemplate* boba;
316 memset(fi, 0, sizeof(fontInfo) );
318 /* weight name - */
319 lpch = LFD_Advance( lpstr, 1);
320 if( !*lpch ) return FALSE;
321 j = lpch - lpstr - 1;
322 LFD_GetWeight( fi, lpstr, j );
324 /* slant - */
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 );
330 /* width name - */
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;
335 else
336 fi->fi_flags |= FI_NORMAL;
338 /* style - */
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" */
344 j = 0;
345 *(lpch - 1) = '\0';
347 if( strstr(lpstr, "sans") )
349 fi->df.dfPitchAndFamily |= FF_SWISS;
350 j = 1;
352 if( strstr(lpstr, "script") )
354 fi->df.dfPitchAndFamily |= FF_SCRIPT;
355 j = 1;
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 */
370 *(lpch - 1) = '\0';
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);
389 switch( *lpstr )
391 case '\0': return FALSE;
393 case 'p': fi->fi_flags |= FI_VARIABLEPITCH;
394 break;
395 case 'c': fi->df.dfPitchAndFamily |= FF_MODERN;
396 fi->fi_flags |= FI_FIXEDEX;
397 /* fall through */
398 case 'm': fi->fi_flags |= FI_FIXEDPITCH;
399 break;
400 default:
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 */
410 *(lpch - 1) = '\0';
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];
437 goto done;
440 /* Note : LFD_ComposeLFD will produce 'prefix-*' encoding *
441 * if (*(boba->psuffix))[j] is NULL here */
443 else
445 for( j = 0; (*(boba->psuffix))[j] ; j++ );
446 fi->df.dfCharSet = (*(boba->pcharset))[j];
447 j = lpch[tmp[0]] ? 254 : 255;
451 done:
452 if( !boba ) return FALSE;
454 /* i - index into fETTable
455 * j - index into suffix array for fETTable[i]
456 * except:
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;
463 return TRUE;
467 /*************************************************************************
468 * LFD_ComposeLFD
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;
479 char* lpch;
480 char lpEncoding[64];
481 char h_string[64], point_string[64];
483 *(lpLFD+MAX_LFD_LENGTH-1)=0;
484 lstrcpy32A( lpLFD, fo->fr->resource );
486 /* add weight */
487 switch( fo->fi->df.dfWeight )
489 case FW_BOLD:
490 strcat( lpLFD, "bold" ); break;
491 case FW_REGULAR:
492 if( fo->fi->fi_flags & FI_FW_BOOK )
493 strcat( lpLFD, "book" );
494 else
495 strcat( lpLFD, "medium" );
496 break;
497 case FW_DEMIBOLD:
498 strcat( lpLFD, "demi" );
499 if( !( fo->fi->fi_flags & FI_FW_DEMI) )
500 strcat ( lpLFD, "bold" );
501 break;
502 case FW_BLACK:
503 strcat( lpLFD, "black" ); break;
504 case FW_LIGHT:
505 strcat( lpLFD, "light" ); break;
506 default:
507 strcat( lpLFD, "*" );
510 /* add slant */
511 if( fo->fi->df.dfItalic )
512 if( fo->fi->fi_flags & FI_OBLIQUE )
513 strcat( lpLFD, "-o" );
514 else
515 strcat( lpLFD, "-i" );
516 else
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-*-");
522 else
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;
536 else
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)};
547 char *s;
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='~';
552 } else {
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';
562 else
563 w = ( fo->fi->fi_flags & FI_VARIABLEPITCH ) ? 'p' : LFDSeparator[0];
565 /* encoding */
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;
573 switch( i )
575 case 254: strcat( lpEncoding, "*" );
576 break;
577 default:
579 if( (*(boba->psuffix))[i] )
580 strcat( lpEncoding, (*(boba->psuffix))[i] );
581 else
582 strcat( lpEncoding, "-*" );
583 /* fall through */
585 case 255: /* no suffix */
588 lpch = lpLFD + lstrlen32A(lpLFD);
589 ch = (fo->fi->fi_flags & FI_SCALABLE) ? '0' : LFDSeparator[0];
591 switch( uRelax )
593 /* RealizeFont() will call us repeatedly with increasing uRelax
594 * until XLoadFont() succeeds. */
596 case 0:
597 if( point )
599 sprintf( lpch, "%s-%s-%i-%c-%c-*-%s", h_string,
600 point_string,
601 fo->fi->lfd_resolution, ch, w, lpEncoding );
602 break;
604 /* fall through */
606 case 1:
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 );
610 break;
612 case 3:
613 sprintf( lpch, "%s-*-%i-%c-*-*-%s",
614 h_string, fo->fi->lfd_resolution, ch, lpEncoding );
615 break;
617 case 4:
618 sprintf( lpch, "%i-*-%i-%c-*-*-%s", fo->fi->lfd_height,
619 fo->fi->lfd_resolution, ch, lpEncoding );
620 break;
622 case 5:
623 sprintf( lpch, "%i-*-*-*-*-*-%s", fo->fi->lfd_height, lpEncoding );
624 break;
626 default:
627 sprintf( lpch, "%i-*-*-*-*-*-*-*", fo->fi->lfd_height);
628 break;
630 /* to avoid an infinite loop; those will allways match */
631 case 200:
632 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1" );
633 break;
634 case 201:
635 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" );
636 break;
639 TRACE(font,"\tLFD(uRelax=%d): %s\n", uRelax, lpLFD );
640 assert(*(lpLFD+MAX_LFD_LENGTH-1)==0); /* check if overwrittem */
641 return TRUE;
645 /***********************************************************************
646 * X Font Resources
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 );
659 if( pEL ) *pEL = 0;
661 if(XFT) {
662 Atom RAW_CAP_HEIGHT = TSXInternAtom(display, "RAW_CAP_HEIGHT", TRUE);
663 if(TSXGetFontProperty(x_fs, RAW_CAP_HEIGHT, &height))
664 *pIL = XFT->ascent -
665 (INT32)(XFT->pixelsize / 1000.0 * height);
666 else
667 *pIL = 0;
668 return bHaveCapHeight && x_fs->per_char;
671 if( TSXGetFontProperty(x_fs, XA_CAP_HEIGHT, &height) == FALSE )
673 if( x_fs->per_char )
674 if( bHaveCapHeight )
675 height = x_fs->per_char['X' - min].ascent;
676 else
677 if (x_fs->ascent >= x_fs->max_bounds.ascent)
678 height = x_fs->max_bounds.ascent;
679 else
681 height = x_fs->ascent;
682 if( pEL )
683 *pEL = x_fs->max_bounds.ascent - height;
685 else
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,
694 XFONTTRANS *XFT)
696 unsigned min = (unsigned char)pFI->dfFirstChar;
697 unsigned max = (unsigned char)pFI->dfLastChar;
699 if( x_fs->per_char )
701 int width, chars, j;
702 for( j = 0, width = 0, chars = 0, max -= min; j <= max; j++ )
703 if( !CI_NONEXISTCHAR(x_fs->per_char + j) )
705 if(!XFT)
706 width += x_fs->per_char[j].width;
707 else
708 width += x_fs->per_char[j].attributes *
709 XFT->pixelsize / 1000.0;
710 chars++;
712 return (width / chars);
714 /* uniform width */
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;
723 if(!pfo->lpX11Trans)
724 return abs(pfo->fs->max_bounds.width);
726 if( pfo->fs->per_char )
728 int maxwidth, j;
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;
735 return maxwidth;
737 return pfo->foAvgCharWidth;
740 /***********************************************************************
741 * XFONT_SetFontMetric
743 * INIT ONLY
745 * Initializes IFONTINFO16. dfHorizRes and dfVertRes must be already set.
747 static void XFONT_SetFontMetric(fontInfo* fi, fontResource* fr, XFontStruct* xfs)
749 unsigned min, max;
750 INT32 el, il;
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;
764 else
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;
782 else
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;
800 } else {
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;
817 pTM->tmOverhang = 0;
818 if( pfo->fo_flags & FO_SYNTH_ITALIC )
820 pTM->tmOverhang += pTM->tmHeight/3;
821 pTM->tmItalic = 1;
822 } else
823 pTM->tmItalic = pdf->dfItalic;
825 pTM->tmWeight = pdf->dfWeight;
826 if( pfo->fo_flags & FO_SYNTH_BOLD )
828 pTM->tmOverhang++;
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 );
867 #undef plf
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 /***********************************************************************
885 * XFONT_FixupFlags
887 * INIT ONLY
889 * dfPitchAndFamily flags for some common typefaces.
891 static BYTE XFONT_FixupFlags( LPCSTR lfFaceName )
893 switch( lfFaceName[0] )
895 case 'h':
896 case 'H': if(!strcasecmp(lfFaceName, "Helvetica") )
897 return FF_SWISS;
898 break;
899 case 'c':
900 case 'C': if(!strcasecmp(lfFaceName, "Courier") ||
901 !strcasecmp(lfFaceName, "Charter") )
902 return FF_ROMAN;
903 break;
904 case 'p':
905 case 'P': if( !strcasecmp(lfFaceName,"Palatino") )
906 return FF_ROMAN;
907 break;
908 case 't':
909 case 'T': if(!strncasecmp(lfFaceName, "Times", 5) )
910 return FF_ROMAN;
911 break;
912 case 'u':
913 case 'U': if(!strcasecmp(lfFaceName, "Utopia") )
914 return FF_ROMAN;
915 break;
916 case 'z':
917 case 'Z': if(!strcasecmp(lfFaceName, "Zapf Dingbats") )
918 return FF_DECORATIVE;
920 return 0;
924 /***********************************************************************
925 * XFONT_CheckResourceName
927 * INIT ONLY
929 static BOOL32 XFONT_CheckResourceName( LPSTR resource, LPCSTR name, INT32 n )
931 resource = LFD_Advance( resource, 2 );
932 if( resource )
933 return (!strncasecmp( resource, name, n ));
934 return FALSE;
938 /***********************************************************************
939 * XFONT_WindowsNames
941 * INIT ONLY
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;
951 char* lpstr, *lpch;
952 int i, up;
953 BYTE bFamilyStyle;
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 ) )
966 break;
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 == ' ' )
976 *lpch = ' ';
977 up = 1; continue;
979 else if( isalpha(*lpstr) && up )
981 *lpch = toupper(*lpstr);
982 up = 0; continue;
984 *lpch = *lpstr;
986 while (*(lpch - 1) == ' ') *(--lpch) = '\0';
988 if( (bFamilyStyle = XFONT_FixupFlags( fr->lfFaceName )) )
990 fontInfo* fi;
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) )
1009 if( fr )
1011 fr->next = pfr->next;
1012 pfr->next = fontList;
1013 fontList = pfr;
1015 break;
1017 fr = pfr;
1022 /***********************************************************************
1023 * XFONT_CreateAlias
1025 static fontAlias* XFONT_CreateAlias( LPCSTR lpTypeFace, LPCSTR lpAlias )
1027 int j;
1028 fontAlias* pfa = aliasTable;
1030 while( 1 )
1032 /* check if we already got one */
1033 if( !strcasecmp( pfa->faTypeFace, lpAlias ) )
1035 TRACE(font,"\tredundant alias '%s' -> '%s'\n",
1036 lpAlias, lpTypeFace );
1037 return NULL;
1039 if( pfa->next ) pfa = pfa->next;
1040 else break;
1043 j = lstrlen32A(lpTypeFace) + 1;
1044 pfa->next = HeapAlloc( SystemHeap, 0, sizeof(fontAlias) +
1045 j + lstrlen32A(lpAlias) + 1 );
1046 if((pfa = pfa->next))
1048 pfa->next = NULL;
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 );
1056 return pfa;
1058 return NULL;
1061 /***********************************************************************
1062 * XFONT_LoadAliases
1064 * Read user-defined aliases from wine.conf. Format is as follows
1066 * Alias# = [Windows font name],[LFD font name], <substitute original name>
1068 * Example:
1069 * Alias0 = Arial, -adobe-helvetica-
1070 * Alias1 = Times New Roman, -bitstream-courier-, 1
1071 * ...
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];
1080 int i = 0, j = 0;
1081 BOOL32 bHaveAlias = TRUE, bSubst = FALSE;
1083 if( *buf_size < 128 )
1085 *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
1086 *buf_size = 256;
1090 if( j < faTemplateNum )
1092 /* built-in templates first */
1094 lpResource = faTemplate[j].fatResource;
1095 lpAlias = faTemplate[j].fatAlias;
1096 j++;
1098 else
1100 /* then WINE.CONF */
1102 wsprintf32A( subsection, "%s%i", INIAliasSection, i++ );
1104 if( (bHaveAlias = PROFILE_GetWineIniString( INIFontSection,
1105 subsection, "", *buffer, 128 )) )
1107 lpAlias = *buffer;
1108 while( isspace(*lpAlias) ) lpAlias++;
1109 lpResource = PROFILE_GetStringItem( lpAlias );
1110 bSubst = (PROFILE_GetStringItem( lpResource )) ? TRUE : FALSE;
1114 if( bHaveAlias )
1116 int length;
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;
1133 if( frMatch )
1135 if( bSubst )
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))
1144 if(prev)
1145 prev->next = pfa->next;
1146 else
1147 aliasTable = pfa->next;
1150 /* Update any references to the substituted font in aliasTable */
1151 if(!strcmp(frMatch->lfFaceName,
1152 pfa->faTypeFace))
1153 pfa->faTypeFace = HEAP_strdupA( SystemHeap, 0,
1154 lpAlias );
1155 prev = pfa;
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;
1164 else
1166 /* create new entry in the alias table */
1167 XFONT_CreateAlias( frMatch->lfFaceName, lpAlias );
1171 else ERR(font, " malformed font alias '%s'\n", *buffer );
1173 else break;
1174 } while(TRUE);
1177 /***********************************************************************
1178 * XFONT_LoadPenalties
1180 * Removes specified fonts from the font table to prevent Wine from
1181 * using it.
1183 * Ignore# = [LFD font name]
1185 * Example:
1186 * Ignore0 = -misc-nil-
1187 * Ignore1 = -sun-open look glyph-
1188 * ...
1191 static void XFONT_LoadPenalties( char** buffer, int *buf_size )
1193 int i = 0;
1194 char subsection[32];
1196 if( *buf_size < 128 )
1198 *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
1199 *buf_size = 256;
1200 *buffer = '\0';
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 );
1222 else
1223 break;
1224 } while(TRUE);
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 )
1236 struct passwd* pwd;
1237 char* pchDisplay;
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;
1247 if( i > *buf_size )
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';
1254 return buffer;
1258 /***********************************************************************
1259 * XFONT_ReadCachedMetrics
1261 * INIT ONLY
1263 static BOOL32 XFONT_ReadCachedMetrics( int fd, int res, unsigned x_checksum, int x_count )
1265 if( fd >= 0 )
1267 unsigned u;
1268 int i, j;
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);
1286 if( fontList )
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);
1298 j = 1;
1299 while( TRUE )
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;
1312 pfi = pfi->next;
1313 offset += sizeof(fontInfo);
1315 pfi->next = NULL;
1316 if( pfr->next )
1318 pfr->next = (fontResource*)(pfi + 1);
1319 pfr = pfr->next;
1321 else break;
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;
1333 while( TRUE )
1335 if( ++offset > length ) goto fail;
1336 if( !*lpch++ ) break;
1339 close( fd );
1340 return TRUE;
1345 fail:
1346 if( fontList ) HeapFree( SystemHeap, 0, fontList );
1347 fontList = NULL;
1348 close( fd );
1350 return FALSE;
1353 /***********************************************************************
1354 * XFONT_WriteCachedMetrics
1356 * INIT ONLY
1358 static BOOL32 XFONT_WriteCachedMetrics( int fd, unsigned x_checksum, int x_count, int n_ff )
1360 fontResource* pfr;
1361 fontInfo* pfi;
1363 if( fd >= 0 )
1365 int i, j, k;
1367 /* font metrics file:
1369 * +0000 x_checksum
1370 * +0004 x_count
1371 * +0008 total size to load
1372 * +000C prepackaged font metrics
1373 * ...
1374 * +...x X_FMC_MAGIC
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;
1384 j += pfr->fi_count;
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 )
1393 fontInfo fi;
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) );
1408 k++;
1410 if( j == sizeof(fontInfo) ) continue;
1412 break;
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 );
1424 close( fd );
1425 return ( i == j );
1427 return TRUE;
1430 /***********************************************************************
1431 * XFONT_CheckIniSection
1433 * INIT ONLY
1435 * Examines wine.conf for old/invalid font entries and recommend changes to
1436 * the user.
1438 * Revision history
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 =
1445 "Wine warning:\n"
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()
1455 int found = 0;
1457 PROFILE_EnumerateWineIniSection("Fonts", &XFONT_CheckIniCallback,
1458 (void *)&found);
1459 if(found)
1460 MSG(fontmsgepilogue);
1462 return 1;
1465 static void XFONT_CheckIniCallback(
1466 char const *key,
1467 char const *value,
1468 void *found)
1470 /* Ignore any keys that start with potential comment characters "'", '#',
1471 or ';'. */
1472 if(key[0] == '\'' || key[0] == '#' || key[0] == ';' || key[0] == '\0')
1473 return;
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);
1489 ++*(int *)found;
1492 MSG(" %s=%s [no wildcards allowed]\n", key, value);
1495 else {
1496 /* Not a valid key */
1497 if(*(int *)found == 0) {
1498 MSG(fontmsgprologue);
1499 ++*(int *)found;
1502 MSG(" %s=%s [obsolete]\n", key, value);
1505 return;
1508 /***********************************************************************
1509 * XFONT_GetPointResolution()
1511 * INIT ONLY
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] );
1530 if( j < best_diff )
1532 best = i;
1533 best_diff = j;
1536 DefResolution = allowed_xfont_resolutions[best];
1537 return point_resolution;
1540 /***********************************************************************
1541 * XFONT_BuildDefaultAliases
1543 * INIT ONLY
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" };
1555 fontResource* fr;
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 );
1563 *buf_size = 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
1582 available. */
1584 if( fr )
1586 TRACE(font, "Using \'%s\' as default serif font\n", fr->lfFaceName);
1587 aliasTable[1].faTypeFace = fr->lfFaceName;
1588 faTemplate[1].fatResource = fr->resource;
1590 else
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. */
1616 if( fr )
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;
1622 else
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;
1630 return 0;
1633 /***********************************************************************
1634 * X11DRV_FONT_Init
1636 * Initialize font resource list and allocate font cache.
1638 BOOL32 X11DRV_FONT_Init( DeviceCaps* pDevCaps )
1640 XFontStruct* x_fs;
1641 fontResource* fr, *pfr;
1642 fontInfo* fi, *pfi;
1643 unsigned x_checksum;
1644 int i, j, res, x_count, fd = -1, buf_size = 0;
1645 char* lpstr, *lpch, *lpmetrics, *buffer;
1646 char** x_pattern;
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++ )
1658 #if 0
1659 printf("%i\t: %s\n", i, x_pattern[i] );
1660 #endif
1662 j = strlen( x_pattern[i] );
1663 if( j ) x_checksum ^= __genericCheckSum( x_pattern[i], j );
1665 x_checksum |= X_PFONT_MAGIC;
1667 buf_size = 128;
1668 buffer = HeapAlloc( SystemHeap, 0, buf_size );
1669 lpmetrics = NULL;
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 )
1678 /* try per-user */
1679 buffer = XFONT_UserMetricsCache( buffer, &buf_size );
1680 if( buffer[0] )
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 */
1688 fi = NULL;
1689 if( fontList == NULL ) /* build metrics from scratch */
1691 int n_ff;
1692 char* typeface;
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;
1701 lpstr = lpch;
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;
1710 pfr = fr;
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;
1720 n_ff++;
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;
1729 else fontList = 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;
1747 if( j > buf_size )
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 */
1773 else
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);
1825 return 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
1834 * anymore.
1836 void XFONT_RemoveFontResource( fontResource** ppfr )
1838 fontInfo* pfi;
1839 fontResource* pfr = *ppfr;
1841 *ppfr = pfr->next;
1842 while( pfr->fi )
1844 pfi = pfr->fi->next;
1845 HeapFree( SystemHeap, 0, pfr->fi );
1846 pfr->fi = pfi;
1848 HeapFree( SystemHeap, 0, pfr );
1851 /***********************************************************************
1852 * X Font Matching
1854 * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1856 static INT32 XFONT_IsSubset(fontInfo* match, fontInfo* fi)
1858 INT32 m;
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 /***********************************************************************
1881 * XFONT_Match
1883 * Compute the matching score between the logical font and the device font.
1885 * contributions from highest to lowest:
1886 * charset
1887 * fixed pitch
1888 * height
1889 * family flags (only when the facename is not present)
1890 * width
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 */
1900 UINT32 penalty = 0;
1901 BOOL32 bR6 = pfm->flags & FO_MATCH_XYINDEP; /* from TextCaps */
1902 BOOL32 bScale = pfi->fi_flags & FI_SCALABLE;
1903 INT32 d, h;
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" : "" );
1910 pfm->flags = 0;
1912 if( plf->lfCharSet == DEFAULT_CHARSET )
1914 if( (pfi->df.dfCharSet!= ANSI_CHARSET) && (pfi->df.dfCharSet!=DEFAULT_CHARSET) )
1915 penalty += 0x200;
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
1921 font */
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;
1937 else d = h = 0;
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) )
1968 penalty += 0x10;
1970 if( plf->lfWidth )
1972 if( bR6 && bScale ) h = 0;
1973 else
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 )
1992 penalty += 0x4;
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 )
2000 penalty++;
2002 TRACE(font," returning %i\n", penalty );
2004 return penalty;
2007 /***********************************************************************
2008 * XFONT_MatchFIList
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) )
2023 continue;
2025 current_score = XFONT_Match( &fm );
2026 if( score > current_score )
2028 memcpy( pfm, &fm, sizeof(fontMatch) );
2029 score = current_score;
2032 return score;
2035 /***********************************************************************
2036 * XFONT_CheckFIList
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)
2043 int i = 0;
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;
2054 i++;
2055 fr->fi_count--;
2056 if( prev ) prev->next = pfi = pfi->next;
2057 else fr->fi = pfi = pfi->next;
2058 HeapFree( SystemHeap, 0, subset );
2059 continue;
2062 else pfi->fi_flags &= ~FI_SUBSET;
2064 prev = pfi;
2065 pfi = pfi->next;
2068 if( action == REMOVE_SUBSETS ) /* also add the superset */
2070 if( fi->fi_flags & FI_SCALABLE )
2072 fi->next = fr->fi;
2073 fr->fi = fi;
2075 else if( prev ) prev->next = fi; else fr->fi = fi;
2076 fr->fi_count++;
2079 if( i ) TRACE(font,"\t purged %i subsets [%i]\n", i , fr->fi_count);
2082 /***********************************************************************
2083 * XFONT_FindFIList
2085 static fontResource* XFONT_FindFIList( fontResource* pfr, const char* pTypeFace )
2087 while( pfr )
2089 if( !strcasecmp( pfr->lfFaceName, pTypeFace ) ) break;
2090 pfr = pfr->next;
2092 return pfr;
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;
2105 pfm->pfi = NULL;
2106 if( fm.plf->lfFaceName[0] )
2108 fontAlias* fa;
2109 LPSTR str = NULL;
2111 for( fa = aliasTable; fa; fa = fa->next )
2112 if( !strcmp( fa->faAlias, fm.plf->lfFaceName ) )
2114 str = fa->faTypeFace;
2115 break;
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 )
2125 fm.pfr = 0;
2126 else
2128 XFONT_MatchFIList( &fm );
2129 *pfm = 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 );
2144 continue;
2147 fm.pfr = *ppfr;
2149 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2151 current_score = XFONT_MatchFIList( &fm );
2152 if( current_score < score )
2154 score = current_score;
2155 *pfm = fm;
2159 return TRUE;
2163 /***********************************************************************
2164 * X Font Cache
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;
2174 fontLF = start;
2175 while( start < end )
2177 fontCache[start].count = -1;
2178 fontCache[start].lru = start + 1;
2179 start++;
2183 static fontObject* XFONT_LookupCachedFont( LPLOGFONT16 plf, UINT16* checksum )
2185 UINT16 cs = __lfCheckSum( plf );
2186 int i = fontMRU, prev = -1;
2188 *checksum = cs;
2189 while( i >= 0 )
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,
2199 LF_FACESIZE ) )
2201 /* remove temporarily from the lru list */
2203 if( prev >= 0 )
2204 fontCache[prev].lru = fontCache[i].lru;
2205 else
2206 fontMRU = (INT16)fontCache[i].lru;
2207 return (fontCache + i);
2210 prev = i;
2211 i = (INT16)fontCache[i].lru;
2213 return NULL;
2216 static fontObject* XFONT_GetCacheEntry()
2218 int i;
2220 if( fontLF == -1 )
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) )
2233 prev_j = prev_i;
2234 j = i;
2236 prev_i = i;
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--;
2247 if( prev_j >= 0 )
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)) )
2271 i = fontCacheSize;
2272 fontCacheSize = prev_i;
2273 fontCache = newCache;
2274 XFONT_GrowFreeList( i, fontCacheSize - 1);
2276 else return NULL;
2280 /* detach from the free list */
2282 i = fontLF;
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);
2293 return -1;
2296 /**********************************************************************
2297 * XFONT_SetX11Trans
2299 static BOOL32 XFONT_SetX11Trans( fontObject *pfo )
2301 char *fontName;
2302 Atom nameAtom;
2303 char *cp, *start;
2305 TSXGetFontProperty( pfo->fs, XA_FONT, &nameAtom );
2306 fontName = TSXGetAtomName( display, nameAtom );
2307 cp = LFD_Advance( fontName, 7 );
2308 if(*cp != '[') {
2309 TSXFree(fontName);
2310 return FALSE;
2312 start = cp;
2313 while((cp = strchr(cp, '~')))
2314 *cp = '-';
2316 #define PX pfo->lpX11Trans
2318 sscanf(start, "[%f%f%f%f]", &PX->a, &PX->b, &PX->c, &PX->d);
2319 TSXFree(fontName);
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);
2332 #undef PX
2333 return TRUE;
2336 /***********************************************************************
2337 * X Device Font Objects
2339 static X_PHYSFONT XFONT_RealizeFont( LPLOGFONT16 plf )
2341 UINT16 checksum;
2342 fontObject* pfo = XFONT_LookupCachedFont( plf, &checksum );
2344 if( !pfo )
2346 fontMatch fm = { NULL, NULL, 0, 0, plf};
2347 INT32 i, index;
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) {
2366 ERR(font,
2367 "plf->lfHeight = %d, this is probably not right. Setting to 100\n",
2368 plf->lfHeight);
2369 plf->lfHeight = 100;
2372 XFONT_MatchDeviceFont( fontList, &fm );
2374 pfo->fr = fm.pfr;
2375 pfo->fi = fm.pfi;
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,
2399 pfo->lpX11Trans ) )
2401 if(!pfo->lpX11Trans)
2402 pfo->foAvgCharWidth =
2403 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].width;
2404 else
2405 pfo->foAvgCharWidth =
2406 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].attributes
2407 * pfo->lpX11Trans->pixelsize / 1000.0;
2408 else
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_...
2423 * styles.
2426 pfo->lpPixmap = NULL;
2428 HeapFree( GetProcessHeap(), 0, lpLFD );
2430 else /* attach back to the free list */
2432 pfo->count = -1;
2433 pfo->lru = fontLF;
2434 fontLF = (pfo - fontCache);
2435 pfo = NULL;
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;
2453 i = pfo->lru;
2454 } while( i >= 0 );
2455 pfo = fontCache + index;
2456 pfo->count++;
2457 return (X_PHYSFONT)(X_PFONT_MAGIC | index);
2461 /* attach at the head of the lru list */
2463 pfo->count++;
2464 pfo->lru = fontMRU;
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);
2478 return NULL;
2481 /***********************************************************************
2482 * XFONT_GetFontStruct
2484 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
2486 if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
2487 return NULL;
2490 /***********************************************************************
2491 * XFONT_GetFontInfo
2493 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
2495 if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
2496 return NULL;
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;
2512 LOGFONT16 lf;
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 );
2531 return hPrevFont;
2535 /***********************************************************************
2537 * X11DRV_EnumDeviceFonts
2539 BOOL32 X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf,
2540 DEVICEFONTENUMPROC proc, LPARAM lp )
2542 ENUMLOGFONTEX16 lf;
2543 NEWTEXTMETRIC16 tm;
2544 fontResource* pfr = fontList;
2545 BOOL32 b, bRet = 0;
2547 if( plf->lfFaceName[0] )
2549 /* enum all entries in this resource */
2550 pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
2551 if( pfr )
2553 fontInfo* pfi;
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 )) )
2562 bRet = b;
2563 else break;
2567 else /* enum first entry in each resource */
2568 for( ; pfr ; pfr = pfr->next )
2570 if(pfr->fi)
2572 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2573 XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
2574 bRet = b;
2575 else break;
2578 return bRet;
2582 /***********************************************************************
2583 * X11DRV_GetTextExtentPoint
2585 BOOL32 X11DRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT32 count,
2586 LPSIZE32 size )
2588 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2589 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2590 if( pfo ) {
2591 if( !pfo->lpX11Trans ) {
2592 int dir, ascent, descent;
2593 XCharStruct info;
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);
2600 } else {
2602 INT32 i;
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);
2617 return TRUE;
2619 return FALSE;
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 );
2635 return TRUE;
2637 return FALSE;
2641 /***********************************************************************
2642 * X11DRV_GetCharWidth
2644 BOOL32 X11DRV_GetCharWidth( DC *dc, UINT32 firstChar, UINT32 lastChar,
2645 LPINT32 buffer )
2647 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2648 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2650 if( pfo )
2652 int i;
2654 if (pfo->fs->per_char == NULL)
2655 for (i = firstChar; i <= lastChar; i++)
2656 if(pfo->lpX11Trans)
2657 *buffer++ = pfo->fs->min_bounds.attributes *
2658 pfo->lpX11Trans->pixelsize / 1000.0;
2659 else
2660 *buffer++ = pfo->fs->min_bounds.width;
2661 else
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,
2667 def);
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;
2676 } else cs = def;
2677 if(pfo->lpX11Trans)
2678 *buffer++ = MAX(cs->attributes, 0) *
2679 pfo->lpX11Trans->pixelsize / 1000.0;
2680 else
2681 *buffer++ = MAX(cs->width, 0 );
2685 return TRUE;
2687 return FALSE;
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
2705 * flag set.
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));
2719 return 1;
2723 /***********************************************************************
2724 * AddFontResource32W (GDI32.4)
2726 INT32 WINAPI AddFontResource32W( LPCWSTR str )
2728 FIXME(font, "(%s): stub\n", debugres_w(str) );
2729 return 1;
2732 /***********************************************************************
2733 * RemoveFontResource16 (GDI.136)
2735 BOOL16 WINAPI RemoveFontResource16( SEGPTR str )
2737 FIXME(font, "(%s): stub\n", debugres_a(PTR_SEG_TO_LIN(str)));
2738 return TRUE;
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;
2761 else
2762 XFONT_RemoveFontResource( ppfr );
2764 retVal = TRUE;
2766 LeaveCriticalSection( &crtsc_fontList );
2767 return retVal;
2769 FIXME(font, "(%s): stub\n", debugres_a(str));
2770 return TRUE;
2774 /***********************************************************************
2775 * RemoveFontResource32W (GDI32.286)
2777 BOOL32 WINAPI RemoveFontResource32W( LPCWSTR str )
2779 FIXME(font, "(%s): stub\n", debugres_w(str) );
2780 return TRUE;