Large-scale renaming of all Win32 functions and types to use the
[wine.git] / graphics / x11drv / xfont.c
blob5c4de2fd297c001af4da4483cd9afef8f5656f36
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 "config.h"
12 #ifndef X_DISPLAY_MISSING
13 #include <X11/Xatom.h>
14 #include "ts_xlib.h"
15 #include "x11font.h"
16 #endif /* !defined(X_DISPLAY_MISSING) */
18 #include <ctype.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <pwd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <math.h>
28 #include <assert.h>
29 #include "heap.h"
30 #include "options.h"
31 #include "font.h"
32 #include "debug.h"
33 #include "ldt.h"
35 #ifndef X_DISPLAY_MISSING
37 #define X_PFONT_MAGIC (0xFADE0000)
38 #define X_FMC_MAGIC (0x0000CAFE)
40 #define MAX_FONT_FAMILIES 128
41 #define MAX_LFD_LENGTH 256
43 #define MAX_FONT_SIZE 1000 /* Max size in pixels */
45 #define REMOVE_SUBSETS 1
46 #define UNMARK_SUBSETS 0
48 #define DEF_SCALABLE_HEIGHT 24
49 #define DEF_SCALABLE_DP 240
51 #define FF_FAMILY (FF_MODERN | FF_SWISS | FF_ROMAN | FF_DECORATIVE | FF_SCRIPT)
53 typedef struct __fontAlias
55 LPSTR faTypeFace;
56 LPSTR faAlias;
57 struct __fontAlias* next;
58 } fontAlias;
60 typedef struct
62 LPSTR fatResource;
63 LPSTR fatAlias;
64 } aliasTemplate;
66 /* Font alias table - these 2 aliases are always present */
67 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
69 static fontAlias __aliasTable[2] = {
70 { NULL, "Helv", &__aliasTable[1] },
71 { NULL, "Tms Rmn", NULL }
74 static fontAlias *aliasTable = __aliasTable;
76 /* Optional built-in aliases, they are installed only when X
77 * cannot supply us with original MS fonts */
78 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
80 static int faTemplateNum = 4;
81 static aliasTemplate faTemplate[4] = {
82 { NULL, "MS Sans Serif" },
83 { NULL, "MS Serif" },
84 { "-adobe-times-", "Times New Roman" },
85 { "-adobe-helvetica-", "Arial" }
88 UINT16 XTextCaps = TC_OP_CHARACTER | TC_OP_STROKE |
89 TC_CP_STROKE | TC_CR_ANY |
90 TC_SA_DOUBLE | TC_SA_INTEGER | TC_SA_CONTIN |
91 TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
93 /* X11R6 adds TC_SF_X_YINDEP, maybe more... */
95 static const char* INIWinePrefix = "/.wine";
96 static const char* INIFontMetrics = "/.cachedmetrics.";
97 static const char* INIFontSection = "fonts";
98 static const char* INIAliasSection = "Alias";
99 static const char* INIIgnoreSection = "Ignore";
100 static const char* INIDefault = "Default";
101 static const char* INIDefaultFixed = "DefaultFixed";
102 static const char* INIResolution = "Resolution";
103 static const char* INIGlobalMetrics = "FontMetrics";
104 static const char* INIDefaultSerif = "DefaultSerif";
105 static const char* INIDefaultSansSerif = "DefaultSansSerif";
107 static const char* LFDSeparator = "*-";
109 /* suffix tables, must be less than 254 entries long */
111 static LPSTR suffx_iso[] = { "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8",
112 "-9", "-10", "-11", "-12", "-13", "-14", "-15", NULL };
113 static LPSTR suffx_iso646[] = { "-irv", NULL };
114 static LPSTR suffx_microsoft[] = { "-cp1252", "-cp1251", "-cp1250", "-cp1253", "-cp1254", "-cp1255",
115 "-cp1256", "-cp1257", "-fontspecific", "-symbol", NULL };
116 static LPSTR suffx_viscii[] = { "-1", NULL };
117 static LPSTR suffx_ansi[] = { "-0", NULL };
118 static LPSTR suffx_koi8[] = { "-ru", "-r", NULL };
119 static LPSTR suffx_null[] = { NULL };
121 /* charset mapping tables, have to have the same number of entries as corresponding suffix tables */
123 static BYTE chset_iso8859[] = { ANSI_CHARSET, EE_CHARSET, ISO3_CHARSET, ISO4_CHARSET, RUSSIAN_CHARSET,
124 ARABIC_CHARSET, GREEK_CHARSET, HEBREW_CHARSET, TURKISH_CHARSET, BALTIC_CHARSET,
125 THAI_CHARSET, SYMBOL_CHARSET, SYMBOL_CHARSET, SYMBOL_CHARSET, ANSI_CHARSET,
126 SYMBOL_CHARSET };
127 static BYTE chset_iso646[] = { ANSI_CHARSET, SYMBOL_CHARSET };
128 static BYTE chset_microsoft[] = { ANSI_CHARSET, RUSSIAN_CHARSET, EE_CHARSET, GREEK_CHARSET, TURKISH_CHARSET,
129 HEBREW_CHARSET, ARABIC_CHARSET, BALTIC_CHARSET, SYMBOL_CHARSET, SYMBOL_CHARSET,
130 SYMBOL_CHARSET };
131 static BYTE chset_ansi[] = { ANSI_CHARSET, ANSI_CHARSET };
132 static BYTE chset_koi8[] = { KOI8_CHARSET, KOI8_CHARSET, KOI8_CHARSET };
133 static BYTE chset_tcvn[] = { TCVN_CHARSET, TCVN_CHARSET };
134 static BYTE chset_tis620[] = { THAI_CHARSET, THAI_CHARSET };
135 static BYTE chset_fontspecific[] = { SYMBOL_CHARSET };
136 static BYTE chset_viscii[] = { VISCII_CHARSET, VISCII_CHARSET };
138 typedef struct __fet
140 LPSTR prefix;
141 LPSTR (*psuffix)[];
142 BYTE (*pcharset)[];
143 struct __fet* next;
144 } fontEncodingTemplate;
146 /* Note: we can attach additional encoding mappings to the end
147 * of this table at runtime.
150 static fontEncodingTemplate __fETTable[10] = {
151 { "iso8859", &suffx_iso, &chset_iso8859, &__fETTable[1] },
152 { "iso646.1991", &suffx_iso646, &chset_iso646, &__fETTable[2] },
153 { "microsoft", &suffx_microsoft, &chset_microsoft, &__fETTable[3] },
154 { "ansi", &suffx_ansi, &chset_ansi, &__fETTable[4] },
155 { "ascii", &suffx_ansi, &chset_ansi, &__fETTable[5] },
156 { "fontspecific", &suffx_null, &chset_fontspecific, &__fETTable[6] },
157 { "koi8", &suffx_koi8, &chset_koi8, &__fETTable[7] },
158 { "tcvn", &suffx_ansi, &chset_tcvn, &__fETTable[8] },
159 { "tis620.2533", &suffx_ansi, &chset_tis620, &__fETTable[9] },
160 { "viscii1.1", &suffx_viscii, &chset_viscii, NULL }
162 static fontEncodingTemplate* fETTable = __fETTable;
164 static unsigned DefResolution = 0;
166 static CRITICAL_SECTION crtsc_fonts_X11;
168 static fontResource* fontList = NULL;
169 static fontObject* fontCache = NULL; /* array */
170 static int fontCacheSize = FONTCACHE;
171 static int fontLF = -1, fontMRU = -1; /* last free, most recently used */
173 #define __PFONT(pFont) ( fontCache + ((UINT)(pFont) & 0x0000FFFF) )
174 #define CHECK_PFONT(pFont) ( (((UINT)(pFont) & 0xFFFF0000) == X_PFONT_MAGIC) &&\
175 (((UINT)(pFont) & 0x0000FFFF) < fontCacheSize) )
177 static INT XFONT_IsSubset(fontInfo*, fontInfo*);
178 static void XFONT_CheckFIList(fontResource*, fontInfo*, int subset_action);
179 static void XFONT_GrowFreeList(int start, int end);
180 static void XFONT_RemoveFontResource(fontResource** ppfr);
183 static Atom RAW_ASCENT;
184 static Atom RAW_DESCENT;
186 /***********************************************************************
187 * Helper macros from X distribution
190 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
191 (((cs)->rbearing|(cs)->lbearing| \
192 (cs)->ascent|(cs)->descent) == 0))
194 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
196 cs = def; \
197 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
198 if (fs->per_char == NULL) { \
199 cs = &fs->min_bounds; \
200 } else { \
201 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
202 if (CI_NONEXISTCHAR(cs)) cs = def; \
207 #define CI_GET_DEFAULT_INFO(fs,cs) \
208 CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
210 /***********************************************************************
211 * Checksums
213 static UINT16 __lfCheckSum( LPLOGFONT16 plf )
215 CHAR font[LF_FACESIZE];
216 UINT16 checksum = 0;
217 UINT16 i;
219 #define ptr ((UINT16*)plf)
220 for( i = 0; i < 9; i++ ) checksum ^= *ptr++;
221 #undef ptr
222 i = 0;
223 #define ptr ((CHAR*)plf)
224 do { font[i++] = tolower(*ptr++); } while (( i < LF_FACESIZE) && (*ptr) && (*ptr!=' '));
225 for( ptr = font, i >>= 1; i > 0; i-- )
226 #undef ptr
227 #define ptr ((UINT16*)plf)
228 checksum ^= *ptr++;
229 #undef ptr
230 return checksum;
233 static UINT16 __genericCheckSum( const void *ptr, int size )
235 unsigned int checksum = 0;
236 const char *p = (const char *)ptr;
237 while (size-- > 0)
238 checksum ^= (checksum << 3) + (checksum >> 29) + *p++;
240 return checksum & 0xffff;
243 /*************************************************************************
244 * LFD parse/compose routines
246 static char* LFD_Advance(LPSTR lpFont, UINT16 uParmsNo)
248 int j = 0;
249 char* lpch = lpFont;
251 for( ; j < uParmsNo && *lpch; lpch++ ) if( *lpch == LFDSeparator[1] ) j++;
252 return lpch;
255 static void LFD_GetWeight( fontInfo* fi, LPSTR lpStr, int j)
257 if( j == 1 && *lpStr == '0' )
258 fi->fi_flags |= FI_POLYWEIGHT;
259 else if( j == 4 )
261 if( !strncasecmp( "bold", lpStr, 4) )
262 fi->df.dfWeight = FW_BOLD;
263 else if( !strncasecmp( "demi", lpStr, 4) )
265 fi->fi_flags |= FI_FW_DEMI;
266 fi->df.dfWeight = FW_DEMIBOLD;
268 else if( !strncasecmp( "book", lpStr, 4) )
270 fi->fi_flags |= FI_FW_BOOK;
271 fi->df.dfWeight = FW_REGULAR;
274 else if( j == 5 )
276 if( !strncasecmp( "light", lpStr, 5) )
277 fi->df.dfWeight = FW_LIGHT;
278 else if( !strncasecmp( "black", lpStr, 5) )
279 fi->df.dfWeight = FW_BLACK;
281 else if( j == 6 && !strncasecmp( "medium", lpStr, 6) )
282 fi->df.dfWeight = FW_REGULAR;
283 else if( j == 8 && !strncasecmp( "demibold", lpStr, 8) )
284 fi->df.dfWeight = FW_DEMIBOLD;
285 else
286 fi->df.dfWeight = FW_DONTCARE; /* FIXME: try to get something
287 * from the weight property */
290 static int LFD_GetSlant( fontInfo* fi, LPSTR lpStr, int l)
292 if( l == 1 )
294 switch( tolower( *lpStr ) )
296 case '0': fi->fi_flags |= FI_POLYSLANT; /* haven't seen this one yet */
297 default:
298 case 'r': fi->df.dfItalic = 0;
299 break;
300 case 'o':
301 fi->fi_flags |= FI_OBLIQUE;
302 case 'i': fi->df.dfItalic = 1;
303 break;
305 return 0;
307 return 1;
310 /*************************************************************************
311 * LFD_InitFontInfo
313 * INIT ONLY
315 * Fill in some fields in the fontInfo struct.
317 static int LFD_InitFontInfo( fontInfo* fi, LPSTR lpstr )
319 LPSTR lpch;
320 int i, j, dec_style_check, scalability;
321 UINT16 tmp[3];
322 fontEncodingTemplate* boba;
324 memset(fi, 0, sizeof(fontInfo) );
326 /* weight name - */
327 lpch = LFD_Advance( lpstr, 1);
328 if( !*lpch ) return FALSE;
329 j = lpch - lpstr - 1;
330 LFD_GetWeight( fi, lpstr, j );
332 /* slant - */
333 lpch = LFD_Advance( lpstr = lpch, 1);
334 if( !*lpch ) return FALSE;
335 j = lpch - lpstr - 1;
336 dec_style_check = LFD_GetSlant( fi, lpstr, j );
338 /* width name - */
339 lpch = LFD_Advance( lpstr = lpch, 1);
340 if( !*lpch ) return FALSE;
341 if( strncasecmp( "normal", lpstr, 6) ) /* XXX 'narrow', 'condensed', etc... */
342 dec_style_check = TRUE;
343 else
344 fi->fi_flags |= FI_NORMAL;
346 /* style - */
347 lpch = LFD_Advance( lpstr = lpch, 1);
348 if( !*lpch ) return FALSE;
349 j = lpch - lpstr - 1;
350 if( j > 3 ) /* find out is there "sans" or "script" */
352 j = 0;
353 *(lpch - 1) = '\0';
355 if( strstr(lpstr, "sans") )
357 fi->df.dfPitchAndFamily |= FF_SWISS;
358 j = 1;
360 if( strstr(lpstr, "script") )
362 fi->df.dfPitchAndFamily |= FF_SCRIPT;
363 j = 1;
365 if( !j && dec_style_check )
366 fi->df.dfPitchAndFamily |= FF_DECORATIVE;
367 *(lpch - 1) = LFDSeparator[1];
370 /* pixel height, decipoint height, and res_x */
372 for( i = scalability = 0; i < 3; i++ )
374 lpch = LFD_Advance( lpstr = lpch, 1);
375 if( !*lpch ) return FALSE;
376 if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
378 *(lpch - 1) = '\0';
379 if( !(tmp[i] = atoi(lpstr)) ) scalability++;
380 *(lpch - 1) = LFDSeparator[1];
382 if( scalability == 3 ) /* Type1 */
384 fi->fi_flags |= FI_SCALABLE;
385 fi->lfd_height = DEF_SCALABLE_HEIGHT; fi->lfd_decipoints = DEF_SCALABLE_DP;
386 fi->lfd_resolution = DefResolution;
388 else if( scalability == 0 ) /* Bitmap */
390 fi->lfd_height = tmp[0]; fi->lfd_decipoints = tmp[1];
391 fi->lfd_resolution = tmp[2];
393 else return FALSE; /* #$%^!!! X11R6 mutant garbage */
395 /* res_y - skip, spacing - */
396 lpstr = LFD_Advance( lpch, 1);
397 switch( *lpstr )
399 case '\0': return FALSE;
401 case 'p': fi->fi_flags |= FI_VARIABLEPITCH;
402 break;
403 case 'c': fi->df.dfPitchAndFamily |= FF_MODERN;
404 fi->fi_flags |= FI_FIXEDEX;
405 /* fall through */
406 case 'm': fi->fi_flags |= FI_FIXEDPITCH;
407 break;
408 default:
409 fi->df.dfPitchAndFamily |= DEFAULT_PITCH | FF_DONTCARE;
411 lpstr = LFD_Advance(lpstr, 1);
412 if( !*lpstr ) return FALSE;
414 /* average width - */
415 lpch = LFD_Advance( lpstr, 1);
416 if( !*lpch ) return FALSE;
417 if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
418 *(lpch - 1) = '\0';
419 if( !(fi->lfd_width = atoi(lpstr)) && !scalability ) return FALSE;
420 *(lpch - 1) = LFDSeparator[1];
422 /* charset registry, charset encoding - */
423 if( strstr(lpch, "jisx") ||
424 strstr(lpch, "ksc") ||
425 strstr(lpch, "gb2312") ||
426 strstr(lpch, "big5") ||
427 strstr(lpch, "unicode") ) return FALSE; /* 2-byte stuff */
429 fi->df.dfCharSet = ANSI_CHARSET;
431 for( i = 0, boba = fETTable; boba; boba = boba->next, i++ )
433 tmp[0] = strlen( boba->prefix );
434 if( !strncasecmp( lpch, boba->prefix, tmp[0] ) )
436 if( lpch[tmp[0]] == '-' )
438 lpstr = lpch + tmp[0];
439 for( j = 0; (*(boba->psuffix))[j]; j++ )
441 tmp[1] = strlen( (*(boba->psuffix))[j] );
442 if( !strncasecmp( lpstr, (*(boba->psuffix))[j], tmp[1] ) )
444 fi->df.dfCharSet = (*(boba->pcharset))[j];
445 goto done;
448 /* Note : LFD_ComposeLFD will produce 'prefix-*' encoding *
449 * if (*(boba->psuffix))[j] is NULL here */
451 else
453 for( j = 0; (*(boba->psuffix))[j] ; j++ );
454 fi->df.dfCharSet = (*(boba->pcharset))[j];
455 j = lpch[tmp[0]] ? 254 : 255;
459 done:
460 if( !boba ) return FALSE;
462 /* i - index into fETTable
463 * j - index into suffix array for fETTable[i]
464 * except:
465 * 254 - weird suffix (i.e. no '-' right after prefix )
466 * 255 - no suffix at all.
469 fi->fi_encoding = 256 * (UINT16)i + (UINT16)j;
471 return TRUE;
475 /*************************************************************************
476 * LFD_ComposeLFD
478 * Note: uRelax is a treatment not a cure. Font mapping algorithm
479 * should be bulletproof enough to allow us to avoid hacks like
480 * if( uRelax == 200 ) even despite LFD being so braindead.
482 static BOOL LFD_ComposeLFD( fontObject* fo,
483 INT height, LPSTR lpLFD, UINT uRelax )
485 fontEncodingTemplate* boba;
486 int i, h, w, ch, point = 0;
487 char* lpch;
488 char lpEncoding[64];
489 char h_string[64], point_string[64];
491 *(lpLFD+MAX_LFD_LENGTH-1)=0;
492 lstrcpyA( lpLFD, fo->fr->resource );
494 /* add weight */
495 switch( fo->fi->df.dfWeight )
497 case FW_BOLD:
498 strcat( lpLFD, "bold" ); break;
499 case FW_REGULAR:
500 if( fo->fi->fi_flags & FI_FW_BOOK )
501 strcat( lpLFD, "book" );
502 else
503 strcat( lpLFD, "medium" );
504 break;
505 case FW_DEMIBOLD:
506 strcat( lpLFD, "demi" );
507 if( !( fo->fi->fi_flags & FI_FW_DEMI) )
508 strcat ( lpLFD, "bold" );
509 break;
510 case FW_BLACK:
511 strcat( lpLFD, "black" ); break;
512 case FW_LIGHT:
513 strcat( lpLFD, "light" ); break;
514 default:
515 strcat( lpLFD, "*" );
518 /* add slant */
519 if( fo->fi->df.dfItalic )
520 if( fo->fi->fi_flags & FI_OBLIQUE )
521 strcat( lpLFD, "-o" );
522 else
523 strcat( lpLFD, "-i" );
524 else
525 strcat( lpLFD, (uRelax < 2) ? "-r" : "-*" );
527 /* add width style and skip serifs */
528 if( fo->fi->fi_flags & FI_NORMAL )
529 strcat( lpLFD, "-normal-*-");
530 else
531 strcat( lpLFD, "-*-*-" );
533 /* add pixelheight, pointheight, and resolution
535 * FIXME: fill in lpXForm and lpPixmap for rotated fonts
537 if( fo->fo_flags & FO_SYNTH_HEIGHT ) h = fo->fi->lfd_height;
538 else h = (fo->fi->lfd_height * height) / fo->fi->df.dfPixHeight;
540 if( XTextCaps & TC_SF_X_YINDEP )
542 if( fo->lf.lfWidth && !(fo->fo_flags & FO_SYNTH_WIDTH) )
543 point = (fo->fi->lfd_decipoints * fo->lf.lfWidth) / fo->fi->df.dfAvgWidth;
544 else
545 if( fo->fi->fi_flags & FI_SCALABLE ) /* adjust h/w ratio */
546 point = h * 72 * 10 / fo->fi->lfd_resolution;
549 /* handle rotated fonts */
550 if (fo->lf.lfEscapement) {
551 /* escapement is in tenths of degrees, theta is in radians */
552 double theta = M_PI*fo->lf.lfEscapement/1800.;
553 double h_matrix[4] = {h*cos(theta), h*sin(theta), -h*sin(theta), h*cos(theta)};
554 double point_matrix[4] = {point*cos(theta), point*sin(theta), -point*sin(theta), point*cos(theta)};
555 char *s;
556 sprintf(h_string, "[%+f%+f%+f%+f]", h_matrix[0], h_matrix[1], h_matrix[2], h_matrix[3]);
557 sprintf(point_string, "[%+f%+f%+f%+f]", point_matrix[0], point_matrix[1], point_matrix[2], point_matrix[3]);
558 while ((s = strchr(h_string, '-'))) *s='~';
559 while ((s = strchr(point_string, '-'))) *s='~';
560 } else {
561 sprintf(h_string, "%d", h);
562 sprintf(point_string, "%d", point);
566 /* spacing and width */
568 if( fo->fi->fi_flags & FI_FIXEDPITCH )
569 w = ( fo->fi->fi_flags & FI_FIXEDEX ) ? 'c' : 'm';
570 else
571 w = ( fo->fi->fi_flags & FI_VARIABLEPITCH ) ? 'p' : LFDSeparator[0];
573 /* encoding */
575 i = fo->fi->fi_encoding >> 8;
576 for( boba = fETTable; i; i--, boba = boba->next );
578 strcpy( lpEncoding, boba->prefix );
580 i = fo->fi->fi_encoding & 255;
581 switch( i )
583 case 254: strcat( lpEncoding, "*" );
584 break;
585 default:
587 if( (*(boba->psuffix))[i] )
588 strcat( lpEncoding, (*(boba->psuffix))[i] );
589 else
590 strcat( lpEncoding, "-*" );
591 /* fall through */
593 case 255: /* no suffix */
596 lpch = lpLFD + lstrlenA(lpLFD);
597 ch = (fo->fi->fi_flags & FI_SCALABLE) ? '0' : LFDSeparator[0];
599 switch( uRelax )
601 /* RealizeFont() will call us repeatedly with increasing uRelax
602 * until XLoadFont() succeeds. */
604 case 0:
605 if( point )
607 sprintf( lpch, "%s-%s-%i-%c-%c-*-%s", h_string,
608 point_string,
609 fo->fi->lfd_resolution, ch, w, lpEncoding );
610 break;
612 /* fall through */
614 case 1:
615 case 2: /* 2 will have replaced an 'r' in slant by '*' */
616 sprintf( lpch, "%s-*-%i-%c-%c-*-%s", h_string,
617 fo->fi->lfd_resolution, ch, w, lpEncoding );
618 break;
620 case 3:
621 sprintf( lpch, "%s-*-%i-%c-*-*-%s",
622 h_string, fo->fi->lfd_resolution, ch, lpEncoding );
623 break;
625 case 4:
626 sprintf( lpch, "%i-*-%i-%c-*-*-%s", fo->fi->lfd_height,
627 fo->fi->lfd_resolution, ch, lpEncoding );
628 break;
630 case 5:
631 sprintf( lpch, "%i-*-*-*-*-*-%s", fo->fi->lfd_height, lpEncoding );
632 break;
634 default:
635 sprintf( lpch, "%i-*-*-*-*-*-*-*", fo->fi->lfd_height);
636 break;
638 /* to avoid an infinite loop; those will allways match */
639 case 200:
640 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1" );
641 break;
642 case 201:
643 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" );
644 break;
647 TRACE(font,"\tLFD(uRelax=%d): %s\n", uRelax, lpLFD );
648 assert(*(lpLFD+MAX_LFD_LENGTH-1)==0); /* check if overwrittem */
649 return TRUE;
653 /***********************************************************************
654 * X Font Resources
656 * font info - http://www.microsoft.com/kb/articles/q65/1/23.htm
657 * Windows font metrics - http://www.microsoft.com/kb/articles/q32/6/67.htm
659 static BOOL XFONT_GetLeading( LPIFONTINFO16 pFI, XFontStruct* x_fs, INT*
660 pIL, INT* pEL, XFONTTRANS *XFT )
662 unsigned long height;
663 unsigned min = (unsigned char)pFI->dfFirstChar;
664 unsigned max = (unsigned char)pFI->dfLastChar;
665 BOOL bHaveCapHeight = (pFI->dfCharSet == ANSI_CHARSET && 'X' >= min && 'X' <= max );
667 if( pEL ) *pEL = 0;
669 if(XFT) {
670 Atom RAW_CAP_HEIGHT = TSXInternAtom(display, "RAW_CAP_HEIGHT", TRUE);
671 if(TSXGetFontProperty(x_fs, RAW_CAP_HEIGHT, &height))
672 *pIL = XFT->ascent -
673 (INT)(XFT->pixelsize / 1000.0 * height);
674 else
675 *pIL = 0;
676 return bHaveCapHeight && x_fs->per_char;
679 if( TSXGetFontProperty(x_fs, XA_CAP_HEIGHT, &height) == FALSE )
681 if( x_fs->per_char )
682 if( bHaveCapHeight )
683 height = x_fs->per_char['X' - min].ascent;
684 else
685 if (x_fs->ascent >= x_fs->max_bounds.ascent)
686 height = x_fs->max_bounds.ascent;
687 else
689 height = x_fs->ascent;
690 if( pEL )
691 *pEL = x_fs->max_bounds.ascent - height;
693 else
694 height = x_fs->min_bounds.ascent;
697 *pIL = x_fs->ascent - height;
698 return (bHaveCapHeight && x_fs->per_char);
701 static INT XFONT_GetAvgCharWidth( LPIFONTINFO16 pFI, XFontStruct* x_fs,
702 XFONTTRANS *XFT)
704 unsigned min = (unsigned char)pFI->dfFirstChar;
705 unsigned max = (unsigned char)pFI->dfLastChar;
707 if( x_fs->per_char )
709 int width, chars, j;
710 for( j = 0, width = 0, chars = 0, max -= min; j <= max; j++ )
711 if( !CI_NONEXISTCHAR(x_fs->per_char + j) )
713 if(!XFT)
714 width += x_fs->per_char[j].width;
715 else
716 width += x_fs->per_char[j].attributes *
717 XFT->pixelsize / 1000.0;
718 chars++;
720 return (width / chars);
722 /* uniform width */
723 return x_fs->min_bounds.width;
726 static INT XFONT_GetMaxCharWidth(fontObject *pfo)
728 unsigned min = (unsigned char)pfo->fs->min_char_or_byte2;
729 unsigned max = (unsigned char)pfo->fs->max_char_or_byte2;
731 if(!pfo->lpX11Trans)
732 return abs(pfo->fs->max_bounds.width);
734 if( pfo->fs->per_char )
736 int maxwidth, j;
737 for( j = 0, maxwidth = 0, max -= min; j <= max; j++ )
738 if( !CI_NONEXISTCHAR(pfo->fs->per_char + j) )
739 if(maxwidth < pfo->fs->per_char[j].attributes)
740 maxwidth = pfo->fs->per_char[j].attributes;
742 maxwidth *= pfo->lpX11Trans->pixelsize / 1000.0;
743 return maxwidth;
745 return pfo->foAvgCharWidth;
748 /***********************************************************************
749 * XFONT_SetFontMetric
751 * INIT ONLY
753 * Initializes IFONTINFO16. dfHorizRes and dfVertRes must be already set.
755 static void XFONT_SetFontMetric(fontInfo* fi, fontResource* fr, XFontStruct* xfs)
757 unsigned min, max;
758 INT el, il;
760 fi->df.dfFirstChar = (BYTE)(min = xfs->min_char_or_byte2);
761 fi->df.dfLastChar = (BYTE)(max = xfs->max_char_or_byte2);
763 fi->df.dfDefaultChar = (BYTE)xfs->default_char;
764 fi->df.dfBreakChar = (BYTE)(( ' ' < min || ' ' > max) ? xfs->default_char: ' ');
766 fi->df.dfPixHeight = (INT16)((fi->df.dfAscent = (INT16)xfs->ascent) + xfs->descent);
767 fi->df.dfPixWidth = (xfs->per_char) ? 0 : xfs->min_bounds.width;
768 fi->df.dfMaxWidth = (INT16)abs(xfs->max_bounds.width);
770 if( XFONT_GetLeading( &fi->df, xfs, &il, &el, NULL ) )
771 fi->df.dfAvgWidth = (INT16)xfs->per_char['X' - min].width;
772 else
773 fi->df.dfAvgWidth = (INT16)XFONT_GetAvgCharWidth( &fi->df, xfs, NULL);
775 fi->df.dfInternalLeading = (INT16)il;
776 fi->df.dfExternalLeading = (INT16)el;
778 fi->df.dfPoints = (INT16)(((INT)(fi->df.dfPixHeight -
779 fi->df.dfInternalLeading) * 72 + (fi->df.dfVertRes >> 1)) / fi->df.dfVertRes);
781 if( xfs->min_bounds.width != xfs->max_bounds.width )
782 fi->df.dfPitchAndFamily |= TMPF_FIXED_PITCH; /* au contraire! */
783 if( fi->fi_flags & FI_SCALABLE )
785 fi->df.dfType = DEVICE_FONTTYPE;
786 fi->df.dfPitchAndFamily |= TMPF_DEVICE;
788 else if( fi->fi_flags & FI_TRUETYPE )
789 fi->df.dfType = TRUETYPE_FONTTYPE;
790 else
791 fi->df.dfType = RASTER_FONTTYPE;
793 fi->df.dfFace = fr->lfFaceName;
796 /***********************************************************************
797 * XFONT_GetTextMetric
799 * GetTextMetrics() back end.
801 static void XFONT_GetTextMetric( fontObject* pfo, LPTEXTMETRICA pTM )
803 LPIFONTINFO16 pdf = &pfo->fi->df;
805 if( ! pfo->lpX11Trans ) {
806 pTM->tmAscent = pfo->fs->ascent;
807 pTM->tmDescent = pfo->fs->descent;
808 } else {
809 pTM->tmAscent = pfo->lpX11Trans->ascent;
810 pTM->tmDescent = pfo->lpX11Trans->descent;
812 pTM->tmHeight = pTM->tmAscent + pTM->tmDescent;
814 pTM->tmAveCharWidth = pfo->foAvgCharWidth;
815 pTM->tmMaxCharWidth = pfo->foMaxCharWidth;
817 pTM->tmInternalLeading = pfo->foInternalLeading;
818 pTM->tmExternalLeading = pdf->dfExternalLeading;
820 pTM->tmStruckOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT )
821 ? 1 : pdf->dfStrikeOut;
822 pTM->tmUnderlined = (pfo->fo_flags & FO_SYNTH_UNDERLINE )
823 ? 1 : pdf->dfUnderline;
825 pTM->tmOverhang = 0;
826 if( pfo->fo_flags & FO_SYNTH_ITALIC )
828 pTM->tmOverhang += pTM->tmHeight/3;
829 pTM->tmItalic = 1;
830 } else
831 pTM->tmItalic = pdf->dfItalic;
833 pTM->tmWeight = pdf->dfWeight;
834 if( pfo->fo_flags & FO_SYNTH_BOLD )
836 pTM->tmOverhang++;
837 pTM->tmWeight += 100;
840 *(INT*)&pTM->tmFirstChar = *(INT*)&pdf->dfFirstChar;
842 pTM->tmCharSet = pdf->dfCharSet;
843 pTM->tmPitchAndFamily = pdf->dfPitchAndFamily;
845 pTM->tmDigitizedAspectX = pdf->dfHorizRes;
846 pTM->tmDigitizedAspectY = pdf->dfVertRes;
849 /***********************************************************************
850 * XFONT_GetFontMetric
852 * Retrieve font metric info (enumeration).
854 static UINT XFONT_GetFontMetric( fontInfo* pfi, LPENUMLOGFONTEX16 pLF,
855 LPNEWTEXTMETRIC16 pTM )
857 memset( pLF, 0, sizeof(*pLF) );
858 memset( pTM, 0, sizeof(*pTM) );
860 #define plf ((LPLOGFONT16)pLF)
861 plf->lfHeight = pTM->tmHeight = pfi->df.dfPixHeight;
862 plf->lfWidth = pTM->tmAveCharWidth = pfi->df.dfAvgWidth;
863 plf->lfWeight = pTM->tmWeight = pfi->df.dfWeight;
864 plf->lfItalic = pTM->tmItalic = pfi->df.dfItalic;
865 plf->lfUnderline = pTM->tmUnderlined = pfi->df.dfUnderline;
866 plf->lfStrikeOut = pTM->tmStruckOut = pfi->df.dfStrikeOut;
867 plf->lfCharSet = pTM->tmCharSet = pfi->df.dfCharSet;
869 /* convert pitch values */
871 pTM->tmPitchAndFamily = pfi->df.dfPitchAndFamily;
872 plf->lfPitchAndFamily = (pfi->df.dfPitchAndFamily & 0xF1) + 1;
874 lstrcpynA( plf->lfFaceName, pfi->df.dfFace, LF_FACESIZE );
875 #undef plf
877 pTM->tmAscent = pfi->df.dfAscent;
878 pTM->tmDescent = pTM->tmHeight - pTM->tmAscent;
879 pTM->tmInternalLeading = pfi->df.dfInternalLeading;
880 pTM->tmMaxCharWidth = pfi->df.dfMaxWidth;
881 pTM->tmDigitizedAspectX = pfi->df.dfHorizRes;
882 pTM->tmDigitizedAspectY = pfi->df.dfVertRes;
884 *(INT*)&pTM->tmFirstChar = *(INT*)&pfi->df.dfFirstChar;
886 /* return font type */
888 return pfi->df.dfType;
892 /***********************************************************************
893 * XFONT_FixupFlags
895 * INIT ONLY
897 * dfPitchAndFamily flags for some common typefaces.
899 static BYTE XFONT_FixupFlags( LPCSTR lfFaceName )
901 switch( lfFaceName[0] )
903 case 'h':
904 case 'H': if(!strcasecmp(lfFaceName, "Helvetica") )
905 return FF_SWISS;
906 break;
907 case 'c':
908 case 'C': if(!strcasecmp(lfFaceName, "Courier") ||
909 !strcasecmp(lfFaceName, "Charter") )
910 return FF_ROMAN;
911 break;
912 case 'p':
913 case 'P': if( !strcasecmp(lfFaceName,"Palatino") )
914 return FF_ROMAN;
915 break;
916 case 't':
917 case 'T': if(!strncasecmp(lfFaceName, "Times", 5) )
918 return FF_ROMAN;
919 break;
920 case 'u':
921 case 'U': if(!strcasecmp(lfFaceName, "Utopia") )
922 return FF_ROMAN;
923 break;
924 case 'z':
925 case 'Z': if(!strcasecmp(lfFaceName, "Zapf Dingbats") )
926 return FF_DECORATIVE;
928 return 0;
932 /***********************************************************************
933 * XFONT_CheckResourceName
935 * INIT ONLY
937 static BOOL XFONT_CheckResourceName( LPSTR resource, LPCSTR name, INT n )
939 resource = LFD_Advance( resource, 2 );
940 if( resource )
941 return (!strncasecmp( resource, name, n ));
942 return FALSE;
946 /***********************************************************************
947 * XFONT_WindowsNames
949 * INIT ONLY
951 * Build generic Windows aliases for X font names.
953 * -misc-fixed- -> "Fixed"
954 * -sony-fixed- -> "Sony Fixed", etc...
956 static void XFONT_WindowsNames( char* buffer )
958 fontResource* fr, *pfr;
959 char* lpstr, *lpch;
960 int i, up;
961 BYTE bFamilyStyle;
962 const char* relocTable[] = { INIDefaultFixed, INIDefault, NULL };
964 for( fr = fontList; fr ; fr = fr->next )
966 if( fr->fr_flags & FR_NAMESET ) continue; /* skip already assigned */
968 lpstr = LFD_Advance(fr->resource, 2);
969 i = LFD_Advance( lpstr, 1 ) - lpstr;
971 for( pfr = fontList; pfr != fr ; pfr = pfr->next )
972 if( pfr->fr_flags & FR_NAMESET )
973 if( XFONT_CheckResourceName( pfr->resource, lpstr, i ) )
974 break;
976 if( pfr != fr ) /* prepend vendor name */
977 lpstr = fr->resource + 1;
979 for( i = 0, up = 1, lpch = fr->lfFaceName; *lpstr && i < 32;
980 lpch++, lpstr++, i++ )
982 if( *lpstr == LFDSeparator[1] || *lpstr == ' ' )
984 *lpch = ' ';
985 up = 1; continue;
987 else if( isalpha(*lpstr) && up )
989 *lpch = toupper(*lpstr);
990 up = 0; continue;
992 *lpch = *lpstr;
994 while (*(lpch - 1) == ' ') *(--lpch) = '\0';
996 if( (bFamilyStyle = XFONT_FixupFlags( fr->lfFaceName )) )
998 fontInfo* fi;
999 for( fi = fr->fi ; fi ; fi = fi->next )
1000 fi->df.dfPitchAndFamily |= bFamilyStyle;
1003 TRACE(font,"typeface \'%s\'\n", fr->lfFaceName);
1005 fr->fr_flags |= FR_NAMESET;
1008 for( up = 0; relocTable[up]; up++ )
1009 if( PROFILE_GetWineIniString( INIFontSection, relocTable[up], "", buffer, 128 ) )
1011 while( *buffer && isspace(*buffer) ) buffer++;
1012 for( fr = NULL, pfr = fontList; pfr; pfr = pfr->next )
1014 i = strlen( pfr->resource );
1015 if( !strncasecmp( pfr->resource, buffer, i) )
1017 if( fr )
1019 fr->next = pfr->next;
1020 pfr->next = fontList;
1021 fontList = pfr;
1023 break;
1025 fr = pfr;
1030 /***********************************************************************
1031 * XFONT_CreateAlias
1033 static fontAlias* XFONT_CreateAlias( LPCSTR lpTypeFace, LPCSTR lpAlias )
1035 int j;
1036 fontAlias* pfa = aliasTable;
1038 while( 1 )
1040 /* check if we already got one */
1041 if( !strcasecmp( pfa->faTypeFace, lpAlias ) )
1043 TRACE(font,"\tredundant alias '%s' -> '%s'\n",
1044 lpAlias, lpTypeFace );
1045 return NULL;
1047 if( pfa->next ) pfa = pfa->next;
1048 else break;
1051 j = lstrlenA(lpTypeFace) + 1;
1052 pfa->next = HeapAlloc( SystemHeap, 0, sizeof(fontAlias) +
1053 j + lstrlenA(lpAlias) + 1 );
1054 if((pfa = pfa->next))
1056 pfa->next = NULL;
1057 pfa->faTypeFace = (LPSTR)(pfa + 1);
1058 lstrcpyA( pfa->faTypeFace, lpTypeFace );
1059 pfa->faAlias = pfa->faTypeFace + j;
1060 lstrcpyA( pfa->faAlias, lpAlias );
1062 TRACE(font, "\tadded alias '%s' for %s\n", lpAlias, lpTypeFace );
1064 return pfa;
1066 return NULL;
1069 /***********************************************************************
1070 * XFONT_LoadAliases
1072 * Read user-defined aliases from wine.conf. Format is as follows
1074 * Alias# = [Windows font name],[LFD font name], <substitute original name>
1076 * Example:
1077 * Alias0 = Arial, -adobe-helvetica-
1078 * Alias1 = Times New Roman, -bitstream-courier-, 1
1079 * ...
1081 * Note that from 081797 and on we have built-in alias templates that take
1082 * care of the necessary Windows typefaces.
1084 static void XFONT_LoadAliases( char** buffer, int *buf_size )
1086 char* lpResource, *lpAlias;
1087 char subsection[32];
1088 int i = 0, j = 0;
1089 BOOL bHaveAlias = TRUE, bSubst = FALSE;
1091 if( *buf_size < 128 )
1093 *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
1094 *buf_size = 256;
1098 if( j < faTemplateNum )
1100 /* built-in templates first */
1102 lpResource = faTemplate[j].fatResource;
1103 lpAlias = faTemplate[j].fatAlias;
1104 j++;
1106 else
1108 /* then WINE.CONF */
1110 wsprintfA( subsection, "%s%i", INIAliasSection, i++ );
1112 if( (bHaveAlias = PROFILE_GetWineIniString( INIFontSection,
1113 subsection, "", *buffer, 128 )) )
1115 lpAlias = *buffer;
1116 while( isspace(*lpAlias) ) lpAlias++;
1117 lpResource = PROFILE_GetStringItem( lpAlias );
1118 bSubst = (PROFILE_GetStringItem( lpResource )) ? TRUE : FALSE;
1122 if( bHaveAlias )
1124 int length;
1126 length = strlen( lpAlias );
1127 if( lpResource && length )
1129 fontResource* fr, *frMatch = NULL;
1131 for (fr = fontList; fr ; fr = fr->next)
1133 if( !strcasecmp( fr->resource, lpResource ) ) frMatch = fr;
1134 if( XFONT_CheckResourceName( fr->resource, lpAlias, length ) )
1136 /* alias is not needed since the real font is present */
1137 frMatch = NULL; break;
1141 if( frMatch )
1143 if( bSubst )
1145 fontAlias *pfa, *prev = NULL;
1147 for(pfa = aliasTable; pfa; pfa = pfa->next)
1149 /* Remove lpAlias from aliasTable - we should free the old entry */
1150 if(!strcmp(lpAlias, pfa->faAlias))
1152 if(prev)
1153 prev->next = pfa->next;
1154 else
1155 aliasTable = pfa->next;
1158 /* Update any references to the substituted font in aliasTable */
1159 if(!strcmp(frMatch->lfFaceName,
1160 pfa->faTypeFace))
1161 pfa->faTypeFace = HEAP_strdupA( SystemHeap, 0,
1162 lpAlias );
1163 prev = pfa;
1166 TRACE(font, "\tsubstituted '%s' with %s\n",
1167 frMatch->lfFaceName, lpAlias );
1169 lstrcpynA( frMatch->lfFaceName, lpAlias, LF_FACESIZE );
1170 frMatch->fr_flags |= FR_NAMESET;
1172 else
1174 /* create new entry in the alias table */
1175 XFONT_CreateAlias( frMatch->lfFaceName, lpAlias );
1179 else ERR(font, " malformed font alias '%s'\n", *buffer );
1181 else break;
1182 } while(TRUE);
1185 /***********************************************************************
1186 * XFONT_LoadPenalties
1188 * Removes specified fonts from the font table to prevent Wine from
1189 * using it.
1191 * Ignore# = [LFD font name]
1193 * Example:
1194 * Ignore0 = -misc-nil-
1195 * Ignore1 = -sun-open look glyph-
1196 * ...
1199 static void XFONT_LoadPenalties( char** buffer, int *buf_size )
1201 int i = 0;
1202 char subsection[32];
1204 if( *buf_size < 128 )
1206 *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
1207 *buf_size = 256;
1208 *buffer = '\0';
1212 wsprintfA( subsection, "%s%i", INIIgnoreSection, i++ );
1214 if( PROFILE_GetWineIniString( INIFontSection,
1215 subsection, "", *buffer, 255 ) )
1217 fontResource** ppfr;
1218 int length = strlen( *buffer );
1220 for( ppfr = &fontList; *ppfr ; ppfr = &((*ppfr)->next))
1222 if( !strncasecmp( (*ppfr)->resource, *buffer, length ) )
1224 TRACE(font, "Ignoring '%s'\n", (*ppfr)->resource );
1226 XFONT_RemoveFontResource( ppfr );
1230 else
1231 break;
1232 } while(TRUE);
1236 /***********************************************************************
1237 * XFONT_UserMetricsCache
1239 * Returns expanded name for the ~/.wine/.cachedmetrics file.
1240 * Now it also appends the current value of the $DISPLAY varaible.
1242 static char* XFONT_UserMetricsCache( char* buffer, int* buf_size )
1244 struct passwd* pwd;
1245 char* pchDisplay;
1247 pchDisplay = getenv( "DISPLAY" );
1248 if( !pchDisplay ) pchDisplay = "0";
1250 pwd = getpwuid(getuid());
1251 if( pwd && pwd->pw_dir )
1253 int i = strlen( pwd->pw_dir ) + strlen( INIWinePrefix ) +
1254 strlen( INIFontMetrics ) + strlen( pchDisplay ) + 2;
1255 if( i > *buf_size )
1256 buffer = (char*) HeapReAlloc( SystemHeap, 0, buffer, *buf_size = i );
1257 strcpy( buffer, pwd->pw_dir );
1258 strcat( buffer, INIWinePrefix );
1259 strcat( buffer, INIFontMetrics );
1260 strcat( buffer, pchDisplay );
1261 } else buffer[0] = '\0';
1262 return buffer;
1266 /***********************************************************************
1267 * XFONT_ReadCachedMetrics
1269 * INIT ONLY
1271 static BOOL XFONT_ReadCachedMetrics( int fd, int res, unsigned x_checksum, int x_count )
1273 if( fd >= 0 )
1275 unsigned u;
1276 int i, j;
1278 /* read checksums */
1279 read( fd, &u, sizeof(unsigned) );
1280 read( fd, &i, sizeof(int) );
1282 if( u == x_checksum && i == x_count )
1284 off_t length, offset = 3 * sizeof(int);
1286 /* read total size */
1287 read( fd, &i, sizeof(int) );
1288 length = lseek( fd, 0, SEEK_END );
1290 if( length == (i + offset) )
1292 lseek( fd, offset, SEEK_SET );
1293 fontList = (fontResource*)HeapAlloc( SystemHeap, 0, i);
1294 if( fontList )
1296 fontResource* pfr = fontList;
1297 fontInfo* pfi = NULL;
1299 TRACE(font,"Reading cached font metrics:\n");
1301 read( fd, fontList, i); /* read all metrics at once */
1302 while( offset < length )
1304 offset += sizeof(fontResource) + sizeof(fontInfo);
1305 pfr->fi = pfi = (fontInfo*)(pfr + 1);
1306 j = 1;
1307 while( TRUE )
1309 if( offset > length ||
1310 (int)(pfi->next) != j++ ) goto fail;
1312 pfi->df.dfFace = pfr->lfFaceName;
1313 pfi->df.dfHorizRes = pfi->df.dfVertRes = res;
1314 pfi->df.dfPoints = (INT16)(((INT)(pfi->df.dfPixHeight -
1315 pfi->df.dfInternalLeading) * 72 + (res >> 1)) / res );
1316 pfi->next = pfi + 1;
1318 if( j > pfr->fi_count ) break;
1320 pfi = pfi->next;
1321 offset += sizeof(fontInfo);
1323 pfi->next = NULL;
1324 if( pfr->next )
1326 pfr->next = (fontResource*)(pfi + 1);
1327 pfr = pfr->next;
1329 else break;
1331 if( pfr->next == NULL &&
1332 *(int*)(pfi + 1) == X_FMC_MAGIC )
1334 /* read LFD stubs */
1335 char* lpch = (char*)((int*)(pfi + 1) + 1);
1336 offset += sizeof(int);
1337 for( pfr = fontList; pfr; pfr = pfr->next )
1339 TRACE(font,"\t%s, %i instances\n", lpch, pfr->fi_count );
1340 pfr->resource = lpch;
1341 while( TRUE )
1343 if( ++offset > length ) goto fail;
1344 if( !*lpch++ ) break;
1347 close( fd );
1348 return TRUE;
1353 fail:
1354 if( fontList ) HeapFree( SystemHeap, 0, fontList );
1355 fontList = NULL;
1356 close( fd );
1358 return FALSE;
1361 /***********************************************************************
1362 * XFONT_WriteCachedMetrics
1364 * INIT ONLY
1366 static BOOL XFONT_WriteCachedMetrics( int fd, unsigned x_checksum, int x_count, int n_ff )
1368 fontResource* pfr;
1369 fontInfo* pfi;
1371 if( fd >= 0 )
1373 int i, j, k;
1375 /* font metrics file:
1377 * +0000 x_checksum
1378 * +0004 x_count
1379 * +0008 total size to load
1380 * +000C prepackaged font metrics
1381 * ...
1382 * +...x X_FMC_MAGIC
1383 * +...x + 4 LFD stubs
1386 write( fd, &x_checksum, sizeof(unsigned) );
1387 write( fd, &x_count, sizeof(int) );
1389 for( j = i = 0, pfr = fontList; pfr; pfr = pfr->next )
1391 i += strlen( pfr->resource ) + 1;
1392 j += pfr->fi_count;
1394 i += n_ff * sizeof(fontResource) + j * sizeof(fontInfo) + sizeof(int);
1395 write( fd, &i, sizeof(int) );
1397 TRACE(font,"Writing font cache:\n");
1399 for( pfr = fontList; pfr; pfr = pfr->next )
1401 fontInfo fi;
1403 TRACE(font,"\t%s, %i instances\n", pfr->resource, pfr->fi_count );
1405 i = write( fd, pfr, sizeof(fontResource) );
1406 if( i == sizeof(fontResource) )
1408 for( k = 1, pfi = pfr->fi; pfi; pfi = pfi->next )
1410 memcpy( &fi, pfi, sizeof(fi) );
1412 fi.df.dfFace = NULL;
1413 fi.next = (fontInfo*)k; /* loader checks this */
1415 j = write( fd, &fi, sizeof(fi) );
1416 k++;
1418 if( j == sizeof(fontInfo) ) continue;
1420 break;
1422 if( i == sizeof(fontResource) && j == sizeof(fontInfo) )
1424 i = j = X_FMC_MAGIC;
1425 write( fd, &i, sizeof(int) );
1426 for( pfr = fontList; pfr && i == j; pfr = pfr->next )
1428 i = strlen( pfr->resource ) + 1;
1429 j = write( fd, pfr->resource, i );
1432 close( fd );
1433 return ( i == j );
1435 return TRUE;
1438 /***********************************************************************
1439 * XFONT_CheckIniSection
1441 * INIT ONLY
1443 * Examines wine.conf for old/invalid font entries and recommend changes to
1444 * the user.
1446 * Revision history
1447 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
1448 * Original implementation.
1450 static void XFONT_CheckIniCallback(char const *, char const *, void *);
1452 static char const *fontmsgprologue =
1453 "Wine warning:\n"
1454 " The following entries in the [fonts] section of the wine.conf file are\n"
1455 " obsolete or invalid:\n";
1457 static char const *fontmsgepilogue =
1458 " These entries should be eliminated or updated.\n"
1459 " See the documentation/fonts file for more information.\n";
1461 static int XFONT_CheckIniSection()
1463 int found = 0;
1465 PROFILE_EnumerateWineIniSection("Fonts", &XFONT_CheckIniCallback,
1466 (void *)&found);
1467 if(found)
1468 MSG(fontmsgepilogue);
1470 return 1;
1473 static void XFONT_CheckIniCallback(
1474 char const *key,
1475 char const *value,
1476 void *found)
1478 /* Ignore any keys that start with potential comment characters "'", '#',
1479 or ';'. */
1480 if(key[0] == '\'' || key[0] == '#' || key[0] == ';' || key[0] == '\0')
1481 return;
1483 /* Make sure this is a valid key */
1484 if((strncasecmp(key, INIAliasSection, 5) == 0) ||
1485 (strncasecmp(key, INIIgnoreSection, 6) == 0) ||
1486 (strcasecmp( key, INIDefault) == 0) ||
1487 (strcasecmp( key, INIDefaultFixed) == 0) ||
1488 (strcasecmp( key, INIGlobalMetrics) == 0) ||
1489 (strcasecmp( key, INIResolution) == 0) ||
1490 (strcasecmp( key, INIDefaultSerif) == 0) ||
1491 (strcasecmp( key, INIDefaultSansSerif) ==0) )
1493 /* Valid key; make sure the value doesn't contain a wildcard */
1494 if(strchr(value, '*')) {
1495 if(*(int *)found == 0) {
1496 MSG(fontmsgprologue);
1497 ++*(int *)found;
1500 MSG(" %s=%s [no wildcards allowed]\n", key, value);
1503 else {
1504 /* Not a valid key */
1505 if(*(int *)found == 0) {
1506 MSG(fontmsgprologue);
1507 ++*(int *)found;
1510 MSG(" %s=%s [obsolete]\n", key, value);
1513 return;
1516 /***********************************************************************
1517 * XFONT_GetPointResolution()
1519 * INIT ONLY
1521 * Here we initialize DefResolution which is used in the
1522 * XFONT_Match() penalty function. We also load the point
1523 * resolution value (higher values result in larger fonts).
1525 static int XFONT_GetPointResolution( DeviceCaps* pDevCaps )
1527 int i, j, point_resolution, num = 3;
1528 int allowed_xfont_resolutions[3] = { 72, 75, 100 };
1529 int best = 0, best_diff = 65536;
1531 DefResolution = point_resolution = PROFILE_GetWineIniInt( INIFontSection, INIResolution, 0 );
1532 if( !DefResolution ) DefResolution = point_resolution = pDevCaps->logPixelsY;
1533 else pDevCaps->logPixelsX = pDevCaps->logPixelsY = DefResolution;
1535 for( i = best = 0; i < num; i++ )
1537 j = abs( DefResolution - allowed_xfont_resolutions[i] );
1538 if( j < best_diff )
1540 best = i;
1541 best_diff = j;
1544 DefResolution = allowed_xfont_resolutions[best];
1545 return point_resolution;
1548 /***********************************************************************
1549 * XFONT_BuildDefaultAliases
1551 * INIT ONLY
1553 * Alias "Helv", and "Tms Rmn" to the DefaultSansSerif and DefaultSerif
1554 * fonts respectively. Create font alias templates for "MS Sans Serif"
1555 * and "MS Serif", also pointing to DefaultSansSerif and DefaultSerif.
1557 static int XFONT_BuildDefaultAliases( char** buffer, int* buf_size )
1560 aliasTemplate fatDefaultSerif = { "-bitstream-charter-", "Charter" };
1561 aliasTemplate fatDefaultSansSerif = { "-adobe-helvetica-", "Helvetica" };
1563 fontResource* fr;
1565 /* Make sure our buffer is big enough; update calling function's
1566 buf_size if we change it. */
1568 if( *buf_size < 128 )
1570 *buffer = HeapReAlloc( SystemHeap, 0, *buffer, 256 );
1571 *buf_size = 256;
1574 /* Get the X11 name of the default serif font from the Wine INI file.
1575 (-bitstream-charter- is the default.) */
1577 PROFILE_GetWineIniString( INIFontSection, INIDefaultSerif,
1578 fatDefaultSerif.fatResource, *buffer, 128 );
1580 /* Find the Windows typeface which corresponds to the X11 font. */
1582 for( fr = fontList; fr; fr = fr->next )
1583 if( !strcasecmp( fr->resource, *buffer ) ) break;
1585 /* Update the Alias Table entry for "Tms Rmn" with the default serif font's
1586 typeface. Update the Alias Template for "MS Serif" with the default
1587 serif font's X11 name. Note that this method leaves us dependant on
1588 the order of the Alias Table and the Alias Templates. Also, we don't
1589 check for or handle a situation in which -bitstream-charter- is not
1590 available. */
1592 if( fr )
1594 TRACE(font, "Using \'%s\' as default serif font\n", fr->lfFaceName);
1595 aliasTable[1].faTypeFace = fr->lfFaceName;
1596 faTemplate[1].fatResource = fr->resource;
1598 else
1600 WARN(font, "No typeface found for \'%s\'; using \'%s\'\n", *buffer,
1601 fatDefaultSerif.fatAlias);
1602 aliasTable[1].faTypeFace = fatDefaultSerif.fatAlias; /* Charter */
1603 faTemplate[1].fatResource = fatDefaultSerif.fatResource;
1606 /* Get the X11 name of the default sans serif font from the Wine INI file.
1607 (-adobe-helvetica- is the default.) */
1609 PROFILE_GetWineIniString (INIFontSection, INIDefaultSansSerif,
1610 fatDefaultSansSerif.fatResource, *buffer, 128 );
1612 /* Find the Windows typeface which corresponds to the X11 font. */
1614 for( fr = fontList; fr; fr = fr->next )
1615 if ( !strcasecmp( fr->resource, *buffer ) ) break;
1617 /* Update the Alias Table entry for "Helv" with the default sans serif font's
1618 typeface. Update the Alias Template for "MS Sans Serif" with the
1619 default sans serif font's X11 name. Note that this method leaves us
1620 dependant on the order of the Alias Table and the Alias Templates.
1621 Also, we don't check for or handle a situation in which
1622 -adobe-helvetica- is not available. */
1624 if( fr )
1626 TRACE(font, "Using \'%s\' as default sans serif font\n", fr->lfFaceName);
1627 aliasTable[0].faTypeFace = fr->lfFaceName;
1628 faTemplate[0].fatResource = fr->resource;
1630 else
1632 WARN(font, "No typeface found for \'%s\'; using \'%s\'\n", *buffer,
1633 fatDefaultSansSerif.fatAlias);
1634 aliasTable[0].faTypeFace = fatDefaultSansSerif.fatAlias; /* Helvetica */
1635 faTemplate[0].fatResource = fatDefaultSansSerif.fatResource;
1638 return 0;
1641 /***********************************************************************
1642 * X11DRV_FONT_Init
1644 * Initialize font resource list and allocate font cache.
1646 BOOL X11DRV_FONT_Init( DeviceCaps* pDevCaps )
1648 XFontStruct* x_fs;
1649 fontResource* fr, *pfr;
1650 fontInfo* fi, *pfi;
1651 unsigned x_checksum;
1652 int i, j, res, x_count, fd = -1, buf_size = 0;
1653 char* lpstr, *lpch, *lpmetrics, *buffer;
1654 char** x_pattern;
1656 XFONT_CheckIniSection();
1658 res = XFONT_GetPointResolution( pDevCaps );
1660 x_pattern = TSXListFonts(display, "*", MAX_FONT_FAMILIES * 16, &x_count );
1662 TRACE(font,"Font Mapper: initializing %i fonts [LPY=%i, XDR=%i, DR=%i]\n",
1663 x_count, pDevCaps->logPixelsY, DefResolution, res);
1664 for( i = x_checksum = 0; i < x_count; i++ )
1666 #if 0
1667 printf("%i\t: %s\n", i, x_pattern[i] );
1668 #endif
1670 j = strlen( x_pattern[i] );
1671 if( j ) x_checksum ^= __genericCheckSum( x_pattern[i], j );
1673 x_checksum |= X_PFONT_MAGIC;
1675 buf_size = 128;
1676 buffer = HeapAlloc( SystemHeap, 0, buf_size );
1677 lpmetrics = NULL;
1679 /* deal with systemwide font metrics cache */
1681 if( PROFILE_GetWineIniString( INIFontSection, INIGlobalMetrics, "", buffer, 128 ) )
1682 fd = open( buffer, O_RDONLY );
1684 if( XFONT_ReadCachedMetrics(fd, res, x_checksum, x_count) == FALSE )
1686 /* try per-user */
1687 buffer = XFONT_UserMetricsCache( buffer, &buf_size );
1688 if( buffer[0] )
1690 fd = open( buffer, O_RDONLY );
1691 if( XFONT_ReadCachedMetrics(fd, res, x_checksum, x_count) == FALSE )
1692 lpmetrics = HEAP_strdupA( SystemHeap, 0, buffer ); /* update later on */
1696 fi = NULL;
1697 if( fontList == NULL ) /* build metrics from scratch */
1699 int n_ff;
1700 char* typeface;
1702 for( i = n_ff = 0; i < x_count; i++ )
1704 typeface = lpch = x_pattern[i];
1706 lpch = LFD_Advance(typeface, 3); /* extra '-' in the beginning */
1707 if( !*lpch ) continue;
1709 lpstr = lpch;
1710 j = lpch - typeface; /* resource name length */
1712 /* find a family to insert into */
1714 for( pfr = NULL, fr = fontList; fr; fr = fr->next )
1716 if( !strncasecmp(fr->resource, typeface, j) &&
1717 strlen(fr->resource) == j ) break;
1718 pfr = fr;
1721 if( !fi ) fi = (fontInfo*) HeapAlloc(SystemHeap, 0, sizeof(fontInfo));
1723 if( !fr ) /* add new family */
1725 if( n_ff >= MAX_FONT_FAMILIES ) break;
1726 if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1728 n_ff++;
1729 fr = (fontResource*) HeapAlloc(SystemHeap, 0, sizeof(fontResource));
1730 memset(fr, 0, sizeof(fontResource));
1731 fr->resource = (char*) HeapAlloc(SystemHeap, 0, j + 1 );
1732 lstrcpynA( fr->resource, typeface, j + 1 );
1734 TRACE(font," family: %s\n", fr->resource );
1736 if( pfr ) pfr->next = fr;
1737 else fontList = fr;
1739 else if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1741 /* check if we already have something better than "fi" */
1743 for( pfi = fr->fi, j = 0; pfi && j <= 0; pfi = pfi->next )
1744 if( (j = XFONT_IsSubset( pfi, fi )) < 0 )
1745 pfi->fi_flags |= FI_SUBSET; /* superseded by "fi" */
1746 if( j > 0 ) continue;
1748 /* add new font instance "fi" to the "fr" font resource */
1750 if( fi->fi_flags & FI_SCALABLE )
1752 /* set scalable font height to 24 to get an origin for extrapolation */
1754 j = strlen(typeface); j += 0x10;
1755 if( j > buf_size )
1756 buffer = (char*)HeapReAlloc( SystemHeap, 0, buffer, buf_size = j );
1758 lpch = LFD_Advance(typeface, 7);
1759 memcpy( buffer, typeface, (j = lpch - typeface) );
1760 lpch = LFD_Advance(lpch, 4);
1761 sprintf( buffer + j, "%d-%d-%d-*-%c-*-", fi->lfd_height,
1762 fi->lfd_decipoints, fi->lfd_resolution,
1763 (*lpch == '-')?'*':*lpch );
1764 lpch = LFD_Advance(lpch, 2);
1765 strcat( lpstr = buffer, lpch);
1767 else lpstr = typeface;
1769 if( (x_fs = TSXLoadQueryFont(display, lpstr)) )
1771 fi->df.dfHorizRes = fi->df.dfVertRes = res;
1773 XFONT_SetFontMetric( fi, fr, x_fs );
1774 TSXFreeFont( display, x_fs );
1776 TRACE(font,"\t[% 2ipt] '%s'\n", fi->df.dfPoints, typeface );
1778 XFONT_CheckFIList( fr, fi, REMOVE_SUBSETS );
1779 fi = NULL; /* preventing reuse */
1781 else
1783 ERR(font, "failed to load %s\n", lpstr );
1785 XFONT_CheckFIList( fr, fi, UNMARK_SUBSETS );
1789 if( lpmetrics ) /* update cached metrics */
1791 fd = open( lpmetrics, O_CREAT | O_TRUNC | O_RDWR, 0644 ); /* -rw-r--r-- */
1792 if( XFONT_WriteCachedMetrics( fd, x_checksum, x_count, n_ff ) == FALSE )
1793 if( fd ) remove( lpmetrics ); /* couldn't write entire file */
1794 HeapFree( SystemHeap, 0, lpmetrics );
1798 if( fi ) HeapFree(SystemHeap, 0, fi);
1799 TSXFreeFontNames(x_pattern);
1801 /* check if we're dealing with X11 R6 server */
1803 strcpy(buffer, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
1804 if( (x_fs = TSXLoadQueryFont(display, buffer)) )
1806 XTextCaps |= TC_SF_X_YINDEP;
1807 TSXFreeFont(display, x_fs);
1810 XFONT_WindowsNames( buffer );
1811 XFONT_BuildDefaultAliases( &buffer, &buf_size );
1812 XFONT_LoadAliases( &buffer, &buf_size );
1813 XFONT_LoadPenalties( &buffer, &buf_size );
1814 HeapFree(SystemHeap, 0, buffer);
1816 InitializeCriticalSection( &crtsc_fonts_X11 );
1817 MakeCriticalSectionGlobal( &crtsc_fonts_X11 );
1819 /* fontList initialization is over, allocate X font cache */
1821 fontCache = (fontObject*) HeapAlloc(SystemHeap, 0, fontCacheSize * sizeof(fontObject));
1822 XFONT_GrowFreeList(0, fontCacheSize - 1);
1824 TRACE(font,"done!\n");
1826 /* update text caps parameter */
1828 pDevCaps->textCaps = XTextCaps;
1830 RAW_ASCENT = TSXInternAtom(display, "RAW_ASCENT", TRUE);
1831 RAW_DESCENT = TSXInternAtom(display, "RAW_DESCENT", TRUE);
1833 return TRUE;
1837 /***********************************************************************
1838 * XFONT_RemoveFontResource
1840 * Caller should check if the font resource is in use. If it is it should
1841 * set FR_REMOVED flag to delay removal until the resource is not in use
1842 * anymore.
1844 void XFONT_RemoveFontResource( fontResource** ppfr )
1846 fontInfo* pfi;
1847 fontResource* pfr = *ppfr;
1849 *ppfr = pfr->next;
1850 while( pfr->fi )
1852 pfi = pfr->fi->next;
1853 HeapFree( SystemHeap, 0, pfr->fi );
1854 pfr->fi = pfi;
1856 HeapFree( SystemHeap, 0, pfr );
1859 /***********************************************************************
1860 * X Font Matching
1862 * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1864 static INT XFONT_IsSubset(fontInfo* match, fontInfo* fi)
1866 INT m;
1868 /* 0 - keep both, 1 - keep match, -1 - keep fi */
1870 m = (BYTE*)&fi->df.dfPixWidth - (BYTE*)&fi->df.dfItalic;
1871 if( memcmp(&match->df.dfItalic, &fi->df.dfItalic, m )) return 0;
1873 if( (!((fi->fi_flags & FI_SCALABLE) + (match->fi_flags & FI_SCALABLE))
1874 && fi->lfd_height != match->lfd_height) ||
1875 (!((fi->fi_flags & FI_POLYWEIGHT) + (match->fi_flags & FI_POLYWEIGHT))
1876 && fi->df.dfWeight != match->df.dfWeight) ) return 0;
1878 m = (int)(match->fi_flags & (FI_POLYWEIGHT | FI_SCALABLE)) -
1879 (int)(fi->fi_flags & (FI_SCALABLE | FI_POLYWEIGHT));
1881 if( m == (FI_POLYWEIGHT - FI_SCALABLE) ||
1882 m == (FI_SCALABLE - FI_POLYWEIGHT) ) return 0; /* keep both */
1883 else if( m >= 0 ) return 1; /* 'match' is better */
1885 return -1; /* 'fi' is better */
1888 /***********************************************************************
1889 * XFONT_Match
1891 * Compute the matching score between the logical font and the device font.
1893 * contributions from highest to lowest:
1894 * charset
1895 * fixed pitch
1896 * height
1897 * family flags (only when the facename is not present)
1898 * width
1899 * weight, italics, underlines, strikeouts
1901 * NOTE: you can experiment with different penalty weights to see what happens.
1902 * http://premium.microsoft.com/msdn/library/techart/f365/f36b/f37b/d38b/sa8bf.htm
1904 static UINT XFONT_Match( fontMatch* pfm )
1906 fontInfo* pfi = pfm->pfi; /* device font to match */
1907 LPLOGFONT16 plf = pfm->plf; /* wanted logical font */
1908 UINT penalty = 0;
1909 BOOL bR6 = pfm->flags & FO_MATCH_XYINDEP; /* from TextCaps */
1910 BOOL bScale = pfi->fi_flags & FI_SCALABLE;
1911 INT d, h;
1913 TRACE(font,"\t[ %-2ipt h=%-3i w=%-3i %s%s]\n", pfi->df.dfPoints,
1914 pfi->df.dfPixHeight, pfi->df.dfAvgWidth,
1915 (pfi->df.dfWeight > 400) ? "Bold " : "Normal ",
1916 (pfi->df.dfItalic) ? "Italic" : "" );
1918 pfm->flags = 0;
1920 if( plf->lfCharSet == DEFAULT_CHARSET )
1922 if( (pfi->df.dfCharSet!= ANSI_CHARSET) && (pfi->df.dfCharSet!=DEFAULT_CHARSET) )
1923 penalty += 0x200;
1925 else if (plf->lfCharSet != pfi->df.dfCharSet) penalty += 0x200;
1927 /* FIXME: Hack to demote symbols and nil fonts. Should take into
1928 account if a program ever actually asked for this type of
1929 font */
1930 if ( (strcmp(pfm->pfr->lfFaceName,"Symbol")==0) || (strcmp(pfm->pfr->lfFaceName,"Nil")==0) )
1931 penalty += 0x200; /* very stiff penality */
1933 /* TMPF_FIXED_PITCH means exactly the opposite */
1935 if( plf->lfPitchAndFamily & FIXED_PITCH )
1937 if( pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH ) penalty += 0x100;
1939 else if( !(pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH) ) penalty += 0x2;
1941 if( plf->lfHeight > 0 )
1942 d = (h = pfi->df.dfPixHeight) - plf->lfHeight;
1943 else if( plf->lfHeight < -1 )
1944 d = (h = pfi->df.dfPoints) + plf->lfHeight;
1945 else d = h = 0;
1947 if( d && h && plf->lfHeight )
1949 UINT16 height = ( plf->lfHeight > 0 ) ? plf->lfHeight
1950 : ((-plf->lfHeight * pfi->df.dfPixHeight) / h);
1951 if( bScale ) pfm->height = height;
1952 else if( (plf->lfQuality != PROOF_QUALITY) && bR6 )
1954 if( d > 0 ) /* do not shrink raster fonts */
1956 pfm->height = pfi->df.dfPixHeight;
1957 penalty += (pfi->df.dfPixHeight - height) * 0x4;
1959 else /* expand only in integer multiples */
1961 pfm->height = height - height%pfi->df.dfPixHeight;
1962 penalty += (height - pfm->height + 1) * height / pfi->df.dfPixHeight;
1965 else /* can't be scaled at all */
1967 if( plf->lfQuality != PROOF_QUALITY) pfm->flags |= FO_SYNTH_HEIGHT;
1968 pfm->height = pfi->df.dfPixHeight;
1969 penalty += (d > 0)? d * 0x8 : -d * 0x10;
1972 else pfm->height = pfi->df.dfPixHeight;
1974 if((pfm->flags & FO_MATCH_PAF) &&
1975 (plf->lfPitchAndFamily & FF_FAMILY) != (pfi->df.dfPitchAndFamily & FF_FAMILY) )
1976 penalty += 0x10;
1978 if( plf->lfWidth )
1980 if( bR6 && bScale ) h = 0;
1981 else
1983 /* FIXME: not complete */
1985 pfm->flags |= FO_SYNTH_WIDTH;
1986 h = abs(plf->lfWidth - (pfm->height * pfi->df.dfAvgWidth)/pfi->df.dfPixHeight);
1988 penalty += h * ( d ) ? 0x2 : 0x1 ;
1990 else if( !(pfi->fi_flags & FI_NORMAL) ) penalty++;
1992 if( plf->lfWeight != FW_DONTCARE )
1994 penalty += abs(plf->lfWeight - pfi->df.dfWeight) / 40;
1995 if( plf->lfWeight > pfi->df.dfWeight ) pfm->flags |= FO_SYNTH_BOLD;
1996 } else if( pfi->df.dfWeight >= FW_BOLD ) penalty++; /* choose normal by default */
1998 if( plf->lfItalic != pfi->df.dfItalic )
2000 penalty += 0x4;
2001 pfm->flags |= FO_SYNTH_ITALIC;
2004 if( plf->lfUnderline ) pfm->flags |= FO_SYNTH_UNDERLINE;
2005 if( plf->lfStrikeOut ) pfm->flags |= FO_SYNTH_STRIKEOUT;
2007 if( penalty && pfi->lfd_resolution != DefResolution )
2008 penalty++;
2010 TRACE(font," returning %i\n", penalty );
2012 return penalty;
2015 /***********************************************************************
2016 * XFONT_MatchFIList
2018 * Scan a particular font resource for the best match.
2020 static UINT XFONT_MatchFIList( fontMatch* pfm )
2022 BOOL skipRaster = (pfm->flags & FO_MATCH_NORASTER);
2023 UINT current_score, score = (UINT)(-1);
2024 UINT16 origflags = pfm->flags; /* Preserve FO_MATCH_XYINDEP */
2025 fontMatch fm = *pfm;
2027 for( fm.pfi = pfm->pfr->fi; fm.pfi && score; fm.pfi = fm.pfi->next,
2028 fm.flags = origflags )
2030 if( skipRaster && !(fm.pfi->fi_flags & FI_SCALABLE) )
2031 continue;
2033 current_score = XFONT_Match( &fm );
2034 if( score > current_score )
2036 memcpy( pfm, &fm, sizeof(fontMatch) );
2037 score = current_score;
2040 return score;
2043 /***********************************************************************
2044 * XFONT_CheckFIList
2046 * REMOVE_SUBSETS - attach new fi and purge subsets
2047 * UNMARK_SUBSETS - remove subset flags from all fi entries
2049 static void XFONT_CheckFIList( fontResource* fr, fontInfo* fi, int action)
2051 int i = 0;
2052 fontInfo* pfi, *prev;
2054 for( prev = NULL, pfi = fr->fi; pfi; )
2056 if( action == REMOVE_SUBSETS )
2058 if( pfi->fi_flags & FI_SUBSET )
2060 fontInfo* subset = pfi;
2062 i++;
2063 fr->fi_count--;
2064 if( prev ) prev->next = pfi = pfi->next;
2065 else fr->fi = pfi = pfi->next;
2066 HeapFree( SystemHeap, 0, subset );
2067 continue;
2070 else pfi->fi_flags &= ~FI_SUBSET;
2072 prev = pfi;
2073 pfi = pfi->next;
2076 if( action == REMOVE_SUBSETS ) /* also add the superset */
2078 if( fi->fi_flags & FI_SCALABLE )
2080 fi->next = fr->fi;
2081 fr->fi = fi;
2083 else if( prev ) prev->next = fi; else fr->fi = fi;
2084 fr->fi_count++;
2087 if( i ) TRACE(font,"\t purged %i subsets [%i]\n", i , fr->fi_count);
2090 /***********************************************************************
2091 * XFONT_FindFIList
2093 static fontResource* XFONT_FindFIList( fontResource* pfr, const char* pTypeFace )
2095 while( pfr )
2097 if( !strcasecmp( pfr->lfFaceName, pTypeFace ) ) break;
2098 pfr = pfr->next;
2100 return pfr;
2103 /***********************************************************************
2104 * XFONT_MatchDeviceFont
2106 * Scan font resource tree.
2108 static BOOL XFONT_MatchDeviceFont( fontResource* start, fontMatch* pfm )
2110 fontResource** ppfr;
2111 fontMatch fm = *pfm;
2113 pfm->pfi = NULL;
2114 if( fm.plf->lfFaceName[0] )
2116 fontAlias* fa;
2117 LPSTR str = NULL;
2119 for( fa = aliasTable; fa; fa = fa->next )
2120 if( !strcmp( fa->faAlias, fm.plf->lfFaceName ) )
2122 str = fa->faTypeFace;
2123 break;
2125 fm.pfr = XFONT_FindFIList( start, str ? str : fm.plf->lfFaceName );
2128 if( fm.pfr ) /* match family */
2130 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2132 if( fm.pfr->fr_flags & FR_REMOVED )
2133 fm.pfr = 0;
2134 else
2136 XFONT_MatchFIList( &fm );
2137 *pfm = fm;
2141 if( !pfm->pfi ) /* match all available fonts */
2143 UINT current_score, score = (UINT)(-1);
2145 fm.flags |= FO_MATCH_PAF;
2146 for( ppfr = &fontList; *ppfr && score; ppfr = &(*ppfr)->next )
2148 if( (*ppfr)->fr_flags & FR_REMOVED )
2150 if( (*ppfr)->fo_count == 0 )
2151 XFONT_RemoveFontResource( ppfr );
2152 continue;
2155 fm.pfr = *ppfr;
2157 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2159 current_score = XFONT_MatchFIList( &fm );
2160 if( current_score < score )
2162 score = current_score;
2163 *pfm = fm;
2167 return TRUE;
2171 /***********************************************************************
2172 * X Font Cache
2174 static void XFONT_GrowFreeList(int start, int end)
2176 /* add all entries from 'start' up to and including 'end' */
2178 memset( fontCache + start, 0, (end - start + 1) * sizeof(fontObject) );
2180 fontCache[end].lru = fontLF;
2181 fontCache[end].count = -1;
2182 fontLF = start;
2183 while( start < end )
2185 fontCache[start].count = -1;
2186 fontCache[start].lru = start + 1;
2187 start++;
2191 static fontObject* XFONT_LookupCachedFont( LPLOGFONT16 plf, UINT16* checksum )
2193 UINT16 cs = __lfCheckSum( plf );
2194 int i = fontMRU, prev = -1;
2196 *checksum = cs;
2197 while( i >= 0 )
2199 if( fontCache[i].lfchecksum == cs &&
2200 !(fontCache[i].fo_flags & FO_REMOVED) )
2202 /* FIXME: something more intelligent here */
2204 if( !memcmp( plf, &fontCache[i].lf,
2205 sizeof(LOGFONT16) - LF_FACESIZE ) &&
2206 !strncasecmp( plf->lfFaceName, fontCache[i].lf.lfFaceName,
2207 LF_FACESIZE ) )
2209 /* remove temporarily from the lru list */
2211 if( prev >= 0 )
2212 fontCache[prev].lru = fontCache[i].lru;
2213 else
2214 fontMRU = (INT16)fontCache[i].lru;
2215 return (fontCache + i);
2218 prev = i;
2219 i = (INT16)fontCache[i].lru;
2221 return NULL;
2224 static fontObject* XFONT_GetCacheEntry()
2226 int i;
2228 if( fontLF == -1 )
2230 int prev_i, prev_j, j;
2232 TRACE(font,"font cache is full\n");
2234 /* lookup the least recently used font */
2236 for( prev_i = prev_j = j = -1, i = fontMRU; i >= 0; i = (INT16)fontCache[i].lru )
2238 if( fontCache[i].count <= 0 &&
2239 !(fontCache[i].fo_flags & FO_SYSTEM) )
2241 prev_j = prev_i;
2242 j = i;
2244 prev_i = i;
2247 if( j >= 0 ) /* unload font */
2249 /* detach from the lru list */
2251 TRACE(font,"\tfreeing entry %i\n", j );
2253 fontCache[j].fr->fo_count--;
2255 if( prev_j >= 0 )
2256 fontCache[prev_j].lru = fontCache[j].lru;
2257 else fontMRU = (INT16)fontCache[j].lru;
2259 /* FIXME: lpXForm, lpPixmap */
2260 if(fontCache[j].lpX11Trans)
2261 HeapFree( SystemHeap, 0, fontCache[j].lpX11Trans );
2263 TSXFreeFont( display, fontCache[j].fs );
2265 memset( fontCache + j, 0, sizeof(fontObject) );
2266 return (fontCache + j);
2268 else /* expand cache */
2270 fontObject* newCache;
2272 prev_i = fontCacheSize + FONTCACHE;
2274 TRACE(font,"\tgrowing font cache from %i to %i\n", fontCacheSize, prev_i );
2276 if( (newCache = (fontObject*)HeapReAlloc(SystemHeap, 0,
2277 fontCache, prev_i)) )
2279 i = fontCacheSize;
2280 fontCacheSize = prev_i;
2281 fontCache = newCache;
2282 XFONT_GrowFreeList( i, fontCacheSize - 1);
2284 else return NULL;
2288 /* detach from the free list */
2290 i = fontLF;
2291 fontLF = (INT16)fontCache[i].lru;
2292 fontCache[i].count = 0;
2293 return (fontCache + i);
2296 static int XFONT_ReleaseCacheEntry(fontObject* pfo)
2298 UINT u = (UINT)(pfo - fontCache);
2300 if( u < fontCacheSize ) return (--fontCache[u].count);
2301 return -1;
2304 /**********************************************************************
2305 * XFONT_SetX11Trans
2307 static BOOL XFONT_SetX11Trans( fontObject *pfo )
2309 char *fontName;
2310 Atom nameAtom;
2311 char *cp, *start;
2313 TSXGetFontProperty( pfo->fs, XA_FONT, &nameAtom );
2314 fontName = TSXGetAtomName( display, nameAtom );
2315 cp = LFD_Advance( fontName, 7 );
2316 if(*cp != '[') {
2317 TSXFree(fontName);
2318 return FALSE;
2320 start = cp;
2321 while((cp = strchr(cp, '~')))
2322 *cp = '-';
2324 #define PX pfo->lpX11Trans
2326 sscanf(start, "[%f%f%f%f]", &PX->a, &PX->b, &PX->c, &PX->d);
2327 TSXFree(fontName);
2329 TSXGetFontProperty( pfo->fs, RAW_ASCENT, &PX->RAW_ASCENT );
2330 TSXGetFontProperty( pfo->fs, RAW_DESCENT, &PX->RAW_DESCENT );
2332 PX->pixelsize = hypot(PX->a, PX->b);
2333 PX->ascent = PX->pixelsize / 1000.0 * PX->RAW_ASCENT;
2334 PX->descent = PX->pixelsize / 1000.0 * PX->RAW_DESCENT;
2336 TRACE(font, "[%f %f %f %f] RA = %ld RD = %ld\n", pfo->lpX11Trans->a,
2337 pfo->lpX11Trans->b, pfo->lpX11Trans->c, pfo->lpX11Trans->d,
2338 pfo->lpX11Trans->RAW_ASCENT, pfo->lpX11Trans->RAW_DESCENT);
2340 #undef PX
2341 return TRUE;
2344 /***********************************************************************
2345 * X Device Font Objects
2347 static X_PHYSFONT XFONT_RealizeFont( LPLOGFONT16 plf )
2349 UINT16 checksum;
2350 fontObject* pfo = XFONT_LookupCachedFont( plf, &checksum );
2352 if( !pfo )
2354 fontMatch fm = { NULL, NULL, 0, 0, plf};
2355 INT i, index;
2357 if( XTextCaps & TC_SF_X_YINDEP ) fm.flags = FO_MATCH_XYINDEP;
2359 /* allocate new font cache entry */
2361 if( (pfo = XFONT_GetCacheEntry()) )
2363 LPSTR lpLFD = HeapAlloc( GetProcessHeap(), 0, MAX_LFD_LENGTH );
2365 if( lpLFD ) /* initialize entry and load font */
2367 UINT uRelaxLevel = 0;
2369 TRACE(font,"(%u) '%s' h=%i weight=%i %s\n",
2370 plf->lfCharSet, plf->lfFaceName, plf->lfHeight,
2371 plf->lfWeight, (plf->lfItalic) ? "Italic" : "" );
2373 if(abs(plf->lfHeight) > MAX_FONT_SIZE) {
2374 ERR(font,
2375 "plf->lfHeight = %d, this is probably not right. Setting to 100\n",
2376 plf->lfHeight);
2377 plf->lfHeight = 100;
2380 XFONT_MatchDeviceFont( fontList, &fm );
2382 pfo->fr = fm.pfr;
2383 pfo->fi = fm.pfi;
2384 pfo->fr->fo_count++;
2385 pfo->fo_flags = fm.flags & ~FO_MATCH_MASK;
2387 memcpy( &pfo->lf, plf, sizeof(LOGFONT16) );
2388 pfo->lfchecksum = checksum;
2392 LFD_ComposeLFD( pfo, fm.height, lpLFD, uRelaxLevel++ );
2393 if( (pfo->fs = TSXLoadQueryFont( display, lpLFD )) ) break;
2394 } while( uRelaxLevel );
2397 if(pfo->lf.lfEscapement != 0) {
2398 pfo->lpX11Trans = HeapAlloc(SystemHeap, 0,
2399 sizeof(XFONTTRANS));
2400 if(!XFONT_SetX11Trans( pfo )) {
2401 HeapFree(SystemHeap, 0, pfo->lpX11Trans);
2402 pfo->lpX11Trans = NULL;
2406 if( XFONT_GetLeading( &pfo->fi->df, pfo->fs, &i, NULL,
2407 pfo->lpX11Trans ) )
2409 if(!pfo->lpX11Trans)
2410 pfo->foAvgCharWidth =
2411 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].width;
2412 else
2413 pfo->foAvgCharWidth =
2414 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].attributes
2415 * pfo->lpX11Trans->pixelsize / 1000.0;
2416 else
2417 pfo->foAvgCharWidth = (INT16)XFONT_GetAvgCharWidth(
2418 &pfo->fi->df, pfo->fs, pfo->lpX11Trans );
2419 pfo->foMaxCharWidth = (INT16)XFONT_GetMaxCharWidth(pfo);
2420 pfo->foInternalLeading = (INT16)i;
2422 /* FIXME: If we've got a soft font or
2423 * there are FO_SYNTH_... flags for the
2424 * non PROOF_QUALITY request, the engine
2425 * should rasterize characters into mono
2426 * pixmaps and store them in the pfo->lpPixmap
2427 * array (pfo->fs should be updated as well).
2428 * array (pfo->fs should be updated as well).
2429 * X11DRV_ExtTextOut() must be heavily modified
2430 * to support pixmap blitting and FO_SYNTH_...
2431 * styles.
2434 pfo->lpPixmap = NULL;
2436 HeapFree( GetProcessHeap(), 0, lpLFD );
2438 else /* attach back to the free list */
2440 pfo->count = -1;
2441 pfo->lru = fontLF;
2442 fontLF = (pfo - fontCache);
2443 pfo = NULL;
2447 if( !pfo ) /* couldn't get a new entry, get one of the cached fonts */
2449 UINT current_score, score = (UINT)(-1);
2451 i = index = fontMRU;
2452 fm.flags |= FO_MATCH_PAF;
2455 pfo = fontCache + i;
2456 fm.pfr = pfo->fr; fm.pfi = pfo->fi;
2458 current_score = XFONT_Match( &fm );
2459 if( current_score < score ) index = i;
2461 i = pfo->lru;
2462 } while( i >= 0 );
2463 pfo = fontCache + index;
2464 pfo->count++;
2465 return (X_PHYSFONT)(X_PFONT_MAGIC | index);
2469 /* attach at the head of the lru list */
2471 pfo->count++;
2472 pfo->lru = fontMRU;
2473 fontMRU = (pfo - fontCache);
2475 TRACE(font,"physfont %i\n", fontMRU);
2477 return (X_PHYSFONT)(X_PFONT_MAGIC | fontMRU);
2480 /***********************************************************************
2481 * XFONT_GetFontObject
2483 fontObject* XFONT_GetFontObject( X_PHYSFONT pFont )
2485 if( CHECK_PFONT(pFont) ) return __PFONT(pFont);
2486 return NULL;
2489 /***********************************************************************
2490 * XFONT_GetFontStruct
2492 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
2494 if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
2495 return NULL;
2498 /***********************************************************************
2499 * XFONT_GetFontInfo
2501 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
2503 if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
2504 return NULL;
2509 /* X11DRV Interface ****************************************************
2511 * Exposed via the dc->funcs dispatch table. *
2513 ***********************************************************************/
2514 /***********************************************************************
2515 * X11DRV_FONT_SelectObject
2517 HFONT X11DRV_FONT_SelectObject( DC* dc, HFONT hfont, FONTOBJ* font )
2519 HFONT hPrevFont = 0;
2520 LOGFONT16 lf;
2521 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2523 EnterCriticalSection( &crtsc_fonts_X11 );
2525 if( CHECK_PFONT(physDev->font) )
2526 XFONT_ReleaseCacheEntry( __PFONT(physDev->font) );
2528 /* FIXME: do we need to pass anything back from here? */
2529 memcpy(&lf,&font->logfont,sizeof(lf));
2530 lf.lfWidth = font->logfont.lfWidth * dc->vportExtX/dc->wndExtX;
2531 lf.lfHeight = font->logfont.lfHeight* dc->vportExtY/dc->wndExtY;
2533 physDev->font = XFONT_RealizeFont( &lf );
2534 hPrevFont = dc->w.hFont;
2535 dc->w.hFont = hfont;
2537 LeaveCriticalSection( &crtsc_fonts_X11 );
2539 return hPrevFont;
2543 /***********************************************************************
2545 * X11DRV_EnumDeviceFonts
2547 BOOL X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf,
2548 DEVICEFONTENUMPROC proc, LPARAM lp )
2550 ENUMLOGFONTEX16 lf;
2551 NEWTEXTMETRIC16 tm;
2552 fontResource* pfr = fontList;
2553 BOOL b, bRet = 0;
2555 if( plf->lfFaceName[0] )
2557 /* enum all entries in this resource */
2558 pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
2559 if( pfr )
2561 fontInfo* pfi;
2562 for( pfi = pfr->fi; pfi; pfi = pfi->next )
2564 /* Note: XFONT_GetFontMetric() will have to
2565 release the crit section, font list will
2566 have to be retraversed on return */
2568 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2569 XFONT_GetFontMetric( pfi, &lf, &tm ), lp )) )
2570 bRet = b;
2571 else break;
2575 else /* enum first entry in each resource */
2576 for( ; pfr ; pfr = pfr->next )
2578 if(pfr->fi)
2580 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2581 XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
2582 bRet = b;
2583 else break;
2586 return bRet;
2590 /***********************************************************************
2591 * X11DRV_GetTextExtentPoint
2593 BOOL X11DRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT count,
2594 LPSIZE size )
2596 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2597 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2598 if( pfo ) {
2599 if( !pfo->lpX11Trans ) {
2600 int dir, ascent, descent;
2601 XCharStruct info;
2603 TSXTextExtents( pfo->fs, str, count, &dir, &ascent, &descent, &info );
2604 size->cx = abs((info.width + dc->w.breakRem + count *
2605 dc->w.charExtra) * dc->wndExtX / dc->vportExtX);
2606 size->cy = abs((pfo->fs->ascent + pfo->fs->descent) *
2607 dc->wndExtY / dc->vportExtY);
2608 } else {
2610 INT i;
2611 float x = 0.0, y = 0.0;
2612 for(i = 0; i < count; i++) {
2613 x += pfo->fs->per_char ?
2614 pfo->fs->per_char[str[i] - pfo->fs->min_char_or_byte2].attributes :
2615 pfo->fs->min_bounds.attributes;
2617 y = pfo->lpX11Trans->RAW_ASCENT + pfo->lpX11Trans->RAW_DESCENT;
2618 TRACE(font, "x = %f y = %f\n", x, y);
2619 x *= pfo->lpX11Trans->pixelsize / 1000.0;
2620 y *= pfo->lpX11Trans->pixelsize / 1000.0;
2621 size->cx = fabsf((x + dc->w.breakRem + count * dc->w.charExtra) *
2622 dc->wndExtX / dc->vportExtX);
2623 size->cy = fabsf(y * dc->wndExtY / dc->vportExtY);
2625 return TRUE;
2627 return FALSE;
2631 /***********************************************************************
2632 * X11DRV_GetTextMetrics
2634 BOOL X11DRV_GetTextMetrics(DC *dc, TEXTMETRICA *metrics)
2636 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2638 if( CHECK_PFONT(physDev->font) )
2640 fontObject* pfo = __PFONT(physDev->font);
2641 XFONT_GetTextMetric( pfo, metrics );
2643 return TRUE;
2645 return FALSE;
2649 /***********************************************************************
2650 * X11DRV_GetCharWidth
2652 BOOL X11DRV_GetCharWidth( DC *dc, UINT firstChar, UINT lastChar,
2653 LPINT buffer )
2655 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2656 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2658 if( pfo )
2660 int i;
2662 if (pfo->fs->per_char == NULL)
2663 for (i = firstChar; i <= lastChar; i++)
2664 if(pfo->lpX11Trans)
2665 *buffer++ = pfo->fs->min_bounds.attributes *
2666 pfo->lpX11Trans->pixelsize / 1000.0;
2667 else
2668 *buffer++ = pfo->fs->min_bounds.width;
2669 else
2671 XCharStruct *cs, *def;
2672 static XCharStruct __null_char = { 0, 0, 0, 0, 0, 0 };
2674 CI_GET_CHAR_INFO(pfo->fs, pfo->fs->default_char, &__null_char,
2675 def);
2677 for (i = firstChar; i <= lastChar; i++)
2679 if (i >= pfo->fs->min_char_or_byte2 &&
2680 i <= pfo->fs->max_char_or_byte2)
2682 cs = &pfo->fs->per_char[(i - pfo->fs->min_char_or_byte2)];
2683 if (CI_NONEXISTCHAR(cs)) cs = def;
2684 } else cs = def;
2685 if(pfo->lpX11Trans)
2686 *buffer++ = MAX(cs->attributes, 0) *
2687 pfo->lpX11Trans->pixelsize / 1000.0;
2688 else
2689 *buffer++ = MAX(cs->width, 0 );
2693 return TRUE;
2695 return FALSE;
2698 #endif /* !defined(X_DISPLAY_MISSING) */
2700 /***********************************************************************
2702 * Font Resource API *
2704 ***********************************************************************/
2705 /***********************************************************************
2706 * AddFontResource16 (GDI.119)
2708 * Can be either .FON, or .FNT, or .TTF, or .FOT font file.
2710 * FIXME: Load header and find the best-matching font in the fontList;
2711 * fixup dfPoints if all metrics are identical, otherwise create
2712 * new fontAlias. When soft font support is ready this will
2713 * simply create a new fontResource ('filename' will go into
2714 * the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE
2715 * flag set.
2717 INT16 WINAPI AddFontResource16( LPCSTR filename )
2719 return AddFontResourceA( filename );
2723 /***********************************************************************
2724 * AddFontResource32A (GDI32.2)
2726 INT WINAPI AddFontResourceA( LPCSTR str )
2728 FIXME(font, "(%s): stub\n", debugres_a(str));
2729 return 1;
2733 /***********************************************************************
2734 * AddFontResource32W (GDI32.4)
2736 INT WINAPI AddFontResourceW( LPCWSTR str )
2738 FIXME(font, "(%s): stub\n", debugres_w(str) );
2739 return 1;
2742 /***********************************************************************
2743 * RemoveFontResource16 (GDI.136)
2745 BOOL16 WINAPI RemoveFontResource16( SEGPTR str )
2747 FIXME(font, "(%s): stub\n", debugres_a(PTR_SEG_TO_LIN(str)));
2748 return TRUE;
2752 /***********************************************************************
2753 * RemoveFontResource32A (GDI32.284)
2755 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
2757 /* This is how it should look like */
2759 fontResource** ppfr;
2760 BOOL32 retVal = FALSE;
2762 EnterCriticalSection( &crtsc_fonts_X11 );
2763 for( ppfr = &fontList; *ppfr; ppfr = &(*ppfr)->next )
2764 if( !strcasecmp( (*ppfr)->lfFaceName, str ) )
2766 if(((*ppfr)->fr_flags & (FR_SOFTFONT | FR_SOFTRESOURCE)) &&
2767 (*ppfr)->hOwnerProcess == GetCurrentProcess() )
2769 if( (*ppfr)->fo_count )
2770 (*ppfr)->fr_flags |= FR_REMOVED;
2771 else
2772 XFONT_RemoveFontResource( ppfr );
2774 retVal = TRUE;
2776 LeaveCriticalSection( &crtsc_fontList );
2777 return retVal;
2779 FIXME(font, "(%s): stub\n", debugres_a(str));
2780 return TRUE;
2784 /***********************************************************************
2785 * RemoveFontResource32W (GDI32.286)
2787 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
2789 FIXME(font, "(%s): stub\n", debugres_w(str) );
2790 return TRUE;