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).
12 #ifndef X_DISPLAY_MISSING
13 #include <X11/Xatom.h>
16 #endif /* !defined(X_DISPLAY_MISSING) */
24 #include <sys/types.h>
36 #ifndef X_DISPLAY_MISSING
38 #define X_PFONT_MAGIC (0xFADE0000)
39 #define X_FMC_MAGIC (0x0000CAFE)
41 #define MAX_FONT_FAMILIES 128
42 #define MAX_LFD_LENGTH 256
44 #define MAX_FONT_SIZE 1000 /* Max size in pixels */
46 #define REMOVE_SUBSETS 1
47 #define UNMARK_SUBSETS 0
49 #define DEF_SCALABLE_HEIGHT 24
50 #define DEF_SCALABLE_DP 240
52 #define FF_FAMILY (FF_MODERN | FF_SWISS | FF_ROMAN | FF_DECORATIVE | FF_SCRIPT)
54 typedef struct __fontAlias
58 struct __fontAlias* next;
67 /* Font alias table - these 2 aliases are always present */
68 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
70 static fontAlias __aliasTable[2] = {
71 { NULL, "Helv", &__aliasTable[1] },
72 { NULL, "Tms Rmn", NULL }
75 static fontAlias *aliasTable = __aliasTable;
77 /* Optional built-in aliases, they are installed only when X
78 * cannot supply us with original MS fonts */
79 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
81 static int faTemplateNum = 4;
82 static aliasTemplate faTemplate[4] = {
83 { NULL, "MS Sans Serif" },
85 { "-adobe-times-", "Times New Roman" },
86 { "-adobe-helvetica-", "Arial" }
89 UINT16 XTextCaps = TC_OP_CHARACTER | TC_OP_STROKE |
90 TC_CP_STROKE | TC_CR_ANY |
91 TC_SA_DOUBLE | TC_SA_INTEGER | TC_SA_CONTIN |
92 TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
94 /* X11R6 adds TC_SF_X_YINDEP, maybe more... */
96 static const char* INIWinePrefix = "/.wine";
97 static const char* INIFontMetrics = "/.cachedmetrics.";
98 static const char* INIFontSection = "fonts";
99 static const char* INIAliasSection = "Alias";
100 static const char* INIIgnoreSection = "Ignore";
101 static const char* INIDefault = "Default";
102 static const char* INIDefaultFixed = "DefaultFixed";
103 static const char* INIResolution = "Resolution";
104 static const char* INIGlobalMetrics = "FontMetrics";
105 static const char* INIDefaultSerif = "DefaultSerif";
106 static const char* INIDefaultSansSerif = "DefaultSansSerif";
108 static const char* LFDSeparator = "*-";
110 /* suffix tables, must be less than 254 entries long */
112 static LPSTR suffx_iso[] = { "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8",
113 "-9", "-10", "-11", "-12", "-13", "-14", "-15", NULL };
114 static LPSTR suffx_iso646[] = { "-irv", NULL };
115 static LPSTR suffx_microsoft[] = { "-cp1252", "-cp1251", "-cp1250", "-cp1253", "-cp1254", "-cp1255",
116 "-cp1256", "-cp1257", "-fontspecific", "-symbol", NULL };
117 static LPSTR suffx_viscii[] = { "-1", NULL };
118 static LPSTR suffx_ansi[] = { "-0", NULL };
119 static LPSTR suffx_koi8[] = { "-ru", "-r", NULL };
120 static LPSTR suffx_null[] = { NULL };
122 /* charset mapping tables, have to have the same number of entries as corresponding suffix tables */
124 static BYTE chset_iso8859[] = { ANSI_CHARSET, EE_CHARSET, ISO3_CHARSET, ISO4_CHARSET, RUSSIAN_CHARSET,
125 ARABIC_CHARSET, GREEK_CHARSET, HEBREW_CHARSET, TURKISH_CHARSET, BALTIC_CHARSET,
126 THAI_CHARSET, SYMBOL_CHARSET, SYMBOL_CHARSET, SYMBOL_CHARSET, ANSI_CHARSET,
128 static BYTE chset_iso646[] = { ANSI_CHARSET, SYMBOL_CHARSET };
129 static BYTE chset_microsoft[] = { ANSI_CHARSET, RUSSIAN_CHARSET, EE_CHARSET, GREEK_CHARSET, TURKISH_CHARSET,
130 HEBREW_CHARSET, ARABIC_CHARSET, BALTIC_CHARSET, SYMBOL_CHARSET, SYMBOL_CHARSET,
132 static BYTE chset_ansi[] = { ANSI_CHARSET, ANSI_CHARSET };
133 static BYTE chset_koi8[] = { KOI8_CHARSET, KOI8_CHARSET, KOI8_CHARSET };
134 static BYTE chset_tcvn[] = { TCVN_CHARSET, TCVN_CHARSET };
135 static BYTE chset_tis620[] = { THAI_CHARSET, THAI_CHARSET };
136 static BYTE chset_fontspecific[] = { SYMBOL_CHARSET };
137 static BYTE chset_viscii[] = { VISCII_CHARSET, VISCII_CHARSET };
145 } fontEncodingTemplate;
147 /* Note: we can attach additional encoding mappings to the end
148 * of this table at runtime.
151 static fontEncodingTemplate __fETTable[10] = {
152 { "iso8859", &suffx_iso, &chset_iso8859, &__fETTable[1] },
153 { "iso646.1991", &suffx_iso646, &chset_iso646, &__fETTable[2] },
154 { "microsoft", &suffx_microsoft, &chset_microsoft, &__fETTable[3] },
155 { "ansi", &suffx_ansi, &chset_ansi, &__fETTable[4] },
156 { "ascii", &suffx_ansi, &chset_ansi, &__fETTable[5] },
157 { "fontspecific", &suffx_null, &chset_fontspecific, &__fETTable[6] },
158 { "koi8", &suffx_koi8, &chset_koi8, &__fETTable[7] },
159 { "tcvn", &suffx_ansi, &chset_tcvn, &__fETTable[8] },
160 { "tis620.2533", &suffx_ansi, &chset_tis620, &__fETTable[9] },
161 { "viscii1.1", &suffx_viscii, &chset_viscii, NULL }
163 static fontEncodingTemplate* fETTable = __fETTable;
165 static unsigned DefResolution = 0;
167 static CRITICAL_SECTION crtsc_fonts_X11;
169 static fontResource* fontList = NULL;
170 static fontObject* fontCache = NULL; /* array */
171 static int fontCacheSize = FONTCACHE;
172 static int fontLF = -1, fontMRU = -1; /* last free, most recently used */
174 #define __PFONT(pFont) ( fontCache + ((UINT)(pFont) & 0x0000FFFF) )
175 #define CHECK_PFONT(pFont) ( (((UINT)(pFont) & 0xFFFF0000) == X_PFONT_MAGIC) &&\
176 (((UINT)(pFont) & 0x0000FFFF) < fontCacheSize) )
178 static INT XFONT_IsSubset(fontInfo*, fontInfo*);
179 static void XFONT_CheckFIList(fontResource*, fontInfo*, int subset_action);
180 static void XFONT_GrowFreeList(int start, int end);
181 static void XFONT_RemoveFontResource(fontResource** ppfr);
184 static Atom RAW_ASCENT;
185 static Atom RAW_DESCENT;
187 /***********************************************************************
188 * Helper macros from X distribution
191 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
192 (((cs)->rbearing|(cs)->lbearing| \
193 (cs)->ascent|(cs)->descent) == 0))
195 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
198 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
199 if (fs->per_char == NULL) { \
200 cs = &fs->min_bounds; \
202 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
203 if (CI_NONEXISTCHAR(cs)) cs = def; \
208 #define CI_GET_DEFAULT_INFO(fs,cs) \
209 CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
211 /***********************************************************************
214 static UINT16 __lfCheckSum( LPLOGFONT16 plf )
216 CHAR font[LF_FACESIZE];
220 #define ptr ((UINT16*)plf)
221 for( i = 0; i < 9; i++ ) checksum ^= *ptr++;
224 #define ptr ((CHAR*)plf)
225 do { font[i++] = tolower(*ptr++); } while (( i < LF_FACESIZE) && (*ptr) && (*ptr!=' '));
226 for( ptr = font, i >>= 1; i > 0; i-- )
228 #define ptr ((UINT16*)plf)
234 static UINT16 __genericCheckSum( const void *ptr, int size )
236 unsigned int checksum = 0;
237 const char *p = (const char *)ptr;
239 checksum ^= (checksum << 3) + (checksum >> 29) + *p++;
241 return checksum & 0xffff;
244 /*************************************************************************
245 * LFD parse/compose routines
247 static char* LFD_Advance(LPSTR lpFont, UINT16 uParmsNo)
252 for( ; j < uParmsNo && *lpch; lpch++ ) if( *lpch == LFDSeparator[1] ) j++;
256 static void LFD_GetWeight( fontInfo* fi, LPSTR lpStr, int j)
258 if( j == 1 && *lpStr == '0' )
259 fi->fi_flags |= FI_POLYWEIGHT;
262 if( !strncasecmp( "bold", lpStr, 4) )
263 fi->df.dfWeight = FW_BOLD;
264 else if( !strncasecmp( "demi", lpStr, 4) )
266 fi->fi_flags |= FI_FW_DEMI;
267 fi->df.dfWeight = FW_DEMIBOLD;
269 else if( !strncasecmp( "book", lpStr, 4) )
271 fi->fi_flags |= FI_FW_BOOK;
272 fi->df.dfWeight = FW_REGULAR;
277 if( !strncasecmp( "light", lpStr, 5) )
278 fi->df.dfWeight = FW_LIGHT;
279 else if( !strncasecmp( "black", lpStr, 5) )
280 fi->df.dfWeight = FW_BLACK;
282 else if( j == 6 && !strncasecmp( "medium", lpStr, 6) )
283 fi->df.dfWeight = FW_REGULAR;
284 else if( j == 8 && !strncasecmp( "demibold", lpStr, 8) )
285 fi->df.dfWeight = FW_DEMIBOLD;
287 fi->df.dfWeight = FW_DONTCARE; /* FIXME: try to get something
288 * from the weight property */
291 static int LFD_GetSlant( fontInfo* fi, LPSTR lpStr, int l)
295 switch( tolower( *lpStr ) )
297 case '0': fi->fi_flags |= FI_POLYSLANT; /* haven't seen this one yet */
299 case 'r': fi->df.dfItalic = 0;
302 fi->fi_flags |= FI_OBLIQUE;
303 case 'i': fi->df.dfItalic = 1;
311 /*************************************************************************
316 * Fill in some fields in the fontInfo struct.
318 static int LFD_InitFontInfo( fontInfo* fi, LPSTR lpstr )
321 int i, j, dec_style_check, scalability;
323 fontEncodingTemplate* boba;
325 memset(fi, 0, sizeof(fontInfo) );
328 lpch = LFD_Advance( lpstr, 1);
329 if( !*lpch ) return FALSE;
330 j = lpch - lpstr - 1;
331 LFD_GetWeight( fi, lpstr, j );
334 lpch = LFD_Advance( lpstr = lpch, 1);
335 if( !*lpch ) return FALSE;
336 j = lpch - lpstr - 1;
337 dec_style_check = LFD_GetSlant( fi, lpstr, j );
340 lpch = LFD_Advance( lpstr = lpch, 1);
341 if( !*lpch ) return FALSE;
342 if( strncasecmp( "normal", lpstr, 6) ) /* XXX 'narrow', 'condensed', etc... */
343 dec_style_check = TRUE;
345 fi->fi_flags |= FI_NORMAL;
348 lpch = LFD_Advance( lpstr = lpch, 1);
349 if( !*lpch ) return FALSE;
350 j = lpch - lpstr - 1;
351 if( j > 3 ) /* find out is there "sans" or "script" */
356 if( strstr(lpstr, "sans") )
358 fi->df.dfPitchAndFamily |= FF_SWISS;
361 if( strstr(lpstr, "script") )
363 fi->df.dfPitchAndFamily |= FF_SCRIPT;
366 if( !j && dec_style_check )
367 fi->df.dfPitchAndFamily |= FF_DECORATIVE;
368 *(lpch - 1) = LFDSeparator[1];
371 /* pixel height, decipoint height, and res_x */
373 for( i = scalability = 0; i < 3; i++ )
375 lpch = LFD_Advance( lpstr = lpch, 1);
376 if( !*lpch ) return FALSE;
377 if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
380 if( !(tmp[i] = atoi(lpstr)) ) scalability++;
381 *(lpch - 1) = LFDSeparator[1];
383 if( scalability == 3 ) /* Type1 */
385 fi->fi_flags |= FI_SCALABLE;
386 fi->lfd_height = DEF_SCALABLE_HEIGHT; fi->lfd_decipoints = DEF_SCALABLE_DP;
387 fi->lfd_resolution = DefResolution;
389 else if( scalability == 0 ) /* Bitmap */
391 fi->lfd_height = tmp[0]; fi->lfd_decipoints = tmp[1];
392 fi->lfd_resolution = tmp[2];
394 else return FALSE; /* #$%^!!! X11R6 mutant garbage */
396 /* res_y - skip, spacing - */
397 lpstr = LFD_Advance( lpch, 1);
400 case '\0': return FALSE;
402 case 'p': fi->fi_flags |= FI_VARIABLEPITCH;
404 case 'c': fi->df.dfPitchAndFamily |= FF_MODERN;
405 fi->fi_flags |= FI_FIXEDEX;
407 case 'm': fi->fi_flags |= FI_FIXEDPITCH;
410 fi->df.dfPitchAndFamily |= DEFAULT_PITCH | FF_DONTCARE;
412 lpstr = LFD_Advance(lpstr, 1);
413 if( !*lpstr ) return FALSE;
415 /* average width - */
416 lpch = LFD_Advance( lpstr, 1);
417 if( !*lpch ) return FALSE;
418 if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
420 if( !(fi->lfd_width = atoi(lpstr)) && !scalability ) return FALSE;
421 *(lpch - 1) = LFDSeparator[1];
423 /* charset registry, charset encoding - */
424 if( strstr(lpch, "jisx") ||
425 strstr(lpch, "ksc") ||
426 strstr(lpch, "gb2312") ||
427 strstr(lpch, "big5") ||
428 strstr(lpch, "unicode") ) return FALSE; /* 2-byte stuff */
430 fi->df.dfCharSet = ANSI_CHARSET;
432 for( i = 0, boba = fETTable; boba; boba = boba->next, i++ )
434 tmp[0] = strlen( boba->prefix );
435 if( !strncasecmp( lpch, boba->prefix, tmp[0] ) )
437 if( lpch[tmp[0]] == '-' )
439 lpstr = lpch + tmp[0];
440 for( j = 0; (*(boba->psuffix))[j]; j++ )
442 tmp[1] = strlen( (*(boba->psuffix))[j] );
443 if( !strncasecmp( lpstr, (*(boba->psuffix))[j], tmp[1] ) )
445 fi->df.dfCharSet = (*(boba->pcharset))[j];
449 /* Note : LFD_ComposeLFD will produce 'prefix-*' encoding *
450 * if (*(boba->psuffix))[j] is NULL here */
454 for( j = 0; (*(boba->psuffix))[j] ; j++ );
455 fi->df.dfCharSet = (*(boba->pcharset))[j];
456 j = lpch[tmp[0]] ? 254 : 255;
461 if( !boba ) return FALSE;
463 /* i - index into fETTable
464 * j - index into suffix array for fETTable[i]
466 * 254 - weird suffix (i.e. no '-' right after prefix )
467 * 255 - no suffix at all.
470 fi->fi_encoding = 256 * (UINT16)i + (UINT16)j;
476 /*************************************************************************
479 * Note: uRelax is a treatment not a cure. Font mapping algorithm
480 * should be bulletproof enough to allow us to avoid hacks like
481 * if( uRelax == 200 ) even despite LFD being so braindead.
483 static BOOL LFD_ComposeLFD( fontObject* fo,
484 INT height, LPSTR lpLFD, UINT uRelax )
486 fontEncodingTemplate* boba;
487 int i, h, w, ch, point = 0;
490 char h_string[64], point_string[64];
492 *(lpLFD+MAX_LFD_LENGTH-1)=0;
493 lstrcpyA( lpLFD, fo->fr->resource );
496 switch( fo->fi->df.dfWeight )
499 strcat( lpLFD, "bold" ); break;
501 if( fo->fi->fi_flags & FI_FW_BOOK )
502 strcat( lpLFD, "book" );
504 strcat( lpLFD, "medium" );
507 strcat( lpLFD, "demi" );
508 if( !( fo->fi->fi_flags & FI_FW_DEMI) )
509 strcat ( lpLFD, "bold" );
512 strcat( lpLFD, "black" ); break;
514 strcat( lpLFD, "light" ); break;
516 strcat( lpLFD, "*" );
520 if( fo->fi->df.dfItalic )
521 if( fo->fi->fi_flags & FI_OBLIQUE )
522 strcat( lpLFD, "-o" );
524 strcat( lpLFD, "-i" );
526 strcat( lpLFD, (uRelax < 2) ? "-r" : "-*" );
528 /* add width style and skip serifs */
529 if( fo->fi->fi_flags & FI_NORMAL )
530 strcat( lpLFD, "-normal-*-");
532 strcat( lpLFD, "-*-*-" );
534 /* add pixelheight, pointheight, and resolution
536 * FIXME: fill in lpXForm and lpPixmap for rotated fonts
538 if( fo->fo_flags & FO_SYNTH_HEIGHT ) h = fo->fi->lfd_height;
539 else h = (fo->fi->lfd_height * height) / fo->fi->df.dfPixHeight;
541 if( XTextCaps & TC_SF_X_YINDEP )
543 if( fo->lf.lfWidth && !(fo->fo_flags & FO_SYNTH_WIDTH) )
544 point = (fo->fi->lfd_decipoints * fo->lf.lfWidth) / fo->fi->df.dfAvgWidth;
546 if( fo->fi->fi_flags & FI_SCALABLE ) /* adjust h/w ratio */
547 point = h * 72 * 10 / fo->fi->lfd_resolution;
550 /* handle rotated fonts */
551 if (fo->lf.lfEscapement) {
552 /* escapement is in tenths of degrees, theta is in radians */
553 double theta = M_PI*fo->lf.lfEscapement/1800.;
554 double h_matrix[4] = {h*cos(theta), h*sin(theta), -h*sin(theta), h*cos(theta)};
555 double point_matrix[4] = {point*cos(theta), point*sin(theta), -point*sin(theta), point*cos(theta)};
557 sprintf(h_string, "[%+f%+f%+f%+f]", h_matrix[0], h_matrix[1], h_matrix[2], h_matrix[3]);
558 sprintf(point_string, "[%+f%+f%+f%+f]", point_matrix[0], point_matrix[1], point_matrix[2], point_matrix[3]);
559 while ((s = strchr(h_string, '-'))) *s='~';
560 while ((s = strchr(point_string, '-'))) *s='~';
562 sprintf(h_string, "%d", h);
563 sprintf(point_string, "%d", point);
567 /* spacing and width */
569 if( fo->fi->fi_flags & FI_FIXEDPITCH )
570 w = ( fo->fi->fi_flags & FI_FIXEDEX ) ? 'c' : 'm';
572 w = ( fo->fi->fi_flags & FI_VARIABLEPITCH ) ? 'p' : LFDSeparator[0];
576 i = fo->fi->fi_encoding >> 8;
577 for( boba = fETTable; i; i--, boba = boba->next );
579 strcpy( lpEncoding, boba->prefix );
581 i = fo->fi->fi_encoding & 255;
584 case 254: strcat( lpEncoding, "*" );
588 if( (*(boba->psuffix))[i] )
589 strcat( lpEncoding, (*(boba->psuffix))[i] );
591 strcat( lpEncoding, "-*" );
594 case 255: /* no suffix */
597 lpch = lpLFD + lstrlenA(lpLFD);
598 ch = (fo->fi->fi_flags & FI_SCALABLE) ? '0' : LFDSeparator[0];
602 /* RealizeFont() will call us repeatedly with increasing uRelax
603 * until XLoadFont() succeeds. */
608 sprintf( lpch, "%s-%s-%i-%c-%c-*-%s", h_string,
610 fo->fi->lfd_resolution, ch, w, lpEncoding );
616 case 2: /* 2 will have replaced an 'r' in slant by '*' */
617 sprintf( lpch, "%s-*-%i-%c-%c-*-%s", h_string,
618 fo->fi->lfd_resolution, ch, w, lpEncoding );
622 sprintf( lpch, "%s-*-%i-%c-*-*-%s",
623 h_string, fo->fi->lfd_resolution, ch, lpEncoding );
627 sprintf( lpch, "%i-*-%i-%c-*-*-%s", fo->fi->lfd_height,
628 fo->fi->lfd_resolution, ch, lpEncoding );
632 sprintf( lpch, "%i-*-*-*-*-*-%s", fo->fi->lfd_height, lpEncoding );
636 sprintf( lpch, "%i-*-*-*-*-*-*-*", fo->fi->lfd_height);
639 /* to avoid an infinite loop; those will allways match */
641 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1" );
644 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" );
648 TRACE(font,"\tLFD(uRelax=%d): %s\n", uRelax, lpLFD );
649 assert(*(lpLFD+MAX_LFD_LENGTH-1)==0); /* check if overwrittem */
654 /***********************************************************************
657 * font info - http://www.microsoft.com/kb/articles/q65/1/23.htm
658 * Windows font metrics - http://www.microsoft.com/kb/articles/q32/6/67.htm
660 static BOOL XFONT_GetLeading( LPIFONTINFO16 pFI, XFontStruct* x_fs, INT*
661 pIL, INT* pEL, XFONTTRANS *XFT )
663 unsigned long height;
664 unsigned min = (unsigned char)pFI->dfFirstChar;
665 unsigned max = (unsigned char)pFI->dfLastChar;
666 BOOL bHaveCapHeight = (pFI->dfCharSet == ANSI_CHARSET && 'X' >= min && 'X' <= max );
671 Atom RAW_CAP_HEIGHT = TSXInternAtom(display, "RAW_CAP_HEIGHT", TRUE);
672 if(TSXGetFontProperty(x_fs, RAW_CAP_HEIGHT, &height))
674 (INT)(XFT->pixelsize / 1000.0 * height);
677 return bHaveCapHeight && x_fs->per_char;
680 if( TSXGetFontProperty(x_fs, XA_CAP_HEIGHT, &height) == FALSE )
684 height = x_fs->per_char['X' - min].ascent;
686 if (x_fs->ascent >= x_fs->max_bounds.ascent)
687 height = x_fs->max_bounds.ascent;
690 height = x_fs->ascent;
692 *pEL = x_fs->max_bounds.ascent - height;
695 height = x_fs->min_bounds.ascent;
698 *pIL = x_fs->ascent - height;
699 return (bHaveCapHeight && x_fs->per_char);
702 static INT XFONT_GetAvgCharWidth( LPIFONTINFO16 pFI, XFontStruct* x_fs,
705 unsigned min = (unsigned char)pFI->dfFirstChar;
706 unsigned max = (unsigned char)pFI->dfLastChar;
711 for( j = 0, width = 0, chars = 0, max -= min; j <= max; j++ )
712 if( !CI_NONEXISTCHAR(x_fs->per_char + j) )
715 width += x_fs->per_char[j].width;
717 width += x_fs->per_char[j].attributes *
718 XFT->pixelsize / 1000.0;
721 return (width / chars);
724 return x_fs->min_bounds.width;
727 static INT XFONT_GetMaxCharWidth(fontObject *pfo)
729 unsigned min = (unsigned char)pfo->fs->min_char_or_byte2;
730 unsigned max = (unsigned char)pfo->fs->max_char_or_byte2;
733 return abs(pfo->fs->max_bounds.width);
735 if( pfo->fs->per_char )
738 for( j = 0, maxwidth = 0, max -= min; j <= max; j++ )
739 if( !CI_NONEXISTCHAR(pfo->fs->per_char + j) )
740 if(maxwidth < pfo->fs->per_char[j].attributes)
741 maxwidth = pfo->fs->per_char[j].attributes;
743 maxwidth *= pfo->lpX11Trans->pixelsize / 1000.0;
746 return pfo->foAvgCharWidth;
749 /***********************************************************************
750 * XFONT_SetFontMetric
754 * Initializes IFONTINFO16. dfHorizRes and dfVertRes must be already set.
756 static void XFONT_SetFontMetric(fontInfo* fi, fontResource* fr, XFontStruct* xfs)
761 fi->df.dfFirstChar = (BYTE)(min = xfs->min_char_or_byte2);
762 fi->df.dfLastChar = (BYTE)(max = xfs->max_char_or_byte2);
764 fi->df.dfDefaultChar = (BYTE)xfs->default_char;
765 fi->df.dfBreakChar = (BYTE)(( ' ' < min || ' ' > max) ? xfs->default_char: ' ');
767 fi->df.dfPixHeight = (INT16)((fi->df.dfAscent = (INT16)xfs->ascent) + xfs->descent);
768 fi->df.dfPixWidth = (xfs->per_char) ? 0 : xfs->min_bounds.width;
769 fi->df.dfMaxWidth = (INT16)abs(xfs->max_bounds.width);
771 if( XFONT_GetLeading( &fi->df, xfs, &il, &el, NULL ) )
772 fi->df.dfAvgWidth = (INT16)xfs->per_char['X' - min].width;
774 fi->df.dfAvgWidth = (INT16)XFONT_GetAvgCharWidth( &fi->df, xfs, NULL);
776 fi->df.dfInternalLeading = (INT16)il;
777 fi->df.dfExternalLeading = (INT16)el;
779 fi->df.dfPoints = (INT16)(((INT)(fi->df.dfPixHeight -
780 fi->df.dfInternalLeading) * 72 + (fi->df.dfVertRes >> 1)) / fi->df.dfVertRes);
782 if( xfs->min_bounds.width != xfs->max_bounds.width )
783 fi->df.dfPitchAndFamily |= TMPF_FIXED_PITCH; /* au contraire! */
784 if( fi->fi_flags & FI_SCALABLE )
786 fi->df.dfType = DEVICE_FONTTYPE;
787 fi->df.dfPitchAndFamily |= TMPF_DEVICE;
789 else if( fi->fi_flags & FI_TRUETYPE )
790 fi->df.dfType = TRUETYPE_FONTTYPE;
792 fi->df.dfType = RASTER_FONTTYPE;
794 fi->df.dfFace = fr->lfFaceName;
797 /***********************************************************************
798 * XFONT_GetTextMetric
800 * GetTextMetrics() back end.
802 static void XFONT_GetTextMetric( fontObject* pfo, LPTEXTMETRICA pTM )
804 LPIFONTINFO16 pdf = &pfo->fi->df;
806 if( ! pfo->lpX11Trans ) {
807 pTM->tmAscent = pfo->fs->ascent;
808 pTM->tmDescent = pfo->fs->descent;
810 pTM->tmAscent = pfo->lpX11Trans->ascent;
811 pTM->tmDescent = pfo->lpX11Trans->descent;
813 pTM->tmHeight = pTM->tmAscent + pTM->tmDescent;
815 pTM->tmAveCharWidth = pfo->foAvgCharWidth;
816 pTM->tmMaxCharWidth = pfo->foMaxCharWidth;
818 pTM->tmInternalLeading = pfo->foInternalLeading;
819 pTM->tmExternalLeading = pdf->dfExternalLeading;
821 pTM->tmStruckOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT )
822 ? 1 : pdf->dfStrikeOut;
823 pTM->tmUnderlined = (pfo->fo_flags & FO_SYNTH_UNDERLINE )
824 ? 1 : pdf->dfUnderline;
827 if( pfo->fo_flags & FO_SYNTH_ITALIC )
829 pTM->tmOverhang += pTM->tmHeight/3;
832 pTM->tmItalic = pdf->dfItalic;
834 pTM->tmWeight = pdf->dfWeight;
835 if( pfo->fo_flags & FO_SYNTH_BOLD )
838 pTM->tmWeight += 100;
841 *(INT*)&pTM->tmFirstChar = *(INT*)&pdf->dfFirstChar;
843 pTM->tmCharSet = pdf->dfCharSet;
844 pTM->tmPitchAndFamily = pdf->dfPitchAndFamily;
846 pTM->tmDigitizedAspectX = pdf->dfHorizRes;
847 pTM->tmDigitizedAspectY = pdf->dfVertRes;
850 /***********************************************************************
851 * XFONT_GetFontMetric
853 * Retrieve font metric info (enumeration).
855 static UINT XFONT_GetFontMetric( fontInfo* pfi, LPENUMLOGFONTEX16 pLF,
856 LPNEWTEXTMETRIC16 pTM )
858 memset( pLF, 0, sizeof(*pLF) );
859 memset( pTM, 0, sizeof(*pTM) );
861 #define plf ((LPLOGFONT16)pLF)
862 plf->lfHeight = pTM->tmHeight = pfi->df.dfPixHeight;
863 plf->lfWidth = pTM->tmAveCharWidth = pfi->df.dfAvgWidth;
864 plf->lfWeight = pTM->tmWeight = pfi->df.dfWeight;
865 plf->lfItalic = pTM->tmItalic = pfi->df.dfItalic;
866 plf->lfUnderline = pTM->tmUnderlined = pfi->df.dfUnderline;
867 plf->lfStrikeOut = pTM->tmStruckOut = pfi->df.dfStrikeOut;
868 plf->lfCharSet = pTM->tmCharSet = pfi->df.dfCharSet;
870 /* convert pitch values */
872 pTM->tmPitchAndFamily = pfi->df.dfPitchAndFamily;
873 plf->lfPitchAndFamily = (pfi->df.dfPitchAndFamily & 0xF1) + 1;
875 lstrcpynA( plf->lfFaceName, pfi->df.dfFace, LF_FACESIZE );
878 pTM->tmAscent = pfi->df.dfAscent;
879 pTM->tmDescent = pTM->tmHeight - pTM->tmAscent;
880 pTM->tmInternalLeading = pfi->df.dfInternalLeading;
881 pTM->tmMaxCharWidth = pfi->df.dfMaxWidth;
882 pTM->tmDigitizedAspectX = pfi->df.dfHorizRes;
883 pTM->tmDigitizedAspectY = pfi->df.dfVertRes;
885 *(INT*)&pTM->tmFirstChar = *(INT*)&pfi->df.dfFirstChar;
887 /* return font type */
889 return pfi->df.dfType;
893 /***********************************************************************
898 * dfPitchAndFamily flags for some common typefaces.
900 static BYTE XFONT_FixupFlags( LPCSTR lfFaceName )
902 switch( lfFaceName[0] )
905 case 'H': if(!strcasecmp(lfFaceName, "Helvetica") )
909 case 'C': if(!strcasecmp(lfFaceName, "Courier") ||
910 !strcasecmp(lfFaceName, "Charter") )
914 case 'P': if( !strcasecmp(lfFaceName,"Palatino") )
918 case 'T': if(!strncasecmp(lfFaceName, "Times", 5) )
922 case 'U': if(!strcasecmp(lfFaceName, "Utopia") )
926 case 'Z': if(!strcasecmp(lfFaceName, "Zapf Dingbats") )
927 return FF_DECORATIVE;
933 /***********************************************************************
934 * XFONT_CheckResourceName
938 static BOOL XFONT_CheckResourceName( LPSTR resource, LPCSTR name, INT n )
940 resource = LFD_Advance( resource, 2 );
942 return (!strncasecmp( resource, name, n ));
947 /***********************************************************************
952 * Build generic Windows aliases for X font names.
954 * -misc-fixed- -> "Fixed"
955 * -sony-fixed- -> "Sony Fixed", etc...
957 static void XFONT_WindowsNames( char* buffer )
959 fontResource* fr, *pfr;
963 const char* relocTable[] = { INIDefaultFixed, INIDefault, NULL };
965 for( fr = fontList; fr ; fr = fr->next )
967 if( fr->fr_flags & FR_NAMESET ) continue; /* skip already assigned */
969 lpstr = LFD_Advance(fr->resource, 2);
970 i = LFD_Advance( lpstr, 1 ) - lpstr;
972 for( pfr = fontList; pfr != fr ; pfr = pfr->next )
973 if( pfr->fr_flags & FR_NAMESET )
974 if( XFONT_CheckResourceName( pfr->resource, lpstr, i ) )
977 if( pfr != fr ) /* prepend vendor name */
978 lpstr = fr->resource + 1;
980 for( i = 0, up = 1, lpch = fr->lfFaceName; *lpstr && i < 32;
981 lpch++, lpstr++, i++ )
983 if( *lpstr == LFDSeparator[1] || *lpstr == ' ' )
988 else if( isalpha(*lpstr) && up )
990 *lpch = toupper(*lpstr);
995 while (*(lpch - 1) == ' ') *(--lpch) = '\0';
997 if( (bFamilyStyle = XFONT_FixupFlags( fr->lfFaceName )) )
1000 for( fi = fr->fi ; fi ; fi = fi->next )
1001 fi->df.dfPitchAndFamily |= bFamilyStyle;
1004 TRACE(font,"typeface \'%s\'\n", fr->lfFaceName);
1006 fr->fr_flags |= FR_NAMESET;
1009 for( up = 0; relocTable[up]; up++ )
1010 if( PROFILE_GetWineIniString( INIFontSection, relocTable[up], "", buffer, 128 ) )
1012 while( *buffer && isspace(*buffer) ) buffer++;
1013 for( fr = NULL, pfr = fontList; pfr; pfr = pfr->next )
1015 i = strlen( pfr->resource );
1016 if( !strncasecmp( pfr->resource, buffer, i) )
1020 fr->next = pfr->next;
1021 pfr->next = fontList;
1031 /***********************************************************************
1034 static fontAlias* XFONT_CreateAlias( LPCSTR lpTypeFace, LPCSTR lpAlias )
1037 fontAlias* pfa = aliasTable;
1041 /* check if we already got one */
1042 if( !strcasecmp( pfa->faTypeFace, lpAlias ) )
1044 TRACE(font,"\tredundant alias '%s' -> '%s'\n",
1045 lpAlias, lpTypeFace );
1048 if( pfa->next ) pfa = pfa->next;
1052 j = lstrlenA(lpTypeFace) + 1;
1053 pfa->next = HeapAlloc( SystemHeap, 0, sizeof(fontAlias) +
1054 j + lstrlenA(lpAlias) + 1 );
1055 if((pfa = pfa->next))
1058 pfa->faTypeFace = (LPSTR)(pfa + 1);
1059 lstrcpyA( pfa->faTypeFace, lpTypeFace );
1060 pfa->faAlias = pfa->faTypeFace + j;
1061 lstrcpyA( pfa->faAlias, lpAlias );
1063 TRACE(font, "\tadded alias '%s' for %s\n", lpAlias, lpTypeFace );
1070 /***********************************************************************
1073 * Read user-defined aliases from wine.conf. Format is as follows
1075 * Alias# = [Windows font name],[LFD font name], <substitute original name>
1078 * Alias0 = Arial, -adobe-helvetica-
1079 * Alias1 = Times New Roman, -bitstream-courier-, 1
1082 * Note that from 081797 and on we have built-in alias templates that take
1083 * care of the necessary Windows typefaces.
1085 static void XFONT_LoadAliases( char** buffer, int *buf_size )
1087 char* lpResource, *lpAlias;
1088 char subsection[32];
1090 BOOL bHaveAlias = TRUE, bSubst = FALSE;
1092 if( *buf_size < 128 )
1094 *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
1099 if( j < faTemplateNum )
1101 /* built-in templates first */
1103 lpResource = faTemplate[j].fatResource;
1104 lpAlias = faTemplate[j].fatAlias;
1109 /* then WINE.CONF */
1111 wsprintfA( subsection, "%s%i", INIAliasSection, i++ );
1113 if( (bHaveAlias = PROFILE_GetWineIniString( INIFontSection,
1114 subsection, "", *buffer, 128 )) )
1117 while( isspace(*lpAlias) ) lpAlias++;
1118 lpResource = PROFILE_GetStringItem( lpAlias );
1119 bSubst = (PROFILE_GetStringItem( lpResource )) ? TRUE : FALSE;
1127 length = strlen( lpAlias );
1128 if( lpResource && length )
1130 fontResource* fr, *frMatch = NULL;
1132 for (fr = fontList; fr ; fr = fr->next)
1134 if( !strcasecmp( fr->resource, lpResource ) ) frMatch = fr;
1135 if( XFONT_CheckResourceName( fr->resource, lpAlias, length ) )
1137 /* alias is not needed since the real font is present */
1138 frMatch = NULL; break;
1146 fontAlias *pfa, *prev = NULL;
1148 for(pfa = aliasTable; pfa; pfa = pfa->next)
1150 /* Remove lpAlias from aliasTable - we should free the old entry */
1151 if(!strcmp(lpAlias, pfa->faAlias))
1154 prev->next = pfa->next;
1156 aliasTable = pfa->next;
1159 /* Update any references to the substituted font in aliasTable */
1160 if(!strcmp(frMatch->lfFaceName,
1162 pfa->faTypeFace = HEAP_strdupA( SystemHeap, 0,
1167 TRACE(font, "\tsubstituted '%s' with %s\n",
1168 frMatch->lfFaceName, lpAlias );
1170 lstrcpynA( frMatch->lfFaceName, lpAlias, LF_FACESIZE );
1171 frMatch->fr_flags |= FR_NAMESET;
1175 /* create new entry in the alias table */
1176 XFONT_CreateAlias( frMatch->lfFaceName, lpAlias );
1180 else ERR(font, " malformed font alias '%s'\n", *buffer );
1186 /***********************************************************************
1187 * XFONT_LoadPenalties
1189 * Removes specified fonts from the font table to prevent Wine from
1192 * Ignore# = [LFD font name]
1195 * Ignore0 = -misc-nil-
1196 * Ignore1 = -sun-open look glyph-
1200 static void XFONT_LoadPenalties( char** buffer, int *buf_size )
1203 char subsection[32];
1205 if( *buf_size < 128 )
1207 *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
1213 wsprintfA( subsection, "%s%i", INIIgnoreSection, i++ );
1215 if( PROFILE_GetWineIniString( INIFontSection,
1216 subsection, "", *buffer, 255 ) )
1218 fontResource** ppfr;
1219 int length = strlen( *buffer );
1221 for( ppfr = &fontList; *ppfr ; ppfr = &((*ppfr)->next))
1223 if( !strncasecmp( (*ppfr)->resource, *buffer, length ) )
1225 TRACE(font, "Ignoring '%s'\n", (*ppfr)->resource );
1227 XFONT_RemoveFontResource( ppfr );
1237 /***********************************************************************
1238 * XFONT_UserMetricsCache
1240 * Returns expanded name for the ~/.wine/.cachedmetrics file.
1241 * Now it also appends the current value of the $DISPLAY varaible.
1243 static char* XFONT_UserMetricsCache( char* buffer, int* buf_size )
1248 pchDisplay = getenv( "DISPLAY" );
1249 if( !pchDisplay ) pchDisplay = "0";
1251 pwd = getpwuid(getuid());
1252 if( pwd && pwd->pw_dir )
1254 int i = strlen( pwd->pw_dir ) + strlen( INIWinePrefix ) +
1255 strlen( INIFontMetrics ) + strlen( pchDisplay ) + 2;
1257 buffer = (char*) HeapReAlloc( SystemHeap, 0, buffer, *buf_size = i );
1258 strcpy( buffer, pwd->pw_dir );
1259 strcat( buffer, INIWinePrefix );
1260 strcat( buffer, INIFontMetrics );
1261 strcat( buffer, pchDisplay );
1262 } else buffer[0] = '\0';
1267 /***********************************************************************
1268 * XFONT_ReadCachedMetrics
1272 static BOOL XFONT_ReadCachedMetrics( int fd, int res, unsigned x_checksum, int x_count )
1279 /* read checksums */
1280 read( fd, &u, sizeof(unsigned) );
1281 read( fd, &i, sizeof(int) );
1283 if( u == x_checksum && i == x_count )
1285 off_t length, offset = 3 * sizeof(int);
1287 /* read total size */
1288 read( fd, &i, sizeof(int) );
1289 length = lseek( fd, 0, SEEK_END );
1291 if( length == (i + offset) )
1293 lseek( fd, offset, SEEK_SET );
1294 fontList = (fontResource*)HeapAlloc( SystemHeap, 0, i);
1297 fontResource* pfr = fontList;
1298 fontInfo* pfi = NULL;
1300 TRACE(font,"Reading cached font metrics:\n");
1302 read( fd, fontList, i); /* read all metrics at once */
1303 while( offset < length )
1305 offset += sizeof(fontResource) + sizeof(fontInfo);
1306 pfr->fi = pfi = (fontInfo*)(pfr + 1);
1310 if( offset > length ||
1311 (int)(pfi->next) != j++ ) goto fail;
1313 pfi->df.dfFace = pfr->lfFaceName;
1314 pfi->df.dfHorizRes = pfi->df.dfVertRes = res;
1315 pfi->df.dfPoints = (INT16)(((INT)(pfi->df.dfPixHeight -
1316 pfi->df.dfInternalLeading) * 72 + (res >> 1)) / res );
1317 pfi->next = pfi + 1;
1319 if( j > pfr->fi_count ) break;
1322 offset += sizeof(fontInfo);
1327 pfr->next = (fontResource*)(pfi + 1);
1332 if( pfr->next == NULL &&
1333 *(int*)(pfi + 1) == X_FMC_MAGIC )
1335 /* read LFD stubs */
1336 char* lpch = (char*)((int*)(pfi + 1) + 1);
1337 offset += sizeof(int);
1338 for( pfr = fontList; pfr; pfr = pfr->next )
1340 TRACE(font,"\t%s, %i instances\n", lpch, pfr->fi_count );
1341 pfr->resource = lpch;
1344 if( ++offset > length ) goto fail;
1345 if( !*lpch++ ) break;
1355 if( fontList ) HeapFree( SystemHeap, 0, fontList );
1362 /***********************************************************************
1363 * XFONT_WriteCachedMetrics
1367 static BOOL XFONT_WriteCachedMetrics( int fd, unsigned x_checksum, int x_count, int n_ff )
1376 /* font metrics file:
1380 * +0008 total size to load
1381 * +000C prepackaged font metrics
1384 * +...x + 4 LFD stubs
1387 write( fd, &x_checksum, sizeof(unsigned) );
1388 write( fd, &x_count, sizeof(int) );
1390 for( j = i = 0, pfr = fontList; pfr; pfr = pfr->next )
1392 i += strlen( pfr->resource ) + 1;
1395 i += n_ff * sizeof(fontResource) + j * sizeof(fontInfo) + sizeof(int);
1396 write( fd, &i, sizeof(int) );
1398 TRACE(font,"Writing font cache:\n");
1400 for( pfr = fontList; pfr; pfr = pfr->next )
1404 TRACE(font,"\t%s, %i instances\n", pfr->resource, pfr->fi_count );
1406 i = write( fd, pfr, sizeof(fontResource) );
1407 if( i == sizeof(fontResource) )
1409 for( k = 1, pfi = pfr->fi; pfi; pfi = pfi->next )
1411 memcpy( &fi, pfi, sizeof(fi) );
1413 fi.df.dfFace = NULL;
1414 fi.next = (fontInfo*)k; /* loader checks this */
1416 j = write( fd, &fi, sizeof(fi) );
1419 if( j == sizeof(fontInfo) ) continue;
1423 if( i == sizeof(fontResource) && j == sizeof(fontInfo) )
1425 i = j = X_FMC_MAGIC;
1426 write( fd, &i, sizeof(int) );
1427 for( pfr = fontList; pfr && i == j; pfr = pfr->next )
1429 i = strlen( pfr->resource ) + 1;
1430 j = write( fd, pfr->resource, i );
1439 /***********************************************************************
1440 * XFONT_CheckIniSection
1444 * Examines wine.conf for old/invalid font entries and recommend changes to
1448 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
1449 * Original implementation.
1451 static void XFONT_CheckIniCallback(char const *, char const *, void *);
1453 static char const *fontmsgprologue =
1455 " The following entries in the [fonts] section of the wine.conf file are\n"
1456 " obsolete or invalid:\n";
1458 static char const *fontmsgepilogue =
1459 " These entries should be eliminated or updated.\n"
1460 " See the documentation/fonts file for more information.\n";
1462 static int XFONT_CheckIniSection()
1466 PROFILE_EnumerateWineIniSection("Fonts", &XFONT_CheckIniCallback,
1469 MSG(fontmsgepilogue);
1474 static void XFONT_CheckIniCallback(
1479 /* Ignore any keys that start with potential comment characters "'", '#',
1481 if(key[0] == '\'' || key[0] == '#' || key[0] == ';' || key[0] == '\0')
1484 /* Make sure this is a valid key */
1485 if((strncasecmp(key, INIAliasSection, 5) == 0) ||
1486 (strncasecmp(key, INIIgnoreSection, 6) == 0) ||
1487 (strcasecmp( key, INIDefault) == 0) ||
1488 (strcasecmp( key, INIDefaultFixed) == 0) ||
1489 (strcasecmp( key, INIGlobalMetrics) == 0) ||
1490 (strcasecmp( key, INIResolution) == 0) ||
1491 (strcasecmp( key, INIDefaultSerif) == 0) ||
1492 (strcasecmp( key, INIDefaultSansSerif) ==0) )
1494 /* Valid key; make sure the value doesn't contain a wildcard */
1495 if(strchr(value, '*')) {
1496 if(*(int *)found == 0) {
1497 MSG(fontmsgprologue);
1501 MSG(" %s=%s [no wildcards allowed]\n", key, value);
1505 /* Not a valid key */
1506 if(*(int *)found == 0) {
1507 MSG(fontmsgprologue);
1511 MSG(" %s=%s [obsolete]\n", key, value);
1517 /***********************************************************************
1518 * XFONT_GetPointResolution()
1522 * Here we initialize DefResolution which is used in the
1523 * XFONT_Match() penalty function. We also load the point
1524 * resolution value (higher values result in larger fonts).
1526 static int XFONT_GetPointResolution( DeviceCaps* pDevCaps )
1528 int i, j, point_resolution, num = 3;
1529 int allowed_xfont_resolutions[3] = { 72, 75, 100 };
1530 int best = 0, best_diff = 65536;
1532 DefResolution = point_resolution = PROFILE_GetWineIniInt( INIFontSection, INIResolution, 0 );
1533 if( !DefResolution ) DefResolution = point_resolution = pDevCaps->logPixelsY;
1534 else pDevCaps->logPixelsX = pDevCaps->logPixelsY = DefResolution;
1536 for( i = best = 0; i < num; i++ )
1538 j = abs( DefResolution - allowed_xfont_resolutions[i] );
1545 DefResolution = allowed_xfont_resolutions[best];
1546 return point_resolution;
1549 /***********************************************************************
1550 * XFONT_BuildDefaultAliases
1554 * Alias "Helv", and "Tms Rmn" to the DefaultSansSerif and DefaultSerif
1555 * fonts respectively. Create font alias templates for "MS Sans Serif"
1556 * and "MS Serif", also pointing to DefaultSansSerif and DefaultSerif.
1558 static int XFONT_BuildDefaultAliases( char** buffer, int* buf_size )
1561 aliasTemplate fatDefaultSerif = { "-bitstream-charter-", "Charter" };
1562 aliasTemplate fatDefaultSansSerif = { "-adobe-helvetica-", "Helvetica" };
1566 /* Make sure our buffer is big enough; update calling function's
1567 buf_size if we change it. */
1569 if( *buf_size < 128 )
1571 *buffer = HeapReAlloc( SystemHeap, 0, *buffer, 256 );
1575 /* Get the X11 name of the default serif font from the Wine INI file.
1576 (-bitstream-charter- is the default.) */
1578 PROFILE_GetWineIniString( INIFontSection, INIDefaultSerif,
1579 fatDefaultSerif.fatResource, *buffer, 128 );
1581 /* Find the Windows typeface which corresponds to the X11 font. */
1583 for( fr = fontList; fr; fr = fr->next )
1584 if( !strcasecmp( fr->resource, *buffer ) ) break;
1586 /* Update the Alias Table entry for "Tms Rmn" with the default serif font's
1587 typeface. Update the Alias Template for "MS Serif" with the default
1588 serif font's X11 name. Note that this method leaves us dependant on
1589 the order of the Alias Table and the Alias Templates. Also, we don't
1590 check for or handle a situation in which -bitstream-charter- is not
1595 TRACE(font, "Using \'%s\' as default serif font\n", fr->lfFaceName);
1596 aliasTable[1].faTypeFace = fr->lfFaceName;
1597 faTemplate[1].fatResource = fr->resource;
1601 WARN(font, "No typeface found for \'%s\'; using \'%s\'\n", *buffer,
1602 fatDefaultSerif.fatAlias);
1603 aliasTable[1].faTypeFace = fatDefaultSerif.fatAlias; /* Charter */
1604 faTemplate[1].fatResource = fatDefaultSerif.fatResource;
1607 /* Get the X11 name of the default sans serif font from the Wine INI file.
1608 (-adobe-helvetica- is the default.) */
1610 PROFILE_GetWineIniString (INIFontSection, INIDefaultSansSerif,
1611 fatDefaultSansSerif.fatResource, *buffer, 128 );
1613 /* Find the Windows typeface which corresponds to the X11 font. */
1615 for( fr = fontList; fr; fr = fr->next )
1616 if ( !strcasecmp( fr->resource, *buffer ) ) break;
1618 /* Update the Alias Table entry for "Helv" with the default sans serif font's
1619 typeface. Update the Alias Template for "MS Sans Serif" with the
1620 default sans serif font's X11 name. Note that this method leaves us
1621 dependant on the order of the Alias Table and the Alias Templates.
1622 Also, we don't check for or handle a situation in which
1623 -adobe-helvetica- is not available. */
1627 TRACE(font, "Using \'%s\' as default sans serif font\n", fr->lfFaceName);
1628 aliasTable[0].faTypeFace = fr->lfFaceName;
1629 faTemplate[0].fatResource = fr->resource;
1633 WARN(font, "No typeface found for \'%s\'; using \'%s\'\n", *buffer,
1634 fatDefaultSansSerif.fatAlias);
1635 aliasTable[0].faTypeFace = fatDefaultSansSerif.fatAlias; /* Helvetica */
1636 faTemplate[0].fatResource = fatDefaultSansSerif.fatResource;
1642 /***********************************************************************
1645 * Initialize font resource list and allocate font cache.
1647 BOOL X11DRV_FONT_Init( DeviceCaps* pDevCaps )
1650 fontResource* fr, *pfr;
1652 unsigned x_checksum;
1653 int i, j, res, x_count, fd = -1, buf_size = 0;
1654 char* lpstr, *lpch, *lpmetrics, *buffer;
1657 XFONT_CheckIniSection();
1659 res = XFONT_GetPointResolution( pDevCaps );
1661 x_pattern = TSXListFonts(display, "*", MAX_FONT_FAMILIES * 16, &x_count );
1663 TRACE(font,"Font Mapper: initializing %i fonts [LPY=%i, XDR=%i, DR=%i]\n",
1664 x_count, pDevCaps->logPixelsY, DefResolution, res);
1665 for( i = x_checksum = 0; i < x_count; i++ )
1668 printf("%i\t: %s\n", i, x_pattern[i] );
1671 j = strlen( x_pattern[i] );
1672 if( j ) x_checksum ^= __genericCheckSum( x_pattern[i], j );
1674 x_checksum |= X_PFONT_MAGIC;
1677 buffer = HeapAlloc( SystemHeap, 0, buf_size );
1680 /* deal with systemwide font metrics cache */
1682 if( PROFILE_GetWineIniString( INIFontSection, INIGlobalMetrics, "", buffer, 128 ) )
1683 fd = open( buffer, O_RDONLY );
1685 if( XFONT_ReadCachedMetrics(fd, res, x_checksum, x_count) == FALSE )
1688 buffer = XFONT_UserMetricsCache( buffer, &buf_size );
1691 fd = open( buffer, O_RDONLY );
1692 if( XFONT_ReadCachedMetrics(fd, res, x_checksum, x_count) == FALSE )
1693 lpmetrics = HEAP_strdupA( SystemHeap, 0, buffer ); /* update later on */
1698 if( fontList == NULL ) /* build metrics from scratch */
1703 for( i = n_ff = 0; i < x_count; i++ )
1705 typeface = lpch = x_pattern[i];
1707 lpch = LFD_Advance(typeface, 3); /* extra '-' in the beginning */
1708 if( !*lpch ) continue;
1711 j = lpch - typeface; /* resource name length */
1713 /* find a family to insert into */
1715 for( pfr = NULL, fr = fontList; fr; fr = fr->next )
1717 if( !strncasecmp(fr->resource, typeface, j) &&
1718 strlen(fr->resource) == j ) break;
1722 if( !fi ) fi = (fontInfo*) HeapAlloc(SystemHeap, 0, sizeof(fontInfo));
1724 if( !fr ) /* add new family */
1726 if( n_ff >= MAX_FONT_FAMILIES ) break;
1727 if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1730 fr = (fontResource*) HeapAlloc(SystemHeap, 0, sizeof(fontResource));
1731 memset(fr, 0, sizeof(fontResource));
1732 fr->resource = (char*) HeapAlloc(SystemHeap, 0, j + 1 );
1733 lstrcpynA( fr->resource, typeface, j + 1 );
1735 TRACE(font," family: %s\n", fr->resource );
1737 if( pfr ) pfr->next = fr;
1740 else if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1742 /* check if we already have something better than "fi" */
1744 for( pfi = fr->fi, j = 0; pfi && j <= 0; pfi = pfi->next )
1745 if( (j = XFONT_IsSubset( pfi, fi )) < 0 )
1746 pfi->fi_flags |= FI_SUBSET; /* superseded by "fi" */
1747 if( j > 0 ) continue;
1749 /* add new font instance "fi" to the "fr" font resource */
1751 if( fi->fi_flags & FI_SCALABLE )
1753 /* set scalable font height to 24 to get an origin for extrapolation */
1755 j = strlen(typeface); j += 0x10;
1757 buffer = (char*)HeapReAlloc( SystemHeap, 0, buffer, buf_size = j );
1759 lpch = LFD_Advance(typeface, 7);
1760 memcpy( buffer, typeface, (j = lpch - typeface) );
1761 lpch = LFD_Advance(lpch, 4);
1762 sprintf( buffer + j, "%d-%d-%d-*-%c-*-", fi->lfd_height,
1763 fi->lfd_decipoints, fi->lfd_resolution,
1764 (*lpch == '-')?'*':*lpch );
1765 lpch = LFD_Advance(lpch, 2);
1766 strcat( lpstr = buffer, lpch);
1768 else lpstr = typeface;
1770 if( (x_fs = TSXLoadQueryFont(display, lpstr)) )
1772 fi->df.dfHorizRes = fi->df.dfVertRes = res;
1774 XFONT_SetFontMetric( fi, fr, x_fs );
1775 TSXFreeFont( display, x_fs );
1777 TRACE(font,"\t[% 2ipt] '%s'\n", fi->df.dfPoints, typeface );
1779 XFONT_CheckFIList( fr, fi, REMOVE_SUBSETS );
1780 fi = NULL; /* preventing reuse */
1784 ERR(font, "failed to load %s\n", lpstr );
1786 XFONT_CheckFIList( fr, fi, UNMARK_SUBSETS );
1790 if( lpmetrics ) /* update cached metrics */
1792 fd = open( lpmetrics, O_CREAT | O_TRUNC | O_RDWR, 0644 ); /* -rw-r--r-- */
1793 if( XFONT_WriteCachedMetrics( fd, x_checksum, x_count, n_ff ) == FALSE )
1794 if( fd ) remove( lpmetrics ); /* couldn't write entire file */
1795 HeapFree( SystemHeap, 0, lpmetrics );
1799 if( fi ) HeapFree(SystemHeap, 0, fi);
1800 TSXFreeFontNames(x_pattern);
1802 /* check if we're dealing with X11 R6 server */
1804 strcpy(buffer, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
1805 if( (x_fs = TSXLoadQueryFont(display, buffer)) )
1807 XTextCaps |= TC_SF_X_YINDEP;
1808 TSXFreeFont(display, x_fs);
1811 XFONT_WindowsNames( buffer );
1812 XFONT_BuildDefaultAliases( &buffer, &buf_size );
1813 XFONT_LoadAliases( &buffer, &buf_size );
1814 XFONT_LoadPenalties( &buffer, &buf_size );
1815 HeapFree(SystemHeap, 0, buffer);
1817 InitializeCriticalSection( &crtsc_fonts_X11 );
1818 MakeCriticalSectionGlobal( &crtsc_fonts_X11 );
1820 /* fontList initialization is over, allocate X font cache */
1822 fontCache = (fontObject*) HeapAlloc(SystemHeap, 0, fontCacheSize * sizeof(fontObject));
1823 XFONT_GrowFreeList(0, fontCacheSize - 1);
1825 TRACE(font,"done!\n");
1827 /* update text caps parameter */
1829 pDevCaps->textCaps = XTextCaps;
1831 RAW_ASCENT = TSXInternAtom(display, "RAW_ASCENT", TRUE);
1832 RAW_DESCENT = TSXInternAtom(display, "RAW_DESCENT", TRUE);
1838 /***********************************************************************
1839 * XFONT_RemoveFontResource
1841 * Caller should check if the font resource is in use. If it is it should
1842 * set FR_REMOVED flag to delay removal until the resource is not in use
1845 void XFONT_RemoveFontResource( fontResource** ppfr )
1848 fontResource* pfr = *ppfr;
1853 pfi = pfr->fi->next;
1854 HeapFree( SystemHeap, 0, pfr->fi );
1857 HeapFree( SystemHeap, 0, pfr );
1860 /***********************************************************************
1863 * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1865 static INT XFONT_IsSubset(fontInfo* match, fontInfo* fi)
1869 /* 0 - keep both, 1 - keep match, -1 - keep fi */
1871 m = (BYTE*)&fi->df.dfPixWidth - (BYTE*)&fi->df.dfItalic;
1872 if( memcmp(&match->df.dfItalic, &fi->df.dfItalic, m )) return 0;
1874 if( (!((fi->fi_flags & FI_SCALABLE) + (match->fi_flags & FI_SCALABLE))
1875 && fi->lfd_height != match->lfd_height) ||
1876 (!((fi->fi_flags & FI_POLYWEIGHT) + (match->fi_flags & FI_POLYWEIGHT))
1877 && fi->df.dfWeight != match->df.dfWeight) ) return 0;
1879 m = (int)(match->fi_flags & (FI_POLYWEIGHT | FI_SCALABLE)) -
1880 (int)(fi->fi_flags & (FI_SCALABLE | FI_POLYWEIGHT));
1882 if( m == (FI_POLYWEIGHT - FI_SCALABLE) ||
1883 m == (FI_SCALABLE - FI_POLYWEIGHT) ) return 0; /* keep both */
1884 else if( m >= 0 ) return 1; /* 'match' is better */
1886 return -1; /* 'fi' is better */
1889 /***********************************************************************
1892 * Compute the matching score between the logical font and the device font.
1894 * contributions from highest to lowest:
1898 * family flags (only when the facename is not present)
1900 * weight, italics, underlines, strikeouts
1902 * NOTE: you can experiment with different penalty weights to see what happens.
1903 * http://premium.microsoft.com/msdn/library/techart/f365/f36b/f37b/d38b/sa8bf.htm
1905 static UINT XFONT_Match( fontMatch* pfm )
1907 fontInfo* pfi = pfm->pfi; /* device font to match */
1908 LPLOGFONT16 plf = pfm->plf; /* wanted logical font */
1910 BOOL bR6 = pfm->flags & FO_MATCH_XYINDEP; /* from TextCaps */
1911 BOOL bScale = pfi->fi_flags & FI_SCALABLE;
1914 TRACE(font,"\t[ %-2ipt h=%-3i w=%-3i %s%s]\n", pfi->df.dfPoints,
1915 pfi->df.dfPixHeight, pfi->df.dfAvgWidth,
1916 (pfi->df.dfWeight > 400) ? "Bold " : "Normal ",
1917 (pfi->df.dfItalic) ? "Italic" : "" );
1921 if( plf->lfCharSet == DEFAULT_CHARSET )
1923 if( (pfi->df.dfCharSet!= ANSI_CHARSET) && (pfi->df.dfCharSet!=DEFAULT_CHARSET) )
1926 else if (plf->lfCharSet != pfi->df.dfCharSet) penalty += 0x200;
1928 /* FIXME: Hack to demote symbols and nil fonts. Should take into
1929 account if a program ever actually asked for this type of
1931 if ( (strcmp(pfm->pfr->lfFaceName,"Symbol")==0) || (strcmp(pfm->pfr->lfFaceName,"Nil")==0) )
1932 penalty += 0x200; /* very stiff penality */
1934 /* TMPF_FIXED_PITCH means exactly the opposite */
1936 if( plf->lfPitchAndFamily & FIXED_PITCH )
1938 if( pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH ) penalty += 0x100;
1940 else if( !(pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH) ) penalty += 0x2;
1942 if( plf->lfHeight > 0 )
1943 d = (h = pfi->df.dfPixHeight) - plf->lfHeight;
1944 else if( plf->lfHeight < -1 )
1945 d = (h = pfi->df.dfPoints) + plf->lfHeight;
1948 if( d && h && plf->lfHeight )
1950 UINT16 height = ( plf->lfHeight > 0 ) ? plf->lfHeight
1951 : ((-plf->lfHeight * pfi->df.dfPixHeight) / h);
1952 if( bScale ) pfm->height = height;
1953 else if( (plf->lfQuality != PROOF_QUALITY) && bR6 )
1955 if( d > 0 ) /* do not shrink raster fonts */
1957 pfm->height = pfi->df.dfPixHeight;
1958 penalty += (pfi->df.dfPixHeight - height) * 0x4;
1960 else /* expand only in integer multiples */
1962 pfm->height = height - height%pfi->df.dfPixHeight;
1963 penalty += (height - pfm->height + 1) * height / pfi->df.dfPixHeight;
1966 else /* can't be scaled at all */
1968 if( plf->lfQuality != PROOF_QUALITY) pfm->flags |= FO_SYNTH_HEIGHT;
1969 pfm->height = pfi->df.dfPixHeight;
1970 penalty += (d > 0)? d * 0x8 : -d * 0x10;
1973 else pfm->height = pfi->df.dfPixHeight;
1975 if((pfm->flags & FO_MATCH_PAF) &&
1976 (plf->lfPitchAndFamily & FF_FAMILY) != (pfi->df.dfPitchAndFamily & FF_FAMILY) )
1981 if( bR6 && bScale ) h = 0;
1984 /* FIXME: not complete */
1986 pfm->flags |= FO_SYNTH_WIDTH;
1987 h = abs(plf->lfWidth - (pfm->height * pfi->df.dfAvgWidth)/pfi->df.dfPixHeight);
1989 penalty += h * ( d ) ? 0x2 : 0x1 ;
1991 else if( !(pfi->fi_flags & FI_NORMAL) ) penalty++;
1993 if( plf->lfWeight != FW_DONTCARE )
1995 penalty += abs(plf->lfWeight - pfi->df.dfWeight) / 40;
1996 if( plf->lfWeight > pfi->df.dfWeight ) pfm->flags |= FO_SYNTH_BOLD;
1997 } else if( pfi->df.dfWeight >= FW_BOLD ) penalty++; /* choose normal by default */
1999 if( plf->lfItalic != pfi->df.dfItalic )
2002 pfm->flags |= FO_SYNTH_ITALIC;
2005 if( plf->lfUnderline ) pfm->flags |= FO_SYNTH_UNDERLINE;
2006 if( plf->lfStrikeOut ) pfm->flags |= FO_SYNTH_STRIKEOUT;
2008 if( penalty && pfi->lfd_resolution != DefResolution )
2011 TRACE(font," returning %i\n", penalty );
2016 /***********************************************************************
2019 * Scan a particular font resource for the best match.
2021 static UINT XFONT_MatchFIList( fontMatch* pfm )
2023 BOOL skipRaster = (pfm->flags & FO_MATCH_NORASTER);
2024 UINT current_score, score = (UINT)(-1);
2025 UINT16 origflags = pfm->flags; /* Preserve FO_MATCH_XYINDEP */
2026 fontMatch fm = *pfm;
2028 for( fm.pfi = pfm->pfr->fi; fm.pfi && score; fm.pfi = fm.pfi->next,
2029 fm.flags = origflags )
2031 if( skipRaster && !(fm.pfi->fi_flags & FI_SCALABLE) )
2034 current_score = XFONT_Match( &fm );
2035 if( score > current_score )
2037 memcpy( pfm, &fm, sizeof(fontMatch) );
2038 score = current_score;
2044 /***********************************************************************
2047 * REMOVE_SUBSETS - attach new fi and purge subsets
2048 * UNMARK_SUBSETS - remove subset flags from all fi entries
2050 static void XFONT_CheckFIList( fontResource* fr, fontInfo* fi, int action)
2053 fontInfo* pfi, *prev;
2055 for( prev = NULL, pfi = fr->fi; pfi; )
2057 if( action == REMOVE_SUBSETS )
2059 if( pfi->fi_flags & FI_SUBSET )
2061 fontInfo* subset = pfi;
2065 if( prev ) prev->next = pfi = pfi->next;
2066 else fr->fi = pfi = pfi->next;
2067 HeapFree( SystemHeap, 0, subset );
2071 else pfi->fi_flags &= ~FI_SUBSET;
2077 if( action == REMOVE_SUBSETS ) /* also add the superset */
2079 if( fi->fi_flags & FI_SCALABLE )
2084 else if( prev ) prev->next = fi; else fr->fi = fi;
2088 if( i ) TRACE(font,"\t purged %i subsets [%i]\n", i , fr->fi_count);
2091 /***********************************************************************
2094 static fontResource* XFONT_FindFIList( fontResource* pfr, const char* pTypeFace )
2098 if( !strcasecmp( pfr->lfFaceName, pTypeFace ) ) break;
2104 /***********************************************************************
2105 * XFONT_MatchDeviceFont
2107 * Scan font resource tree.
2109 static BOOL XFONT_MatchDeviceFont( fontResource* start, fontMatch* pfm )
2111 fontResource** ppfr;
2112 fontMatch fm = *pfm;
2115 if( fm.plf->lfFaceName[0] )
2120 for( fa = aliasTable; fa; fa = fa->next )
2121 if( !strcmp( fa->faAlias, fm.plf->lfFaceName ) )
2123 str = fa->faTypeFace;
2126 fm.pfr = XFONT_FindFIList( start, str ? str : fm.plf->lfFaceName );
2129 if( fm.pfr ) /* match family */
2131 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2133 if( fm.pfr->fr_flags & FR_REMOVED )
2137 XFONT_MatchFIList( &fm );
2142 if( !pfm->pfi ) /* match all available fonts */
2144 UINT current_score, score = (UINT)(-1);
2146 fm.flags |= FO_MATCH_PAF;
2147 for( ppfr = &fontList; *ppfr && score; ppfr = &(*ppfr)->next )
2149 if( (*ppfr)->fr_flags & FR_REMOVED )
2151 if( (*ppfr)->fo_count == 0 )
2152 XFONT_RemoveFontResource( ppfr );
2158 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2160 current_score = XFONT_MatchFIList( &fm );
2161 if( current_score < score )
2163 score = current_score;
2172 /***********************************************************************
2175 static void XFONT_GrowFreeList(int start, int end)
2177 /* add all entries from 'start' up to and including 'end' */
2179 memset( fontCache + start, 0, (end - start + 1) * sizeof(fontObject) );
2181 fontCache[end].lru = fontLF;
2182 fontCache[end].count = -1;
2184 while( start < end )
2186 fontCache[start].count = -1;
2187 fontCache[start].lru = start + 1;
2192 static fontObject* XFONT_LookupCachedFont( LPLOGFONT16 plf, UINT16* checksum )
2194 UINT16 cs = __lfCheckSum( plf );
2195 int i = fontMRU, prev = -1;
2200 if( fontCache[i].lfchecksum == cs &&
2201 !(fontCache[i].fo_flags & FO_REMOVED) )
2203 /* FIXME: something more intelligent here */
2205 if( !memcmp( plf, &fontCache[i].lf,
2206 sizeof(LOGFONT16) - LF_FACESIZE ) &&
2207 !strncasecmp( plf->lfFaceName, fontCache[i].lf.lfFaceName,
2210 /* remove temporarily from the lru list */
2213 fontCache[prev].lru = fontCache[i].lru;
2215 fontMRU = (INT16)fontCache[i].lru;
2216 return (fontCache + i);
2220 i = (INT16)fontCache[i].lru;
2225 static fontObject* XFONT_GetCacheEntry()
2231 int prev_i, prev_j, j;
2233 TRACE(font,"font cache is full\n");
2235 /* lookup the least recently used font */
2237 for( prev_i = prev_j = j = -1, i = fontMRU; i >= 0; i = (INT16)fontCache[i].lru )
2239 if( fontCache[i].count <= 0 &&
2240 !(fontCache[i].fo_flags & FO_SYSTEM) )
2248 if( j >= 0 ) /* unload font */
2250 /* detach from the lru list */
2252 TRACE(font,"\tfreeing entry %i\n", j );
2254 fontCache[j].fr->fo_count--;
2257 fontCache[prev_j].lru = fontCache[j].lru;
2258 else fontMRU = (INT16)fontCache[j].lru;
2260 /* FIXME: lpXForm, lpPixmap */
2261 if(fontCache[j].lpX11Trans)
2262 HeapFree( SystemHeap, 0, fontCache[j].lpX11Trans );
2264 TSXFreeFont( display, fontCache[j].fs );
2266 memset( fontCache + j, 0, sizeof(fontObject) );
2267 return (fontCache + j);
2269 else /* expand cache */
2271 fontObject* newCache;
2273 prev_i = fontCacheSize + FONTCACHE;
2275 TRACE(font,"\tgrowing font cache from %i to %i\n", fontCacheSize, prev_i );
2277 if( (newCache = (fontObject*)HeapReAlloc(SystemHeap, 0,
2278 fontCache, prev_i)) )
2281 fontCacheSize = prev_i;
2282 fontCache = newCache;
2283 XFONT_GrowFreeList( i, fontCacheSize - 1);
2289 /* detach from the free list */
2292 fontLF = (INT16)fontCache[i].lru;
2293 fontCache[i].count = 0;
2294 return (fontCache + i);
2297 static int XFONT_ReleaseCacheEntry(fontObject* pfo)
2299 UINT u = (UINT)(pfo - fontCache);
2301 if( u < fontCacheSize ) return (--fontCache[u].count);
2305 /**********************************************************************
2308 static BOOL XFONT_SetX11Trans( fontObject *pfo )
2314 TSXGetFontProperty( pfo->fs, XA_FONT, &nameAtom );
2315 fontName = TSXGetAtomName( display, nameAtom );
2316 cp = LFD_Advance( fontName, 7 );
2322 while((cp = strchr(cp, '~')))
2325 #define PX pfo->lpX11Trans
2327 sscanf(start, "[%f%f%f%f]", &PX->a, &PX->b, &PX->c, &PX->d);
2330 TSXGetFontProperty( pfo->fs, RAW_ASCENT, &PX->RAW_ASCENT );
2331 TSXGetFontProperty( pfo->fs, RAW_DESCENT, &PX->RAW_DESCENT );
2333 PX->pixelsize = hypot(PX->a, PX->b);
2334 PX->ascent = PX->pixelsize / 1000.0 * PX->RAW_ASCENT;
2335 PX->descent = PX->pixelsize / 1000.0 * PX->RAW_DESCENT;
2337 TRACE(font, "[%f %f %f %f] RA = %ld RD = %ld\n", pfo->lpX11Trans->a,
2338 pfo->lpX11Trans->b, pfo->lpX11Trans->c, pfo->lpX11Trans->d,
2339 pfo->lpX11Trans->RAW_ASCENT, pfo->lpX11Trans->RAW_DESCENT);
2345 /***********************************************************************
2346 * X Device Font Objects
2348 static X_PHYSFONT XFONT_RealizeFont( LPLOGFONT16 plf )
2351 fontObject* pfo = XFONT_LookupCachedFont( plf, &checksum );
2355 fontMatch fm = { NULL, NULL, 0, 0, plf};
2358 if( XTextCaps & TC_SF_X_YINDEP ) fm.flags = FO_MATCH_XYINDEP;
2360 /* allocate new font cache entry */
2362 if( (pfo = XFONT_GetCacheEntry()) )
2364 LPSTR lpLFD = HeapAlloc( GetProcessHeap(), 0, MAX_LFD_LENGTH );
2366 if( lpLFD ) /* initialize entry and load font */
2368 UINT uRelaxLevel = 0;
2370 TRACE(font,"(%u) '%s' h=%i weight=%i %s\n",
2371 plf->lfCharSet, plf->lfFaceName, plf->lfHeight,
2372 plf->lfWeight, (plf->lfItalic) ? "Italic" : "" );
2374 if(abs(plf->lfHeight) > MAX_FONT_SIZE) {
2376 "plf->lfHeight = %d, this is probably not right. Setting to 100\n",
2378 plf->lfHeight = 100;
2381 XFONT_MatchDeviceFont( fontList, &fm );
2385 pfo->fr->fo_count++;
2386 pfo->fo_flags = fm.flags & ~FO_MATCH_MASK;
2388 memcpy( &pfo->lf, plf, sizeof(LOGFONT16) );
2389 pfo->lfchecksum = checksum;
2393 LFD_ComposeLFD( pfo, fm.height, lpLFD, uRelaxLevel++ );
2394 if( (pfo->fs = TSXLoadQueryFont( display, lpLFD )) ) break;
2395 } while( uRelaxLevel );
2398 if(pfo->lf.lfEscapement != 0) {
2399 pfo->lpX11Trans = HeapAlloc(SystemHeap, 0,
2400 sizeof(XFONTTRANS));
2401 if(!XFONT_SetX11Trans( pfo )) {
2402 HeapFree(SystemHeap, 0, pfo->lpX11Trans);
2403 pfo->lpX11Trans = NULL;
2407 if( XFONT_GetLeading( &pfo->fi->df, pfo->fs, &i, NULL,
2410 if(!pfo->lpX11Trans)
2411 pfo->foAvgCharWidth =
2412 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].width;
2414 pfo->foAvgCharWidth =
2415 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].attributes
2416 * pfo->lpX11Trans->pixelsize / 1000.0;
2418 pfo->foAvgCharWidth = (INT16)XFONT_GetAvgCharWidth(
2419 &pfo->fi->df, pfo->fs, pfo->lpX11Trans );
2420 pfo->foMaxCharWidth = (INT16)XFONT_GetMaxCharWidth(pfo);
2421 pfo->foInternalLeading = (INT16)i;
2423 /* FIXME: If we've got a soft font or
2424 * there are FO_SYNTH_... flags for the
2425 * non PROOF_QUALITY request, the engine
2426 * should rasterize characters into mono
2427 * pixmaps and store them in the pfo->lpPixmap
2428 * array (pfo->fs should be updated as well).
2429 * array (pfo->fs should be updated as well).
2430 * X11DRV_ExtTextOut() must be heavily modified
2431 * to support pixmap blitting and FO_SYNTH_...
2435 pfo->lpPixmap = NULL;
2437 HeapFree( GetProcessHeap(), 0, lpLFD );
2439 else /* attach back to the free list */
2443 fontLF = (pfo - fontCache);
2448 if( !pfo ) /* couldn't get a new entry, get one of the cached fonts */
2450 UINT current_score, score = (UINT)(-1);
2452 i = index = fontMRU;
2453 fm.flags |= FO_MATCH_PAF;
2456 pfo = fontCache + i;
2457 fm.pfr = pfo->fr; fm.pfi = pfo->fi;
2459 current_score = XFONT_Match( &fm );
2460 if( current_score < score ) index = i;
2464 pfo = fontCache + index;
2466 return (X_PHYSFONT)(X_PFONT_MAGIC | index);
2470 /* attach at the head of the lru list */
2474 fontMRU = (pfo - fontCache);
2476 TRACE(font,"physfont %i\n", fontMRU);
2478 return (X_PHYSFONT)(X_PFONT_MAGIC | fontMRU);
2481 /***********************************************************************
2482 * XFONT_GetFontObject
2484 fontObject* XFONT_GetFontObject( X_PHYSFONT pFont )
2486 if( CHECK_PFONT(pFont) ) return __PFONT(pFont);
2490 /***********************************************************************
2491 * XFONT_GetFontStruct
2493 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
2495 if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
2499 /***********************************************************************
2502 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
2504 if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
2510 /* X11DRV Interface ****************************************************
2512 * Exposed via the dc->funcs dispatch table. *
2514 ***********************************************************************/
2515 /***********************************************************************
2516 * X11DRV_FONT_SelectObject
2518 HFONT X11DRV_FONT_SelectObject( DC* dc, HFONT hfont, FONTOBJ* font )
2520 HFONT hPrevFont = 0;
2522 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2524 EnterCriticalSection( &crtsc_fonts_X11 );
2526 if( CHECK_PFONT(physDev->font) )
2527 XFONT_ReleaseCacheEntry( __PFONT(physDev->font) );
2529 /* FIXME: do we need to pass anything back from here? */
2530 memcpy(&lf,&font->logfont,sizeof(lf));
2531 lf.lfWidth = font->logfont.lfWidth * dc->vportExtX/dc->wndExtX;
2532 lf.lfHeight = font->logfont.lfHeight* dc->vportExtY/dc->wndExtY;
2534 physDev->font = XFONT_RealizeFont( &lf );
2535 hPrevFont = dc->w.hFont;
2536 dc->w.hFont = hfont;
2538 LeaveCriticalSection( &crtsc_fonts_X11 );
2544 /***********************************************************************
2546 * X11DRV_EnumDeviceFonts
2548 BOOL X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf,
2549 DEVICEFONTENUMPROC proc, LPARAM lp )
2553 fontResource* pfr = fontList;
2556 if( plf->lfFaceName[0] )
2558 /* enum all entries in this resource */
2559 pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
2563 for( pfi = pfr->fi; pfi; pfi = pfi->next )
2565 /* Note: XFONT_GetFontMetric() will have to
2566 release the crit section, font list will
2567 have to be retraversed on return */
2569 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2570 XFONT_GetFontMetric( pfi, &lf, &tm ), lp )) )
2576 else /* enum first entry in each resource */
2577 for( ; pfr ; pfr = pfr->next )
2581 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2582 XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
2591 /***********************************************************************
2592 * X11DRV_GetTextExtentPoint
2594 BOOL X11DRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT count,
2597 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2598 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2600 if( !pfo->lpX11Trans ) {
2601 int dir, ascent, descent;
2604 TSXTextExtents( pfo->fs, str, count, &dir, &ascent, &descent, &info );
2605 size->cx = abs((info.width + dc->w.breakRem + count *
2606 dc->w.charExtra) * dc->wndExtX / dc->vportExtX);
2607 size->cy = abs((pfo->fs->ascent + pfo->fs->descent) *
2608 dc->wndExtY / dc->vportExtY);
2612 float x = 0.0, y = 0.0;
2613 for(i = 0; i < count; i++) {
2614 x += pfo->fs->per_char ?
2615 pfo->fs->per_char[str[i] - pfo->fs->min_char_or_byte2].attributes :
2616 pfo->fs->min_bounds.attributes;
2618 y = pfo->lpX11Trans->RAW_ASCENT + pfo->lpX11Trans->RAW_DESCENT;
2619 TRACE(font, "x = %f y = %f\n", x, y);
2620 x *= pfo->lpX11Trans->pixelsize / 1000.0;
2621 y *= pfo->lpX11Trans->pixelsize / 1000.0;
2622 size->cx = fabsf((x + dc->w.breakRem + count * dc->w.charExtra) *
2623 dc->wndExtX / dc->vportExtX);
2624 size->cy = fabsf(y * dc->wndExtY / dc->vportExtY);
2632 /***********************************************************************
2633 * X11DRV_GetTextMetrics
2635 BOOL X11DRV_GetTextMetrics(DC *dc, TEXTMETRICA *metrics)
2637 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2639 if( CHECK_PFONT(physDev->font) )
2641 fontObject* pfo = __PFONT(physDev->font);
2642 XFONT_GetTextMetric( pfo, metrics );
2650 /***********************************************************************
2651 * X11DRV_GetCharWidth
2653 BOOL X11DRV_GetCharWidth( DC *dc, UINT firstChar, UINT lastChar,
2656 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2657 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2663 if (pfo->fs->per_char == NULL)
2664 for (i = firstChar; i <= lastChar; i++)
2666 *buffer++ = pfo->fs->min_bounds.attributes *
2667 pfo->lpX11Trans->pixelsize / 1000.0;
2669 *buffer++ = pfo->fs->min_bounds.width;
2672 XCharStruct *cs, *def;
2673 static XCharStruct __null_char = { 0, 0, 0, 0, 0, 0 };
2675 CI_GET_CHAR_INFO(pfo->fs, pfo->fs->default_char, &__null_char,
2678 for (i = firstChar; i <= lastChar; i++)
2680 if (i >= pfo->fs->min_char_or_byte2 &&
2681 i <= pfo->fs->max_char_or_byte2)
2683 cs = &pfo->fs->per_char[(i - pfo->fs->min_char_or_byte2)];
2684 if (CI_NONEXISTCHAR(cs)) cs = def;
2687 *buffer++ = MAX(cs->attributes, 0) *
2688 pfo->lpX11Trans->pixelsize / 1000.0;
2690 *buffer++ = MAX(cs->width, 0 );
2699 #endif /* !defined(X_DISPLAY_MISSING) */
2701 /***********************************************************************
2703 * Font Resource API *
2705 ***********************************************************************/
2706 /***********************************************************************
2707 * AddFontResource16 (GDI.119)
2709 * Can be either .FON, or .FNT, or .TTF, or .FOT font file.
2711 * FIXME: Load header and find the best-matching font in the fontList;
2712 * fixup dfPoints if all metrics are identical, otherwise create
2713 * new fontAlias. When soft font support is ready this will
2714 * simply create a new fontResource ('filename' will go into
2715 * the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE
2718 INT16 WINAPI AddFontResource16( LPCSTR filename )
2720 return AddFontResourceA( filename );
2724 /***********************************************************************
2725 * AddFontResource32A (GDI32.2)
2727 INT WINAPI AddFontResourceA( LPCSTR str )
2729 FIXME(font, "(%s): stub\n", debugres_a(str));
2734 /***********************************************************************
2735 * AddFontResource32W (GDI32.4)
2737 INT WINAPI AddFontResourceW( LPCWSTR str )
2739 FIXME(font, "(%s): stub\n", debugres_w(str) );
2743 /***********************************************************************
2744 * RemoveFontResource16 (GDI.136)
2746 BOOL16 WINAPI RemoveFontResource16( SEGPTR str )
2748 FIXME(font, "(%s): stub\n", debugres_a(PTR_SEG_TO_LIN(str)));
2753 /***********************************************************************
2754 * RemoveFontResource32A (GDI32.284)
2756 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
2758 /* This is how it should look like */
2760 fontResource** ppfr;
2761 BOOL32 retVal = FALSE;
2763 EnterCriticalSection( &crtsc_fonts_X11 );
2764 for( ppfr = &fontList; *ppfr; ppfr = &(*ppfr)->next )
2765 if( !strcasecmp( (*ppfr)->lfFaceName, str ) )
2767 if(((*ppfr)->fr_flags & (FR_SOFTFONT | FR_SOFTRESOURCE)) &&
2768 (*ppfr)->hOwnerProcess == GetCurrentProcess() )
2770 if( (*ppfr)->fo_count )
2771 (*ppfr)->fr_flags |= FR_REMOVED;
2773 XFONT_RemoveFontResource( ppfr );
2777 LeaveCriticalSection( &crtsc_fontList );
2780 FIXME(font, "(%s): stub\n", debugres_a(str));
2785 /***********************************************************************
2786 * RemoveFontResource32W (GDI32.286)
2788 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
2790 FIXME(font, "(%s): stub\n", debugres_w(str) );