Cleaned up font encoding handling. Added 'Ignore#' option to the
[wine/multimedia.git] / graphics / x11drv / xfont.c
blobc0b7fda13c8d0da4b34dc6e15f191a04e8bed7fd
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 );
1810 /* fontList initialization is over, allocate X font cache */
1812 fontCache = (fontObject*) HeapAlloc(SystemHeap, 0, fontCacheSize * sizeof(fontObject));
1813 XFONT_GrowFreeList(0, fontCacheSize - 1);
1815 TRACE(font,"done!\n");
1817 /* update text caps parameter */
1819 pDevCaps->textCaps = XTextCaps;
1821 RAW_ASCENT = TSXInternAtom(display, "RAW_ASCENT", TRUE);
1822 RAW_DESCENT = TSXInternAtom(display, "RAW_DESCENT", TRUE);
1824 return TRUE;
1828 /***********************************************************************
1829 * XFONT_RemoveFontResource
1831 * Caller should check if the font resource is in use. If it is it should
1832 * set FR_REMOVED flag to delay removal until the resource is not in use
1833 * anymore.
1835 void XFONT_RemoveFontResource( fontResource** ppfr )
1837 fontInfo* pfi;
1838 fontResource* pfr = *ppfr;
1840 *ppfr = pfr->next;
1841 while( pfr->fi )
1843 pfi = pfr->fi->next;
1844 HeapFree( SystemHeap, 0, pfr->fi );
1845 pfr->fi = pfi;
1847 HeapFree( SystemHeap, 0, pfr );
1850 /***********************************************************************
1851 * X Font Matching
1853 * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1855 static INT32 XFONT_IsSubset(fontInfo* match, fontInfo* fi)
1857 INT32 m;
1859 /* 0 - keep both, 1 - keep match, -1 - keep fi */
1861 m = (BYTE*)&fi->df.dfPixWidth - (BYTE*)&fi->df.dfItalic;
1862 if( memcmp(&match->df.dfItalic, &fi->df.dfItalic, m )) return 0;
1864 if( (!((fi->fi_flags & FI_SCALABLE) + (match->fi_flags & FI_SCALABLE))
1865 && fi->lfd_height != match->lfd_height) ||
1866 (!((fi->fi_flags & FI_POLYWEIGHT) + (match->fi_flags & FI_POLYWEIGHT))
1867 && fi->df.dfWeight != match->df.dfWeight) ) return 0;
1869 m = (int)(match->fi_flags & (FI_POLYWEIGHT | FI_SCALABLE)) -
1870 (int)(fi->fi_flags & (FI_SCALABLE | FI_POLYWEIGHT));
1872 if( m == (FI_POLYWEIGHT - FI_SCALABLE) ||
1873 m == (FI_SCALABLE - FI_POLYWEIGHT) ) return 0; /* keep both */
1874 else if( m >= 0 ) return 1; /* 'match' is better */
1876 return -1; /* 'fi' is better */
1879 /***********************************************************************
1880 * XFONT_Match
1882 * Compute the matching score between the logical font and the device font.
1884 * contributions from highest to lowest:
1885 * charset
1886 * fixed pitch
1887 * height
1888 * family flags (only when the facename is not present)
1889 * width
1890 * weight, italics, underlines, strikeouts
1892 * NOTE: you can experiment with different penalty weights to see what happens.
1893 * http://premium.microsoft.com/msdn/library/techart/f365/f36b/f37b/d38b/sa8bf.htm
1895 static UINT32 XFONT_Match( fontMatch* pfm )
1897 fontInfo* pfi = pfm->pfi; /* device font to match */
1898 LPLOGFONT16 plf = pfm->plf; /* wanted logical font */
1899 UINT32 penalty = 0;
1900 BOOL32 bR6 = pfm->flags & FO_MATCH_XYINDEP; /* from TextCaps */
1901 BOOL32 bScale = pfi->fi_flags & FI_SCALABLE;
1902 INT32 d, h;
1904 TRACE(font,"\t[ %-2ipt h=%-3i w=%-3i %s%s]\n", pfi->df.dfPoints,
1905 pfi->df.dfPixHeight, pfi->df.dfAvgWidth,
1906 (pfi->df.dfWeight > 400) ? "Bold " : "Normal ",
1907 (pfi->df.dfItalic) ? "Italic" : "" );
1909 pfm->flags = 0;
1911 if( plf->lfCharSet == DEFAULT_CHARSET )
1913 if( (pfi->df.dfCharSet!= ANSI_CHARSET) && (pfi->df.dfCharSet!=DEFAULT_CHARSET) )
1914 penalty += 0x200;
1916 else if (plf->lfCharSet != pfi->df.dfCharSet) penalty += 0x200;
1918 /* FIXME: Hack to demote symbols and nil fonts. Should take into
1919 account if a program ever actually asked for this type of
1920 font */
1921 if ( (strcmp(pfm->pfr->lfFaceName,"Symbol")==0) || (strcmp(pfm->pfr->lfFaceName,"Nil")==0) )
1922 penalty += 0x200; /* very stiff penality */
1924 /* TMPF_FIXED_PITCH means exactly the opposite */
1926 if( plf->lfPitchAndFamily & FIXED_PITCH )
1928 if( pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH ) penalty += 0x100;
1930 else if( !(pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH) ) penalty += 0x2;
1932 if( plf->lfHeight > 0 )
1933 d = (h = pfi->df.dfPixHeight) - plf->lfHeight;
1934 else if( plf->lfHeight < -1 )
1935 d = (h = pfi->df.dfPoints) + plf->lfHeight;
1936 else d = h = 0;
1938 if( d && plf->lfHeight )
1940 UINT16 height = ( plf->lfHeight > 0 ) ? plf->lfHeight
1941 : ((-plf->lfHeight * pfi->df.dfPixHeight) / h);
1942 if( bScale ) pfm->height = height;
1943 else if( (plf->lfQuality != PROOF_QUALITY) && bR6 )
1945 if( d > 0 ) /* do not shrink raster fonts */
1947 pfm->height = pfi->df.dfPixHeight;
1948 penalty += (pfi->df.dfPixHeight - height) * 0x4;
1950 else /* expand only in integer multiples */
1952 pfm->height = height - height%pfi->df.dfPixHeight;
1953 penalty += (height - pfm->height + 1) * height / pfi->df.dfPixHeight;
1956 else /* can't be scaled at all */
1958 if( plf->lfQuality != PROOF_QUALITY) pfm->flags |= FO_SYNTH_HEIGHT;
1959 pfm->height = pfi->df.dfPixHeight;
1960 penalty += (d > 0)? d * 0x8 : -d * 0x10;
1962 } else pfm->height = pfi->df.dfPixHeight;
1964 if((pfm->flags & FO_MATCH_PAF) &&
1965 (plf->lfPitchAndFamily & FF_FAMILY) != (pfi->df.dfPitchAndFamily & FF_FAMILY) )
1966 penalty += 0x10;
1968 if( plf->lfWidth )
1970 if( bR6 && bScale ) h = 0;
1971 else
1973 /* FIXME: not complete */
1975 pfm->flags |= FO_SYNTH_WIDTH;
1976 h = abs(plf->lfWidth - (pfm->height * pfi->df.dfAvgWidth)/pfi->df.dfPixHeight);
1978 penalty += h * ( d ) ? 0x2 : 0x1 ;
1980 else if( !(pfi->fi_flags & FI_NORMAL) ) penalty++;
1982 if( plf->lfWeight != FW_DONTCARE )
1984 penalty += abs(plf->lfWeight - pfi->df.dfWeight) / 40;
1985 if( plf->lfWeight > pfi->df.dfWeight ) pfm->flags |= FO_SYNTH_BOLD;
1986 } else if( pfi->df.dfWeight >= FW_BOLD ) penalty++; /* choose normal by default */
1988 if( plf->lfItalic != pfi->df.dfItalic )
1990 penalty += 0x4;
1991 pfm->flags |= FO_SYNTH_ITALIC;
1994 if( plf->lfUnderline ) pfm->flags |= FO_SYNTH_UNDERLINE;
1995 if( plf->lfStrikeOut ) pfm->flags |= FO_SYNTH_STRIKEOUT;
1997 if( penalty && pfi->lfd_resolution != DefResolution )
1998 penalty++;
2000 TRACE(font," returning %i\n", penalty );
2002 return penalty;
2005 /***********************************************************************
2006 * XFONT_MatchFIList
2008 * Scan a particular font resource for the best match.
2010 static UINT32 XFONT_MatchFIList( fontMatch* pfm )
2012 BOOL32 skipRaster = (pfm->flags & FO_MATCH_NORASTER);
2013 UINT32 current_score, score = (UINT32)(-1);
2014 UINT16 origflags = pfm->flags; /* Preserve FO_MATCH_XYINDEP */
2015 fontMatch fm = *pfm;
2017 for( fm.pfi = pfm->pfr->fi; fm.pfi && score; fm.pfi = fm.pfi->next,
2018 fm.flags = origflags )
2020 if( skipRaster && !(fm.pfi->fi_flags & FI_SCALABLE) )
2021 continue;
2023 current_score = XFONT_Match( &fm );
2024 if( score > current_score )
2026 memcpy( pfm, &fm, sizeof(fontMatch) );
2027 score = current_score;
2030 return score;
2033 /***********************************************************************
2034 * XFONT_CheckFIList
2036 * REMOVE_SUBSETS - attach new fi and purge subsets
2037 * UNMARK_SUBSETS - remove subset flags from all fi entries
2039 static void XFONT_CheckFIList( fontResource* fr, fontInfo* fi, int action)
2041 int i = 0;
2042 fontInfo* pfi, *prev;
2044 for( prev = NULL, pfi = fr->fi; pfi; )
2046 if( action == REMOVE_SUBSETS )
2048 if( pfi->fi_flags & FI_SUBSET )
2050 fontInfo* subset = pfi;
2052 i++;
2053 fr->fi_count--;
2054 if( prev ) prev->next = pfi = pfi->next;
2055 else fr->fi = pfi = pfi->next;
2056 HeapFree( SystemHeap, 0, subset );
2057 continue;
2060 else pfi->fi_flags &= ~FI_SUBSET;
2062 prev = pfi;
2063 pfi = pfi->next;
2066 if( action == REMOVE_SUBSETS ) /* also add the superset */
2068 if( fi->fi_flags & FI_SCALABLE )
2070 fi->next = fr->fi;
2071 fr->fi = fi;
2073 else if( prev ) prev->next = fi; else fr->fi = fi;
2074 fr->fi_count++;
2077 if( i ) TRACE(font,"\t purged %i subsets [%i]\n", i , fr->fi_count);
2080 /***********************************************************************
2081 * XFONT_FindFIList
2083 static fontResource* XFONT_FindFIList( fontResource* pfr, const char* pTypeFace )
2085 while( pfr )
2087 if( !strcasecmp( pfr->lfFaceName, pTypeFace ) ) break;
2088 pfr = pfr->next;
2090 return pfr;
2093 /***********************************************************************
2094 * XFONT_MatchDeviceFont
2096 * Scan font resource tree.
2098 static BOOL32 XFONT_MatchDeviceFont( fontResource* start, fontMatch* pfm )
2100 fontResource** ppfr;
2101 fontMatch fm = *pfm;
2103 pfm->pfi = NULL;
2104 if( fm.plf->lfFaceName[0] )
2106 fontAlias* fa;
2107 LPSTR str = NULL;
2109 for( fa = aliasTable; fa; fa = fa->next )
2110 if( !strcmp( fa->faAlias, fm.plf->lfFaceName ) )
2112 str = fa->faTypeFace;
2113 break;
2115 fm.pfr = XFONT_FindFIList( start, str ? str : fm.plf->lfFaceName );
2118 if( fm.pfr ) /* match family */
2120 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2122 if( fm.pfr->fr_flags & FR_REMOVED )
2123 fm.pfr = 0;
2124 else
2126 XFONT_MatchFIList( &fm );
2127 *pfm = fm;
2131 if( !pfm->pfi ) /* match all available fonts */
2133 UINT32 current_score, score = (UINT32)(-1);
2135 fm.flags |= FO_MATCH_PAF;
2136 for( ppfr = &fontList; *ppfr && score; ppfr = &(*ppfr)->next )
2138 if( (*ppfr)->fr_flags & FR_REMOVED )
2140 if( (*ppfr)->fo_count == 0 )
2141 XFONT_RemoveFontResource( ppfr );
2142 continue;
2145 fm.pfr = *ppfr;
2147 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2149 current_score = XFONT_MatchFIList( &fm );
2150 if( current_score < score )
2152 score = current_score;
2153 *pfm = fm;
2157 return TRUE;
2161 /***********************************************************************
2162 * X Font Cache
2164 static void XFONT_GrowFreeList(int start, int end)
2166 /* add all entries from 'start' up to and including 'end' */
2168 memset( fontCache + start, 0, (end - start + 1) * sizeof(fontObject) );
2170 fontCache[end].lru = fontLF;
2171 fontCache[end].count = -1;
2172 fontLF = start;
2173 while( start < end )
2175 fontCache[start].count = -1;
2176 fontCache[start].lru = start + 1;
2177 start++;
2181 static fontObject* XFONT_LookupCachedFont( LPLOGFONT16 plf, UINT16* checksum )
2183 UINT16 cs = __lfCheckSum( plf );
2184 int i = fontMRU, prev = -1;
2186 *checksum = cs;
2187 while( i >= 0 )
2189 if( fontCache[i].lfchecksum == cs &&
2190 !(fontCache[i].fo_flags & FO_REMOVED) )
2192 /* FIXME: something more intelligent here */
2194 if( !memcmp( plf, &fontCache[i].lf,
2195 sizeof(LOGFONT16) - LF_FACESIZE ) &&
2196 !strncasecmp( plf->lfFaceName, fontCache[i].lf.lfFaceName,
2197 LF_FACESIZE ) )
2199 /* remove temporarily from the lru list */
2201 if( prev >= 0 )
2202 fontCache[prev].lru = fontCache[i].lru;
2203 else
2204 fontMRU = (INT16)fontCache[i].lru;
2205 return (fontCache + i);
2208 prev = i;
2209 i = (INT16)fontCache[i].lru;
2211 return NULL;
2214 static fontObject* XFONT_GetCacheEntry()
2216 int i;
2218 if( fontLF == -1 )
2220 int prev_i, prev_j, j;
2222 TRACE(font,"font cache is full\n");
2224 /* lookup the least recently used font */
2226 for( prev_i = prev_j = j = -1, i = fontMRU; i >= 0; i = (INT16)fontCache[i].lru )
2228 if( fontCache[i].count <= 0 &&
2229 !(fontCache[i].fo_flags & FO_SYSTEM) )
2231 prev_j = prev_i;
2232 j = i;
2234 prev_i = i;
2237 if( j >= 0 ) /* unload font */
2239 /* detach from the lru list */
2241 TRACE(font,"\tfreeing entry %i\n", j );
2243 fontCache[j].fr->fo_count--;
2245 if( prev_j >= 0 )
2246 fontCache[prev_j].lru = fontCache[j].lru;
2247 else fontMRU = (INT16)fontCache[j].lru;
2249 /* FIXME: lpXForm, lpPixmap */
2250 if(fontCache[j].lpX11Trans)
2251 HeapFree( SystemHeap, 0, fontCache[j].lpX11Trans );
2253 TSXFreeFont( display, fontCache[j].fs );
2255 memset( fontCache + j, 0, sizeof(fontObject) );
2256 return (fontCache + j);
2258 else /* expand cache */
2260 fontObject* newCache;
2262 prev_i = fontCacheSize + FONTCACHE;
2264 TRACE(font,"\tgrowing font cache from %i to %i\n", fontCacheSize, prev_i );
2266 if( (newCache = (fontObject*)HeapReAlloc(SystemHeap, 0,
2267 fontCache, prev_i)) )
2269 i = fontCacheSize;
2270 fontCacheSize = prev_i;
2271 fontCache = newCache;
2272 XFONT_GrowFreeList( i, fontCacheSize - 1);
2274 else return NULL;
2278 /* detach from the free list */
2280 i = fontLF;
2281 fontLF = (INT16)fontCache[i].lru;
2282 fontCache[i].count = 0;
2283 return (fontCache + i);
2286 static int XFONT_ReleaseCacheEntry(fontObject* pfo)
2288 UINT32 u = (UINT32)(pfo - fontCache);
2290 if( u < fontCacheSize ) return (--fontCache[u].count);
2291 return -1;
2294 /**********************************************************************
2295 * XFONT_SetX11Trans
2297 static BOOL32 XFONT_SetX11Trans( fontObject *pfo )
2299 char *fontName;
2300 Atom nameAtom;
2301 char *cp, *start;
2303 TSXGetFontProperty( pfo->fs, XA_FONT, &nameAtom );
2304 fontName = TSXGetAtomName( display, nameAtom );
2305 cp = LFD_Advance( fontName, 7 );
2306 if(*cp != '[') {
2307 TSXFree(fontName);
2308 return FALSE;
2310 start = cp;
2311 while((cp = strchr(cp, '~')))
2312 *cp = '-';
2314 #define PX pfo->lpX11Trans
2316 sscanf(start, "[%f%f%f%f]", &PX->a, &PX->b, &PX->c, &PX->d);
2317 TSXFree(fontName);
2319 TSXGetFontProperty( pfo->fs, RAW_ASCENT, &PX->RAW_ASCENT );
2320 TSXGetFontProperty( pfo->fs, RAW_DESCENT, &PX->RAW_DESCENT );
2322 PX->pixelsize = hypot(PX->a, PX->b);
2323 PX->ascent = PX->pixelsize / 1000.0 * PX->RAW_ASCENT;
2324 PX->descent = PX->pixelsize / 1000.0 * PX->RAW_DESCENT;
2326 TRACE(font, "[%f %f %f %f] RA = %ld RD = %ld\n", pfo->lpX11Trans->a,
2327 pfo->lpX11Trans->b, pfo->lpX11Trans->c, pfo->lpX11Trans->d,
2328 pfo->lpX11Trans->RAW_ASCENT, pfo->lpX11Trans->RAW_DESCENT);
2330 #undef PX
2331 return TRUE;
2334 /***********************************************************************
2335 * X Device Font Objects
2337 static X_PHYSFONT XFONT_RealizeFont( LPLOGFONT16 plf )
2339 UINT16 checksum;
2340 fontObject* pfo = XFONT_LookupCachedFont( plf, &checksum );
2342 if( !pfo )
2344 fontMatch fm = { NULL, NULL, 0, 0, plf};
2345 INT32 i, index;
2347 if( XTextCaps & TC_SF_X_YINDEP ) fm.flags = FO_MATCH_XYINDEP;
2349 /* allocate new font cache entry */
2351 if( (pfo = XFONT_GetCacheEntry()) )
2353 LPSTR lpLFD = HeapAlloc( GetProcessHeap(), 0, MAX_LFD_LENGTH );
2355 if( lpLFD ) /* initialize entry and load font */
2357 UINT32 uRelaxLevel = 0;
2359 TRACE(font,"(%u) '%s' h=%i weight=%i %s\n",
2360 plf->lfCharSet, plf->lfFaceName, plf->lfHeight,
2361 plf->lfWeight, (plf->lfItalic) ? "Italic" : "" );
2363 if(abs(plf->lfHeight) > MAX_FONT_SIZE) {
2364 ERR(font,
2365 "plf->lfHeight = %d, this is probably not right. Setting to 100\n",
2366 plf->lfHeight);
2367 plf->lfHeight = 100;
2370 XFONT_MatchDeviceFont( fontList, &fm );
2372 pfo->fr = fm.pfr;
2373 pfo->fi = fm.pfi;
2374 pfo->fr->fo_count++;
2375 pfo->fo_flags = fm.flags & ~FO_MATCH_MASK;
2377 memcpy( &pfo->lf, plf, sizeof(LOGFONT16) );
2378 pfo->lfchecksum = checksum;
2382 LFD_ComposeLFD( pfo, fm.height, lpLFD, uRelaxLevel++ );
2383 if( (pfo->fs = TSXLoadQueryFont( display, lpLFD )) ) break;
2384 } while( uRelaxLevel );
2387 if(pfo->lf.lfEscapement != 0) {
2388 pfo->lpX11Trans = HeapAlloc(SystemHeap, 0,
2389 sizeof(XFONTTRANS));
2390 if(!XFONT_SetX11Trans( pfo )) {
2391 HeapFree(SystemHeap, 0, pfo->lpX11Trans);
2392 pfo->lpX11Trans = NULL;
2396 if( XFONT_GetLeading( &pfo->fi->df, pfo->fs, &i, NULL,
2397 pfo->lpX11Trans ) )
2399 if(!pfo->lpX11Trans)
2400 pfo->foAvgCharWidth =
2401 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].width;
2402 else
2403 pfo->foAvgCharWidth =
2404 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].attributes
2405 * pfo->lpX11Trans->pixelsize / 1000.0;
2406 else
2407 pfo->foAvgCharWidth = (INT16)XFONT_GetAvgCharWidth(
2408 &pfo->fi->df, pfo->fs, pfo->lpX11Trans );
2409 pfo->foMaxCharWidth = (INT16)XFONT_GetMaxCharWidth(pfo);
2410 pfo->foInternalLeading = (INT16)i;
2412 /* FIXME: If we've got a soft font or
2413 * there are FO_SYNTH_... flags for the
2414 * non PROOF_QUALITY request, the engine
2415 * should rasterize characters into mono
2416 * pixmaps and store them in the pfo->lpPixmap
2417 * array (pfo->fs should be updated as well).
2418 * array (pfo->fs should be updated as well).
2419 * X11DRV_ExtTextOut() must be heavily modified
2420 * to support pixmap blitting and FO_SYNTH_...
2421 * styles.
2424 pfo->lpPixmap = NULL;
2426 HeapFree( GetProcessHeap(), 0, lpLFD );
2428 else /* attach back to the free list */
2430 pfo->count = -1;
2431 pfo->lru = fontLF;
2432 fontLF = (pfo - fontCache);
2433 pfo = NULL;
2437 if( !pfo ) /* couldn't get a new entry, get one of the cached fonts */
2439 UINT32 current_score, score = (UINT32)(-1);
2441 i = index = fontMRU;
2442 fm.flags |= FO_MATCH_PAF;
2445 pfo = fontCache + i;
2446 fm.pfr = pfo->fr; fm.pfi = pfo->fi;
2448 current_score = XFONT_Match( &fm );
2449 if( current_score < score ) index = i;
2451 i = pfo->lru;
2452 } while( i >= 0 );
2453 pfo = fontCache + index;
2454 pfo->count++;
2455 return (X_PHYSFONT)(X_PFONT_MAGIC | index);
2459 /* attach at the head of the lru list */
2461 pfo->count++;
2462 pfo->lru = fontMRU;
2463 fontMRU = (pfo - fontCache);
2465 TRACE(font,"physfont %i\n", fontMRU);
2467 return (X_PHYSFONT)(X_PFONT_MAGIC | fontMRU);
2470 /***********************************************************************
2471 * XFONT_GetFontObject
2473 fontObject* XFONT_GetFontObject( X_PHYSFONT pFont )
2475 if( CHECK_PFONT(pFont) ) return __PFONT(pFont);
2476 return NULL;
2479 /***********************************************************************
2480 * XFONT_GetFontStruct
2482 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
2484 if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
2485 return NULL;
2488 /***********************************************************************
2489 * XFONT_GetFontInfo
2491 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
2493 if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
2494 return NULL;
2499 /* X11DRV Interface ****************************************************
2501 * Exposed via the dc->funcs dispatch table. *
2503 ***********************************************************************/
2504 /***********************************************************************
2505 * X11DRV_FONT_SelectObject
2507 HFONT32 X11DRV_FONT_SelectObject( DC* dc, HFONT32 hfont, FONTOBJ* font )
2509 HFONT32 hPrevFont = 0;
2510 LOGFONT16 lf;
2511 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2513 EnterCriticalSection( &crtsc_fonts_X11 );
2515 if( CHECK_PFONT(physDev->font) )
2516 XFONT_ReleaseCacheEntry( __PFONT(physDev->font) );
2518 /* FIXME: do we need to pass anything back from here? */
2519 memcpy(&lf,&font->logfont,sizeof(lf));
2520 lf.lfWidth = font->logfont.lfWidth * dc->vportExtX/dc->wndExtX;
2521 lf.lfHeight = font->logfont.lfHeight* dc->vportExtY/dc->wndExtY;
2523 physDev->font = XFONT_RealizeFont( &lf );
2524 hPrevFont = dc->w.hFont;
2525 dc->w.hFont = hfont;
2527 LeaveCriticalSection( &crtsc_fonts_X11 );
2529 return hPrevFont;
2533 /***********************************************************************
2535 * X11DRV_EnumDeviceFonts
2537 BOOL32 X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf,
2538 DEVICEFONTENUMPROC proc, LPARAM lp )
2540 ENUMLOGFONTEX16 lf;
2541 NEWTEXTMETRIC16 tm;
2542 fontResource* pfr = fontList;
2543 BOOL32 b, bRet = 0;
2545 if( plf->lfFaceName[0] )
2547 /* enum all entries in this resource */
2548 pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
2549 if( pfr )
2551 fontInfo* pfi;
2552 for( pfi = pfr->fi; pfi; pfi = pfi->next )
2554 /* Note: XFONT_GetFontMetric() will have to
2555 release the crit section, font list will
2556 have to be retraversed on return */
2558 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2559 XFONT_GetFontMetric( pfi, &lf, &tm ), lp )) )
2560 bRet = b;
2561 else break;
2565 else /* enum first entry in each resource */
2566 for( ; pfr ; pfr = pfr->next )
2568 if(pfr->fi)
2570 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2571 XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
2572 bRet = b;
2573 else break;
2576 return bRet;
2580 /***********************************************************************
2581 * X11DRV_GetTextExtentPoint
2583 BOOL32 X11DRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT32 count,
2584 LPSIZE32 size )
2586 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2587 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2588 if( pfo ) {
2589 if( !pfo->lpX11Trans ) {
2590 int dir, ascent, descent;
2591 XCharStruct info;
2593 TSXTextExtents( pfo->fs, str, count, &dir, &ascent, &descent, &info );
2594 size->cx = abs((info.width + dc->w.breakRem + count *
2595 dc->w.charExtra) * dc->wndExtX / dc->vportExtX);
2596 size->cy = abs((pfo->fs->ascent + pfo->fs->descent) *
2597 dc->wndExtY / dc->vportExtY);
2598 } else {
2600 INT32 i;
2601 float x = 0.0, y = 0.0;
2602 for(i = 0; i < count; i++) {
2603 x += pfo->fs->per_char ?
2604 pfo->fs->per_char[str[i] - pfo->fs->min_char_or_byte2].attributes :
2605 pfo->fs->min_bounds.attributes;
2607 y = pfo->lpX11Trans->RAW_ASCENT + pfo->lpX11Trans->RAW_DESCENT;
2608 TRACE(font, "x = %f y = %f\n", x, y);
2609 x *= pfo->lpX11Trans->pixelsize / 1000.0;
2610 y *= pfo->lpX11Trans->pixelsize / 1000.0;
2611 size->cx = fabsf((x + dc->w.breakRem + count * dc->w.charExtra) *
2612 dc->wndExtX / dc->vportExtX);
2613 size->cy = fabsf(y * dc->wndExtY / dc->vportExtY);
2615 return TRUE;
2617 return FALSE;
2621 /***********************************************************************
2622 * X11DRV_GetTextMetrics
2624 BOOL32 X11DRV_GetTextMetrics(DC *dc, TEXTMETRIC32A *metrics)
2626 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2628 if( CHECK_PFONT(physDev->font) )
2630 fontObject* pfo = __PFONT(physDev->font);
2631 XFONT_GetTextMetric( pfo, metrics );
2633 return TRUE;
2635 return FALSE;
2639 /***********************************************************************
2640 * X11DRV_GetCharWidth
2642 BOOL32 X11DRV_GetCharWidth( DC *dc, UINT32 firstChar, UINT32 lastChar,
2643 LPINT32 buffer )
2645 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2646 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2648 if( pfo )
2650 int i;
2652 if (pfo->fs->per_char == NULL)
2653 for (i = firstChar; i <= lastChar; i++)
2654 if(pfo->lpX11Trans)
2655 *buffer++ = pfo->fs->min_bounds.attributes *
2656 pfo->lpX11Trans->pixelsize / 1000.0;
2657 else
2658 *buffer++ = pfo->fs->min_bounds.width;
2659 else
2661 XCharStruct *cs, *def;
2662 static XCharStruct __null_char = { 0, 0, 0, 0, 0, 0 };
2664 CI_GET_CHAR_INFO(pfo->fs, pfo->fs->default_char, &__null_char,
2665 def);
2667 for (i = firstChar; i <= lastChar; i++)
2669 if (i >= pfo->fs->min_char_or_byte2 &&
2670 i <= pfo->fs->max_char_or_byte2)
2672 cs = &pfo->fs->per_char[(i - pfo->fs->min_char_or_byte2)];
2673 if (CI_NONEXISTCHAR(cs)) cs = def;
2674 } else cs = def;
2675 if(pfo->lpX11Trans)
2676 *buffer++ = MAX(cs->attributes, 0) *
2677 pfo->lpX11Trans->pixelsize / 1000.0;
2678 else
2679 *buffer++ = MAX(cs->width, 0 );
2683 return TRUE;
2685 return FALSE;
2688 /***********************************************************************
2690 * Font Resource API *
2692 ***********************************************************************/
2693 /***********************************************************************
2694 * AddFontResource16 (GDI.119)
2696 * Can be either .FON, or .FNT, or .TTF, or .FOT font file.
2698 * FIXME: Load header and find the best-matching font in the fontList;
2699 * fixup dfPoints if all metrics are identical, otherwise create
2700 * new fontAlias. When soft font support is ready this will
2701 * simply create a new fontResource ('filename' will go into
2702 * the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE
2703 * flag set.
2705 INT16 WINAPI AddFontResource16( LPCSTR filename )
2707 return AddFontResource32A( filename );
2711 /***********************************************************************
2712 * AddFontResource32A (GDI32.2)
2714 INT32 WINAPI AddFontResource32A( LPCSTR str )
2716 FIXME(font, "(%s): stub\n", debugres_a(str));
2717 return 1;
2721 /***********************************************************************
2722 * AddFontResource32W (GDI32.4)
2724 INT32 WINAPI AddFontResource32W( LPCWSTR str )
2726 FIXME(font, "(%s): stub\n", debugres_w(str) );
2727 return 1;
2730 /***********************************************************************
2731 * RemoveFontResource16 (GDI.136)
2733 BOOL16 WINAPI RemoveFontResource16( SEGPTR str )
2735 FIXME(font, "(%s): stub\n", debugres_a(PTR_SEG_TO_LIN(str)));
2736 return TRUE;
2740 /***********************************************************************
2741 * RemoveFontResource32A (GDI32.284)
2743 BOOL32 WINAPI RemoveFontResource32A( LPCSTR str )
2745 /* This is how it should look like */
2747 fontResource** ppfr;
2748 BOOL32 retVal = FALSE;
2750 EnterCriticalSection( &crtsc_fonts_X11 );
2751 for( ppfr = &fontList; *ppfr; ppfr = &(*ppfr)->next )
2752 if( !strcasecmp( (*ppfr)->lfFaceName, str ) )
2754 if(((*ppfr)->fr_flags & (FR_SOFTFONT | FR_SOFTRESOURCE)) &&
2755 (*ppfr)->hOwnerProcess == GetCurrentProcess() )
2757 if( (*ppfr)->fo_count )
2758 (*ppfr)->fr_flags |= FR_REMOVED;
2759 else
2760 XFONT_RemoveFontResource( ppfr );
2762 retVal = TRUE;
2764 LeaveCriticalSection( &crtsc_fontList );
2765 return retVal;
2767 FIXME(font, "(%s): stub\n", debugres_a(str));
2768 return TRUE;
2772 /***********************************************************************
2773 * RemoveFontResource32W (GDI32.286)
2775 BOOL32 WINAPI RemoveFontResource32W( LPCWSTR str )
2777 FIXME(font, "(%s): stub\n", debugres_w(str) );
2778 return TRUE;