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) */
23 #include <sys/types.h>
35 DEFAULT_DEBUG_CHANNEL(font)
37 #ifndef X_DISPLAY_MISSING
39 #define X_PFONT_MAGIC (0xFADE0000)
40 #define X_FMC_MAGIC (0x0000CAFE)
42 #define MAX_FONT_FAMILIES 128
43 #define MAX_LFD_LENGTH 256
45 #define MAX_FONT_SIZE 1000 /* Max size in pixels */
47 #define REMOVE_SUBSETS 1
48 #define UNMARK_SUBSETS 0
50 #define DEF_SCALABLE_HEIGHT 24
51 #define DEF_SCALABLE_DP 240
53 #define FF_FAMILY (FF_MODERN | FF_SWISS | FF_ROMAN | FF_DECORATIVE | FF_SCRIPT)
55 typedef struct __fontAlias
59 struct __fontAlias* next;
68 /* Font alias table - these 2 aliases are always present */
69 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
71 static fontAlias __aliasTable[2] = {
72 { NULL, "Helv", &__aliasTable[1] },
73 { NULL, "Tms Rmn", NULL }
76 static fontAlias *aliasTable = __aliasTable;
78 /* Optional built-in aliases, they are installed only when X
79 * cannot supply us with original MS fonts */
80 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
82 static int faTemplateNum = 4;
83 static aliasTemplate faTemplate[4] = {
84 { NULL, "MS Sans Serif" },
86 { "-adobe-times-", "Times New Roman" },
87 { "-adobe-helvetica-", "Arial" }
90 UINT16 XTextCaps = TC_OP_CHARACTER | TC_OP_STROKE |
91 TC_CP_STROKE | TC_CR_ANY |
92 TC_SA_DOUBLE | TC_SA_INTEGER | TC_SA_CONTIN |
93 TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
95 /* X11R6 adds TC_SF_X_YINDEP, maybe more... */
97 static const char* INIWinePrefix = "/.wine";
98 static const char* INIFontMetrics = "/.cachedmetrics.";
99 static const char* INIFontSection = "fonts";
100 static const char* INIAliasSection = "Alias";
101 static const char* INIIgnoreSection = "Ignore";
102 static const char* INIDefault = "Default";
103 static const char* INIDefaultFixed = "DefaultFixed";
104 static const char* INIResolution = "Resolution";
105 static const char* INIGlobalMetrics = "FontMetrics";
106 static const char* INIDefaultSerif = "DefaultSerif";
107 static const char* INIDefaultSansSerif = "DefaultSansSerif";
109 static const char* LFDSeparator = "*-";
111 /* suffix tables, must be less than 254 entries long */
113 static LPSTR suffx_iso[] = { "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8",
114 "-9", "-10", "-11", "-12", "-13", "-14", "-15", NULL };
115 static LPSTR suffx_iso646[] = { "-irv", NULL };
116 static LPSTR suffx_microsoft[] = { "-cp1252", "-cp1251", "-cp1250", "-cp1253", "-cp1254", "-cp1255",
117 "-cp1256", "-cp1257", "-fontspecific", "-symbol", NULL };
118 static LPSTR suffx_viscii[] = { "-1", NULL };
119 static LPSTR suffx_ansi[] = { "-0", NULL };
120 static LPSTR suffx_koi8[] = { "-ru", "-r", NULL };
121 static LPSTR suffx_null[] = { NULL };
123 /* charset mapping tables, have to have the same number of entries as corresponding suffix tables */
125 static BYTE chset_iso8859[] = { ANSI_CHARSET, EE_CHARSET, ISO3_CHARSET, ISO4_CHARSET, RUSSIAN_CHARSET,
126 ARABIC_CHARSET, GREEK_CHARSET, HEBREW_CHARSET, TURKISH_CHARSET, BALTIC_CHARSET,
127 THAI_CHARSET, SYMBOL_CHARSET, SYMBOL_CHARSET, SYMBOL_CHARSET, ANSI_CHARSET,
129 static BYTE chset_iso646[] = { ANSI_CHARSET, SYMBOL_CHARSET };
130 static BYTE chset_microsoft[] = { ANSI_CHARSET, RUSSIAN_CHARSET, EE_CHARSET, GREEK_CHARSET, TURKISH_CHARSET,
131 HEBREW_CHARSET, ARABIC_CHARSET, BALTIC_CHARSET, SYMBOL_CHARSET, SYMBOL_CHARSET,
133 static BYTE chset_ansi[] = { ANSI_CHARSET, ANSI_CHARSET };
134 static BYTE chset_koi8[] = { KOI8_CHARSET, KOI8_CHARSET, KOI8_CHARSET };
135 static BYTE chset_tcvn[] = { TCVN_CHARSET, TCVN_CHARSET };
136 static BYTE chset_tis620[] = { THAI_CHARSET, THAI_CHARSET };
137 static BYTE chset_fontspecific[] = { SYMBOL_CHARSET };
138 static BYTE chset_viscii[] = { VISCII_CHARSET, VISCII_CHARSET };
146 } fontEncodingTemplate;
148 /* Note: we can attach additional encoding mappings to the end
149 * of this table at runtime.
152 static fontEncodingTemplate __fETTable[10] = {
153 { "iso8859", &suffx_iso, &chset_iso8859, &__fETTable[1] },
154 { "iso646.1991", &suffx_iso646, &chset_iso646, &__fETTable[2] },
155 { "microsoft", &suffx_microsoft, &chset_microsoft, &__fETTable[3] },
156 { "ansi", &suffx_ansi, &chset_ansi, &__fETTable[4] },
157 { "ascii", &suffx_ansi, &chset_ansi, &__fETTable[5] },
158 { "fontspecific", &suffx_null, &chset_fontspecific, &__fETTable[6] },
159 { "koi8", &suffx_koi8, &chset_koi8, &__fETTable[7] },
160 { "tcvn", &suffx_ansi, &chset_tcvn, &__fETTable[8] },
161 { "tis620.2533", &suffx_ansi, &chset_tis620, &__fETTable[9] },
162 { "viscii1.1", &suffx_viscii, &chset_viscii, NULL }
164 static fontEncodingTemplate* fETTable = __fETTable;
166 static unsigned DefResolution = 0;
168 static CRITICAL_SECTION crtsc_fonts_X11;
170 static fontResource* fontList = NULL;
171 static fontObject* fontCache = NULL; /* array */
172 static int fontCacheSize = FONTCACHE;
173 static int fontLF = -1, fontMRU = -1; /* last free, most recently used */
175 #define __PFONT(pFont) ( fontCache + ((UINT)(pFont) & 0x0000FFFF) )
176 #define CHECK_PFONT(pFont) ( (((UINT)(pFont) & 0xFFFF0000) == X_PFONT_MAGIC) &&\
177 (((UINT)(pFont) & 0x0000FFFF) < fontCacheSize) )
179 static INT XFONT_IsSubset(fontInfo*, fontInfo*);
180 static void XFONT_CheckFIList(fontResource*, fontInfo*, int subset_action);
181 static void XFONT_GrowFreeList(int start, int end);
182 static void XFONT_RemoveFontResource(fontResource** ppfr);
185 static Atom RAW_ASCENT;
186 static Atom RAW_DESCENT;
188 /***********************************************************************
189 * Helper macros from X distribution
192 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
193 (((cs)->rbearing|(cs)->lbearing| \
194 (cs)->ascent|(cs)->descent) == 0))
196 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
199 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
200 if (fs->per_char == NULL) { \
201 cs = &fs->min_bounds; \
203 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
204 if (CI_NONEXISTCHAR(cs)) cs = def; \
209 #define CI_GET_DEFAULT_INFO(fs,cs) \
210 CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
212 /***********************************************************************
215 static UINT16 __lfCheckSum( LPLOGFONT16 plf )
217 CHAR font[LF_FACESIZE];
221 #define ptr ((UINT16*)plf)
222 for( i = 0; i < 9; i++ ) checksum ^= *ptr++;
225 #define ptr ((CHAR*)plf)
226 do { font[i++] = tolower(*ptr++); } while (( i < LF_FACESIZE) && (*ptr) && (*ptr!=' '));
227 for( ptr = font, i >>= 1; i > 0; i-- )
229 #define ptr ((UINT16*)plf)
235 static UINT16 __genericCheckSum( const void *ptr, int size )
237 unsigned int checksum = 0;
238 const char *p = (const char *)ptr;
240 checksum ^= (checksum << 3) + (checksum >> 29) + *p++;
242 return checksum & 0xffff;
245 /*************************************************************************
246 * LFD parse/compose routines
248 static char* LFD_Advance(LPSTR lpFont, UINT16 uParmsNo)
253 for( ; j < uParmsNo && *lpch; lpch++ ) if( *lpch == LFDSeparator[1] ) j++;
257 static void LFD_GetWeight( fontInfo* fi, LPSTR lpStr, int j)
259 if( j == 1 && *lpStr == '0' )
260 fi->fi_flags |= FI_POLYWEIGHT;
263 if( !strncasecmp( "bold", lpStr, 4) )
264 fi->df.dfWeight = FW_BOLD;
265 else if( !strncasecmp( "demi", lpStr, 4) )
267 fi->fi_flags |= FI_FW_DEMI;
268 fi->df.dfWeight = FW_DEMIBOLD;
270 else if( !strncasecmp( "book", lpStr, 4) )
272 fi->fi_flags |= FI_FW_BOOK;
273 fi->df.dfWeight = FW_REGULAR;
278 if( !strncasecmp( "light", lpStr, 5) )
279 fi->df.dfWeight = FW_LIGHT;
280 else if( !strncasecmp( "black", lpStr, 5) )
281 fi->df.dfWeight = FW_BLACK;
283 else if( j == 6 && !strncasecmp( "medium", lpStr, 6) )
284 fi->df.dfWeight = FW_REGULAR;
285 else if( j == 8 && !strncasecmp( "demibold", lpStr, 8) )
286 fi->df.dfWeight = FW_DEMIBOLD;
288 fi->df.dfWeight = FW_DONTCARE; /* FIXME: try to get something
289 * from the weight property */
292 static int LFD_GetSlant( fontInfo* fi, LPSTR lpStr, int l)
296 switch( tolower( *lpStr ) )
298 case '0': fi->fi_flags |= FI_POLYSLANT; /* haven't seen this one yet */
300 case 'r': fi->df.dfItalic = 0;
303 fi->fi_flags |= FI_OBLIQUE;
304 case 'i': fi->df.dfItalic = 1;
312 /*************************************************************************
317 * Fill in some fields in the fontInfo struct.
319 static int LFD_InitFontInfo( fontInfo* fi, LPSTR lpstr )
322 int i, j, dec_style_check, scalability;
324 fontEncodingTemplate* boba;
326 memset(fi, 0, sizeof(fontInfo) );
329 lpch = LFD_Advance( lpstr, 1);
330 if( !*lpch ) return FALSE;
331 j = lpch - lpstr - 1;
332 LFD_GetWeight( fi, lpstr, j );
335 lpch = LFD_Advance( lpstr = lpch, 1);
336 if( !*lpch ) return FALSE;
337 j = lpch - lpstr - 1;
338 dec_style_check = LFD_GetSlant( fi, lpstr, j );
341 lpch = LFD_Advance( lpstr = lpch, 1);
342 if( !*lpch ) return FALSE;
343 if( strncasecmp( "normal", lpstr, 6) ) /* XXX 'narrow', 'condensed', etc... */
344 dec_style_check = TRUE;
346 fi->fi_flags |= FI_NORMAL;
349 lpch = LFD_Advance( lpstr = lpch, 1);
350 if( !*lpch ) return FALSE;
351 j = lpch - lpstr - 1;
352 if( j > 3 ) /* find out is there "sans" or "script" */
357 if( strstr(lpstr, "sans") )
359 fi->df.dfPitchAndFamily |= FF_SWISS;
362 if( strstr(lpstr, "script") )
364 fi->df.dfPitchAndFamily |= FF_SCRIPT;
367 if( !j && dec_style_check )
368 fi->df.dfPitchAndFamily |= FF_DECORATIVE;
369 *(lpch - 1) = LFDSeparator[1];
372 /* pixel height, decipoint height, and res_x */
374 for( i = scalability = 0; i < 3; i++ )
376 lpch = LFD_Advance( lpstr = lpch, 1);
377 if( !*lpch ) return FALSE;
378 if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
381 if( !(tmp[i] = atoi(lpstr)) ) scalability++;
382 *(lpch - 1) = LFDSeparator[1];
384 if( scalability == 3 ) /* Type1 */
386 fi->fi_flags |= FI_SCALABLE;
387 fi->lfd_height = DEF_SCALABLE_HEIGHT; fi->lfd_decipoints = DEF_SCALABLE_DP;
388 fi->lfd_resolution = DefResolution;
390 else if( scalability == 0 ) /* Bitmap */
392 fi->lfd_height = tmp[0]; fi->lfd_decipoints = tmp[1];
393 fi->lfd_resolution = tmp[2];
395 else return FALSE; /* #$%^!!! X11R6 mutant garbage */
397 /* res_y - skip, spacing - */
398 lpstr = LFD_Advance( lpch, 1);
401 case '\0': return FALSE;
403 case 'p': fi->fi_flags |= FI_VARIABLEPITCH;
405 case 'c': fi->df.dfPitchAndFamily |= FF_MODERN;
406 fi->fi_flags |= FI_FIXEDEX;
408 case 'm': fi->fi_flags |= FI_FIXEDPITCH;
411 fi->df.dfPitchAndFamily |= DEFAULT_PITCH | FF_DONTCARE;
413 lpstr = LFD_Advance(lpstr, 1);
414 if( !*lpstr ) return FALSE;
416 /* average width - */
417 lpch = LFD_Advance( lpstr, 1);
418 if( !*lpch ) return FALSE;
419 if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
421 if( !(fi->lfd_width = atoi(lpstr)) && !scalability ) return FALSE;
422 *(lpch - 1) = LFDSeparator[1];
424 /* charset registry, charset encoding - */
425 if( strstr(lpch, "jisx") ||
426 strstr(lpch, "ksc") ||
427 strstr(lpch, "gb2312") ||
428 strstr(lpch, "big5") ||
429 strstr(lpch, "unicode") ) return FALSE; /* 2-byte stuff */
431 fi->df.dfCharSet = ANSI_CHARSET;
433 for( i = 0, boba = fETTable; boba; boba = boba->next, i++ )
435 tmp[0] = strlen( boba->prefix );
436 if( !strncasecmp( lpch, boba->prefix, tmp[0] ) )
438 if( lpch[tmp[0]] == '-' )
440 lpstr = lpch + tmp[0];
441 for( j = 0; (*(boba->psuffix))[j]; j++ )
443 tmp[1] = strlen( (*(boba->psuffix))[j] );
444 if( !strncasecmp( lpstr, (*(boba->psuffix))[j], tmp[1] ) )
446 fi->df.dfCharSet = (*(boba->pcharset))[j];
450 /* Note : LFD_ComposeLFD will produce 'prefix-*' encoding *
451 * if (*(boba->psuffix))[j] is NULL here */
455 for( j = 0; (*(boba->psuffix))[j] ; j++ );
456 fi->df.dfCharSet = (*(boba->pcharset))[j];
457 j = lpch[tmp[0]] ? 254 : 255;
462 if( !boba ) return FALSE;
464 /* i - index into fETTable
465 * j - index into suffix array for fETTable[i]
467 * 254 - weird suffix (i.e. no '-' right after prefix )
468 * 255 - no suffix at all.
471 fi->fi_encoding = 256 * (UINT16)i + (UINT16)j;
477 /*************************************************************************
480 * Note: uRelax is a treatment not a cure. Font mapping algorithm
481 * should be bulletproof enough to allow us to avoid hacks like
482 * if( uRelax == 200 ) even despite LFD being so braindead.
484 static BOOL LFD_ComposeLFD( fontObject* fo,
485 INT height, LPSTR lpLFD, UINT uRelax )
487 fontEncodingTemplate* boba;
488 int i, h, w, ch, point = 0;
491 char h_string[64], point_string[64];
493 *(lpLFD+MAX_LFD_LENGTH-1)=0;
494 lstrcpyA( lpLFD, fo->fr->resource );
497 switch( fo->fi->df.dfWeight )
500 strcat( lpLFD, "bold" ); break;
502 if( fo->fi->fi_flags & FI_FW_BOOK )
503 strcat( lpLFD, "book" );
505 strcat( lpLFD, "medium" );
508 strcat( lpLFD, "demi" );
509 if( !( fo->fi->fi_flags & FI_FW_DEMI) )
510 strcat ( lpLFD, "bold" );
513 strcat( lpLFD, "black" ); break;
515 strcat( lpLFD, "light" ); break;
517 strcat( lpLFD, "*" );
521 if( fo->fi->df.dfItalic )
522 if( fo->fi->fi_flags & FI_OBLIQUE )
523 strcat( lpLFD, "-o" );
525 strcat( lpLFD, "-i" );
527 strcat( lpLFD, (uRelax < 2) ? "-r" : "-*" );
529 /* add width style and skip serifs */
530 if( fo->fi->fi_flags & FI_NORMAL )
531 strcat( lpLFD, "-normal-*-");
533 strcat( lpLFD, "-*-*-" );
535 /* add pixelheight, pointheight, and resolution
537 * FIXME: fill in lpXForm and lpPixmap for rotated fonts
539 if( fo->fo_flags & FO_SYNTH_HEIGHT ) h = fo->fi->lfd_height;
540 else h = (fo->fi->lfd_height * height) / fo->fi->df.dfPixHeight;
542 if( XTextCaps & TC_SF_X_YINDEP )
544 if( fo->lf.lfWidth && !(fo->fo_flags & FO_SYNTH_WIDTH) )
545 point = (fo->fi->lfd_decipoints * fo->lf.lfWidth) / fo->fi->df.dfAvgWidth;
547 if( fo->fi->fi_flags & FI_SCALABLE ) /* adjust h/w ratio */
548 point = h * 72 * 10 / fo->fi->lfd_resolution;
551 /* handle rotated fonts */
552 if (fo->lf.lfEscapement) {
553 /* escapement is in tenths of degrees, theta is in radians */
554 double theta = M_PI*fo->lf.lfEscapement/1800.;
556 double point_matrix[4];
558 h_matrix[0] = h*cos(theta);
559 h_matrix[1] = h*sin(theta);
560 h_matrix[2] = -h*sin(theta);
561 h_matrix[3] = h*cos(theta);
562 point_matrix[0] = point*cos(theta);
563 point_matrix[1] = point*sin(theta);
564 point_matrix[2] = -point*sin(theta);
565 point_matrix[3] = point*cos(theta);
566 sprintf(h_string, "[%+f%+f%+f%+f]", h_matrix[0], h_matrix[1], h_matrix[2], h_matrix[3]);
567 sprintf(point_string, "[%+f%+f%+f%+f]", point_matrix[0], point_matrix[1], point_matrix[2], point_matrix[3]);
568 while ((s = strchr(h_string, '-'))) *s='~';
569 while ((s = strchr(point_string, '-'))) *s='~';
571 sprintf(h_string, "%d", h);
572 sprintf(point_string, "%d", point);
576 /* spacing and width */
578 if( fo->fi->fi_flags & FI_FIXEDPITCH )
579 w = ( fo->fi->fi_flags & FI_FIXEDEX ) ? 'c' : 'm';
581 w = ( fo->fi->fi_flags & FI_VARIABLEPITCH ) ? 'p' : LFDSeparator[0];
585 i = fo->fi->fi_encoding >> 8;
586 for( boba = fETTable; i; i--, boba = boba->next );
588 strcpy( lpEncoding, boba->prefix );
590 i = fo->fi->fi_encoding & 255;
593 case 254: strcat( lpEncoding, "*" );
597 if( (*(boba->psuffix))[i] )
598 strcat( lpEncoding, (*(boba->psuffix))[i] );
600 strcat( lpEncoding, "-*" );
603 case 255: /* no suffix */
607 lpch = lpLFD + lstrlenA(lpLFD);
608 ch = (fo->fi->fi_flags & FI_SCALABLE) ? '0' : LFDSeparator[0];
612 /* RealizeFont() will call us repeatedly with increasing uRelax
613 * until XLoadFont() succeeds. */
618 sprintf( lpch, "%s-%s-%i-%c-%c-*-%s", h_string,
620 fo->fi->lfd_resolution, ch, w, lpEncoding );
626 case 2: /* 2 will have replaced an 'r' in slant by '*' */
627 sprintf( lpch, "%s-*-%i-%c-%c-*-%s", h_string,
628 fo->fi->lfd_resolution, ch, w, lpEncoding );
632 sprintf( lpch, "%s-*-%i-%c-*-*-%s",
633 h_string, fo->fi->lfd_resolution, ch, lpEncoding );
637 sprintf( lpch, "%i-*-%i-%c-*-*-%s", fo->fi->lfd_height,
638 fo->fi->lfd_resolution, ch, lpEncoding );
642 sprintf( lpch, "%i-*-*-*-*-*-%s", fo->fi->lfd_height, lpEncoding );
646 sprintf( lpch, "%i-*-*-*-*-*-*-*", fo->fi->lfd_height);
649 /* to avoid an infinite loop; those will allways match */
651 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1" );
654 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" );
658 TRACE(font,"\tLFD(uRelax=%d): %s\n", uRelax, lpLFD );
659 assert(*(lpLFD+MAX_LFD_LENGTH-1)==0); /* check if overwrittem */
664 /***********************************************************************
667 * font info - http://www.microsoft.com/kb/articles/q65/1/23.htm
668 * Windows font metrics - http://www.microsoft.com/kb/articles/q32/6/67.htm
670 static BOOL XFONT_GetLeading( LPIFONTINFO16 pFI, XFontStruct* x_fs, INT*
671 pIL, INT* pEL, XFONTTRANS *XFT )
673 unsigned long height;
674 unsigned min = (unsigned char)pFI->dfFirstChar;
675 unsigned max = (unsigned char)pFI->dfLastChar;
676 BOOL bHaveCapHeight = (pFI->dfCharSet == ANSI_CHARSET && 'X' >= min && 'X' <= max );
681 Atom RAW_CAP_HEIGHT = TSXInternAtom(display, "RAW_CAP_HEIGHT", TRUE);
682 if(TSXGetFontProperty(x_fs, RAW_CAP_HEIGHT, &height))
684 (INT)(XFT->pixelsize / 1000.0 * height);
687 return bHaveCapHeight && x_fs->per_char;
690 if( TSXGetFontProperty(x_fs, XA_CAP_HEIGHT, &height) == FALSE )
694 height = x_fs->per_char['X' - min].ascent;
696 if (x_fs->ascent >= x_fs->max_bounds.ascent)
697 height = x_fs->max_bounds.ascent;
700 height = x_fs->ascent;
702 *pEL = x_fs->max_bounds.ascent - height;
705 height = x_fs->min_bounds.ascent;
708 *pIL = x_fs->ascent - height;
709 return (bHaveCapHeight && x_fs->per_char);
712 static INT XFONT_GetAvgCharWidth( LPIFONTINFO16 pFI, XFontStruct* x_fs,
715 unsigned min = (unsigned char)pFI->dfFirstChar;
716 unsigned max = (unsigned char)pFI->dfLastChar;
721 for( j = 0, width = 0, chars = 0, max -= min; j <= max; j++ )
722 if( !CI_NONEXISTCHAR(x_fs->per_char + j) )
725 width += x_fs->per_char[j].width;
727 width += x_fs->per_char[j].attributes *
728 XFT->pixelsize / 1000.0;
731 return (width / chars);
734 return x_fs->min_bounds.width;
737 static INT XFONT_GetMaxCharWidth(fontObject *pfo)
739 unsigned min = (unsigned char)pfo->fs->min_char_or_byte2;
740 unsigned max = (unsigned char)pfo->fs->max_char_or_byte2;
743 return abs(pfo->fs->max_bounds.width);
745 if( pfo->fs->per_char )
748 for( j = 0, maxwidth = 0, max -= min; j <= max; j++ )
749 if( !CI_NONEXISTCHAR(pfo->fs->per_char + j) )
750 if(maxwidth < pfo->fs->per_char[j].attributes)
751 maxwidth = pfo->fs->per_char[j].attributes;
753 maxwidth *= pfo->lpX11Trans->pixelsize / 1000.0;
756 return pfo->foAvgCharWidth;
759 /***********************************************************************
760 * XFONT_SetFontMetric
764 * Initializes IFONTINFO16. dfHorizRes and dfVertRes must be already set.
766 static void XFONT_SetFontMetric(fontInfo* fi, fontResource* fr, XFontStruct* xfs)
771 fi->df.dfFirstChar = (BYTE)(min = xfs->min_char_or_byte2);
772 fi->df.dfLastChar = (BYTE)(max = xfs->max_char_or_byte2);
774 fi->df.dfDefaultChar = (BYTE)xfs->default_char;
775 fi->df.dfBreakChar = (BYTE)(( ' ' < min || ' ' > max) ? xfs->default_char: ' ');
777 fi->df.dfPixHeight = (INT16)((fi->df.dfAscent = (INT16)xfs->ascent) + xfs->descent);
778 fi->df.dfPixWidth = (xfs->per_char) ? 0 : xfs->min_bounds.width;
779 fi->df.dfMaxWidth = (INT16)abs(xfs->max_bounds.width);
781 if( XFONT_GetLeading( &fi->df, xfs, &il, &el, NULL ) )
782 fi->df.dfAvgWidth = (INT16)xfs->per_char['X' - min].width;
784 fi->df.dfAvgWidth = (INT16)XFONT_GetAvgCharWidth( &fi->df, xfs, NULL);
786 fi->df.dfInternalLeading = (INT16)il;
787 fi->df.dfExternalLeading = (INT16)el;
789 fi->df.dfPoints = (INT16)(((INT)(fi->df.dfPixHeight -
790 fi->df.dfInternalLeading) * 72 + (fi->df.dfVertRes >> 1)) / fi->df.dfVertRes);
792 if( xfs->min_bounds.width != xfs->max_bounds.width )
793 fi->df.dfPitchAndFamily |= TMPF_FIXED_PITCH; /* au contraire! */
794 if( fi->fi_flags & FI_SCALABLE )
796 fi->df.dfType = DEVICE_FONTTYPE;
797 fi->df.dfPitchAndFamily |= TMPF_DEVICE;
799 else if( fi->fi_flags & FI_TRUETYPE )
800 fi->df.dfType = TRUETYPE_FONTTYPE;
802 fi->df.dfType = RASTER_FONTTYPE;
804 fi->df.dfFace = fr->lfFaceName;
807 /***********************************************************************
808 * XFONT_GetTextMetric
810 * GetTextMetrics() back end.
812 static void XFONT_GetTextMetric( fontObject* pfo, LPTEXTMETRICA pTM )
814 LPIFONTINFO16 pdf = &pfo->fi->df;
816 if( ! pfo->lpX11Trans ) {
817 pTM->tmAscent = pfo->fs->ascent;
818 pTM->tmDescent = pfo->fs->descent;
820 pTM->tmAscent = pfo->lpX11Trans->ascent;
821 pTM->tmDescent = pfo->lpX11Trans->descent;
823 pTM->tmHeight = pTM->tmAscent + pTM->tmDescent;
825 pTM->tmAveCharWidth = pfo->foAvgCharWidth;
826 pTM->tmMaxCharWidth = pfo->foMaxCharWidth;
828 pTM->tmInternalLeading = pfo->foInternalLeading;
829 pTM->tmExternalLeading = pdf->dfExternalLeading;
831 pTM->tmStruckOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT )
832 ? 1 : pdf->dfStrikeOut;
833 pTM->tmUnderlined = (pfo->fo_flags & FO_SYNTH_UNDERLINE )
834 ? 1 : pdf->dfUnderline;
837 if( pfo->fo_flags & FO_SYNTH_ITALIC )
839 pTM->tmOverhang += pTM->tmHeight/3;
842 pTM->tmItalic = pdf->dfItalic;
844 pTM->tmWeight = pdf->dfWeight;
845 if( pfo->fo_flags & FO_SYNTH_BOLD )
848 pTM->tmWeight += 100;
851 *(INT*)&pTM->tmFirstChar = *(INT*)&pdf->dfFirstChar;
853 pTM->tmCharSet = pdf->dfCharSet;
854 pTM->tmPitchAndFamily = pdf->dfPitchAndFamily;
856 pTM->tmDigitizedAspectX = pdf->dfHorizRes;
857 pTM->tmDigitizedAspectY = pdf->dfVertRes;
860 /***********************************************************************
861 * XFONT_GetFontMetric
863 * Retrieve font metric info (enumeration).
865 static UINT XFONT_GetFontMetric( fontInfo* pfi, LPENUMLOGFONTEX16 pLF,
866 LPNEWTEXTMETRIC16 pTM )
868 memset( pLF, 0, sizeof(*pLF) );
869 memset( pTM, 0, sizeof(*pTM) );
871 #define plf ((LPLOGFONT16)pLF)
872 plf->lfHeight = pTM->tmHeight = pfi->df.dfPixHeight;
873 plf->lfWidth = pTM->tmAveCharWidth = pfi->df.dfAvgWidth;
874 plf->lfWeight = pTM->tmWeight = pfi->df.dfWeight;
875 plf->lfItalic = pTM->tmItalic = pfi->df.dfItalic;
876 plf->lfUnderline = pTM->tmUnderlined = pfi->df.dfUnderline;
877 plf->lfStrikeOut = pTM->tmStruckOut = pfi->df.dfStrikeOut;
878 plf->lfCharSet = pTM->tmCharSet = pfi->df.dfCharSet;
880 /* convert pitch values */
882 pTM->tmPitchAndFamily = pfi->df.dfPitchAndFamily;
883 plf->lfPitchAndFamily = (pfi->df.dfPitchAndFamily & 0xF1) + 1;
885 lstrcpynA( plf->lfFaceName, pfi->df.dfFace, LF_FACESIZE );
888 pTM->tmAscent = pfi->df.dfAscent;
889 pTM->tmDescent = pTM->tmHeight - pTM->tmAscent;
890 pTM->tmInternalLeading = pfi->df.dfInternalLeading;
891 pTM->tmMaxCharWidth = pfi->df.dfMaxWidth;
892 pTM->tmDigitizedAspectX = pfi->df.dfHorizRes;
893 pTM->tmDigitizedAspectY = pfi->df.dfVertRes;
895 *(INT*)&pTM->tmFirstChar = *(INT*)&pfi->df.dfFirstChar;
897 /* return font type */
899 return pfi->df.dfType;
903 /***********************************************************************
908 * dfPitchAndFamily flags for some common typefaces.
910 static BYTE XFONT_FixupFlags( LPCSTR lfFaceName )
912 switch( lfFaceName[0] )
915 case 'H': if(!strcasecmp(lfFaceName, "Helvetica") )
919 case 'C': if(!strcasecmp(lfFaceName, "Courier") ||
920 !strcasecmp(lfFaceName, "Charter") )
924 case 'P': if( !strcasecmp(lfFaceName,"Palatino") )
928 case 'T': if(!strncasecmp(lfFaceName, "Times", 5) )
932 case 'U': if(!strcasecmp(lfFaceName, "Utopia") )
936 case 'Z': if(!strcasecmp(lfFaceName, "Zapf Dingbats") )
937 return FF_DECORATIVE;
943 /***********************************************************************
944 * XFONT_CheckResourceName
948 static BOOL XFONT_CheckResourceName( LPSTR resource, LPCSTR name, INT n )
950 resource = LFD_Advance( resource, 2 );
952 return (!strncasecmp( resource, name, n ));
957 /***********************************************************************
962 * Build generic Windows aliases for X font names.
964 * -misc-fixed- -> "Fixed"
965 * -sony-fixed- -> "Sony Fixed", etc...
967 static void XFONT_WindowsNames( char* buffer )
969 fontResource* fr, *pfr;
973 const char* relocTable[3];
975 relocTable[0] = INIDefaultFixed;
976 relocTable[1] = INIDefault;
977 relocTable[2] = NULL;
979 for( fr = fontList; fr ; fr = fr->next )
981 if( fr->fr_flags & FR_NAMESET ) continue; /* skip already assigned */
983 lpstr = LFD_Advance(fr->resource, 2);
984 i = LFD_Advance( lpstr, 1 ) - lpstr;
986 for( pfr = fontList; pfr != fr ; pfr = pfr->next )
987 if( pfr->fr_flags & FR_NAMESET )
988 if( XFONT_CheckResourceName( pfr->resource, lpstr, i ) )
991 if( pfr != fr ) /* prepend vendor name */
992 lpstr = fr->resource + 1;
994 for( i = 0, up = 1, lpch = fr->lfFaceName; *lpstr && i < 32;
995 lpch++, lpstr++, i++ )
997 if( *lpstr == LFDSeparator[1] || *lpstr == ' ' )
1002 else if( isalpha(*lpstr) && up )
1004 *lpch = toupper(*lpstr);
1009 while (*(lpch - 1) == ' ') *(--lpch) = '\0';
1011 if( (bFamilyStyle = XFONT_FixupFlags( fr->lfFaceName )) )
1014 for( fi = fr->fi ; fi ; fi = fi->next )
1015 fi->df.dfPitchAndFamily |= bFamilyStyle;
1018 TRACE(font,"typeface \'%s\'\n", fr->lfFaceName);
1020 fr->fr_flags |= FR_NAMESET;
1023 for( up = 0; relocTable[up]; up++ )
1024 if( PROFILE_GetWineIniString( INIFontSection, relocTable[up], "", buffer, 128 ) )
1026 while( *buffer && isspace(*buffer) ) buffer++;
1027 for( fr = NULL, pfr = fontList; pfr; pfr = pfr->next )
1029 i = strlen( pfr->resource );
1030 if( !strncasecmp( pfr->resource, buffer, i) )
1034 fr->next = pfr->next;
1035 pfr->next = fontList;
1045 /***********************************************************************
1048 static fontAlias* XFONT_CreateAlias( LPCSTR lpTypeFace, LPCSTR lpAlias )
1051 fontAlias* pfa = aliasTable;
1055 /* check if we already got one */
1056 if( !strcasecmp( pfa->faTypeFace, lpAlias ) )
1058 TRACE(font,"\tredundant alias '%s' -> '%s'\n",
1059 lpAlias, lpTypeFace );
1062 if( pfa->next ) pfa = pfa->next;
1066 j = lstrlenA(lpTypeFace) + 1;
1067 pfa->next = HeapAlloc( SystemHeap, 0, sizeof(fontAlias) +
1068 j + lstrlenA(lpAlias) + 1 );
1069 if((pfa = pfa->next))
1072 pfa->faTypeFace = (LPSTR)(pfa + 1);
1073 lstrcpyA( pfa->faTypeFace, lpTypeFace );
1074 pfa->faAlias = pfa->faTypeFace + j;
1075 lstrcpyA( pfa->faAlias, lpAlias );
1077 TRACE(font, "\tadded alias '%s' for %s\n", lpAlias, lpTypeFace );
1084 /***********************************************************************
1087 * Read user-defined aliases from wine.conf. Format is as follows
1089 * Alias# = [Windows font name],[LFD font name], <substitute original name>
1092 * Alias0 = Arial, -adobe-helvetica-
1093 * Alias1 = Times New Roman, -bitstream-courier-, 1
1096 * Note that from 081797 and on we have built-in alias templates that take
1097 * care of the necessary Windows typefaces.
1099 static void XFONT_LoadAliases( char** buffer, int *buf_size )
1101 char* lpResource, *lpAlias;
1102 char subsection[32];
1104 BOOL bHaveAlias = TRUE, bSubst = FALSE;
1106 if( *buf_size < 128 )
1108 *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
1113 if( j < faTemplateNum )
1115 /* built-in templates first */
1117 lpResource = faTemplate[j].fatResource;
1118 lpAlias = faTemplate[j].fatAlias;
1123 /* then WINE.CONF */
1125 wsprintfA( subsection, "%s%i", INIAliasSection, i++ );
1127 if( (bHaveAlias = PROFILE_GetWineIniString( INIFontSection,
1128 subsection, "", *buffer, 128 )) )
1131 while( isspace(*lpAlias) ) lpAlias++;
1132 lpResource = PROFILE_GetStringItem( lpAlias );
1133 bSubst = (PROFILE_GetStringItem( lpResource )) ? TRUE : FALSE;
1141 length = strlen( lpAlias );
1142 if( lpResource && length )
1144 fontResource* fr, *frMatch = NULL;
1146 for (fr = fontList; fr ; fr = fr->next)
1148 if( !strcasecmp( fr->resource, lpResource ) ) frMatch = fr;
1149 if( XFONT_CheckResourceName( fr->resource, lpAlias, length ) )
1151 /* alias is not needed since the real font is present */
1152 frMatch = NULL; break;
1160 fontAlias *pfa, *prev = NULL;
1162 for(pfa = aliasTable; pfa; pfa = pfa->next)
1164 /* Remove lpAlias from aliasTable - we should free the old entry */
1165 if(!strcmp(lpAlias, pfa->faAlias))
1168 prev->next = pfa->next;
1170 aliasTable = pfa->next;
1173 /* Update any references to the substituted font in aliasTable */
1174 if(!strcmp(frMatch->lfFaceName,
1176 pfa->faTypeFace = HEAP_strdupA( SystemHeap, 0,
1181 TRACE(font, "\tsubstituted '%s' with %s\n",
1182 frMatch->lfFaceName, lpAlias );
1184 lstrcpynA( frMatch->lfFaceName, lpAlias, LF_FACESIZE );
1185 frMatch->fr_flags |= FR_NAMESET;
1189 /* create new entry in the alias table */
1190 XFONT_CreateAlias( frMatch->lfFaceName, lpAlias );
1194 else ERR(font, " malformed font alias '%s'\n", *buffer );
1200 /***********************************************************************
1201 * XFONT_LoadPenalties
1203 * Removes specified fonts from the font table to prevent Wine from
1206 * Ignore# = [LFD font name]
1209 * Ignore0 = -misc-nil-
1210 * Ignore1 = -sun-open look glyph-
1214 static void XFONT_LoadPenalties( char** buffer, int *buf_size )
1217 char subsection[32];
1219 if( *buf_size < 128 )
1221 *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
1227 wsprintfA( subsection, "%s%i", INIIgnoreSection, i++ );
1229 if( PROFILE_GetWineIniString( INIFontSection,
1230 subsection, "", *buffer, 255 ) )
1232 fontResource** ppfr;
1233 int length = strlen( *buffer );
1235 for( ppfr = &fontList; *ppfr ; ppfr = &((*ppfr)->next))
1237 if( !strncasecmp( (*ppfr)->resource, *buffer, length ) )
1239 TRACE(font, "Ignoring '%s'\n", (*ppfr)->resource );
1241 XFONT_RemoveFontResource( ppfr );
1251 /***********************************************************************
1252 * XFONT_UserMetricsCache
1254 * Returns expanded name for the ~/.wine/.cachedmetrics file.
1255 * Now it also appends the current value of the $DISPLAY varaible.
1257 static char* XFONT_UserMetricsCache( char* buffer, int* buf_size )
1259 char* pchDisplay, *home;
1261 pchDisplay = getenv( "DISPLAY" );
1262 if( !pchDisplay ) pchDisplay = "0";
1264 if ((home = getenv( "HOME" )) != NULL)
1266 int i = strlen( home ) + strlen( INIWinePrefix ) +
1267 strlen( INIFontMetrics ) + strlen( pchDisplay ) + 2;
1269 buffer = (char*) HeapReAlloc( SystemHeap, 0, buffer, *buf_size = i );
1270 strcpy( buffer, home );
1271 strcat( buffer, INIWinePrefix );
1272 strcat( buffer, INIFontMetrics );
1273 strcat( buffer, pchDisplay );
1274 } else buffer[0] = '\0';
1279 /***********************************************************************
1280 * XFONT_ReadCachedMetrics
1284 static BOOL XFONT_ReadCachedMetrics( int fd, int res, unsigned x_checksum, int x_count )
1291 /* read checksums */
1292 read( fd, &u, sizeof(unsigned) );
1293 read( fd, &i, sizeof(int) );
1295 if( u == x_checksum && i == x_count )
1297 off_t length, offset = 3 * sizeof(int);
1299 /* read total size */
1300 read( fd, &i, sizeof(int) );
1301 length = lseek( fd, 0, SEEK_END );
1303 if( length == (i + offset) )
1305 lseek( fd, offset, SEEK_SET );
1306 fontList = (fontResource*)HeapAlloc( SystemHeap, 0, i);
1309 fontResource* pfr = fontList;
1310 fontInfo* pfi = NULL;
1312 TRACE(font,"Reading cached font metrics:\n");
1314 read( fd, fontList, i); /* read all metrics at once */
1315 while( offset < length )
1317 offset += sizeof(fontResource) + sizeof(fontInfo);
1318 pfr->fi = pfi = (fontInfo*)(pfr + 1);
1322 if( offset > length ||
1323 (int)(pfi->next) != j++ ) goto fail;
1325 pfi->df.dfFace = pfr->lfFaceName;
1326 pfi->df.dfHorizRes = pfi->df.dfVertRes = res;
1327 pfi->df.dfPoints = (INT16)(((INT)(pfi->df.dfPixHeight -
1328 pfi->df.dfInternalLeading) * 72 + (res >> 1)) / res );
1329 pfi->next = pfi + 1;
1331 if( j > pfr->fi_count ) break;
1334 offset += sizeof(fontInfo);
1339 pfr->next = (fontResource*)(pfi + 1);
1344 if( pfr->next == NULL &&
1345 *(int*)(pfi + 1) == X_FMC_MAGIC )
1347 /* read LFD stubs */
1348 char* lpch = (char*)((int*)(pfi + 1) + 1);
1349 offset += sizeof(int);
1350 for( pfr = fontList; pfr; pfr = pfr->next )
1352 TRACE(font,"\t%s, %i instances\n", lpch, pfr->fi_count );
1353 pfr->resource = lpch;
1356 if( ++offset > length ) goto fail;
1357 if( !*lpch++ ) break;
1367 if( fontList ) HeapFree( SystemHeap, 0, fontList );
1374 /***********************************************************************
1375 * XFONT_WriteCachedMetrics
1379 static BOOL XFONT_WriteCachedMetrics( int fd, unsigned x_checksum, int x_count, int n_ff )
1388 /* font metrics file:
1392 * +0008 total size to load
1393 * +000C prepackaged font metrics
1396 * +...x + 4 LFD stubs
1399 write( fd, &x_checksum, sizeof(unsigned) );
1400 write( fd, &x_count, sizeof(int) );
1402 for( j = i = 0, pfr = fontList; pfr; pfr = pfr->next )
1404 i += strlen( pfr->resource ) + 1;
1407 i += n_ff * sizeof(fontResource) + j * sizeof(fontInfo) + sizeof(int);
1408 write( fd, &i, sizeof(int) );
1410 TRACE(font,"Writing font cache:\n");
1412 for( pfr = fontList; pfr; pfr = pfr->next )
1416 TRACE(font,"\t%s, %i instances\n", pfr->resource, pfr->fi_count );
1418 i = write( fd, pfr, sizeof(fontResource) );
1419 if( i == sizeof(fontResource) )
1421 for( k = 1, pfi = pfr->fi; pfi; pfi = pfi->next )
1423 memcpy( &fi, pfi, sizeof(fi) );
1425 fi.df.dfFace = NULL;
1426 fi.next = (fontInfo*)k; /* loader checks this */
1428 j = write( fd, &fi, sizeof(fi) );
1431 if( j == sizeof(fontInfo) ) continue;
1435 if( i == sizeof(fontResource) && j == sizeof(fontInfo) )
1437 i = j = X_FMC_MAGIC;
1438 write( fd, &i, sizeof(int) );
1439 for( pfr = fontList; pfr && i == j; pfr = pfr->next )
1441 i = strlen( pfr->resource ) + 1;
1442 j = write( fd, pfr->resource, i );
1451 /***********************************************************************
1452 * XFONT_CheckIniSection
1456 * Examines wine.conf for old/invalid font entries and recommend changes to
1460 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
1461 * Original implementation.
1463 static void XFONT_CheckIniCallback(char const *, char const *, void *);
1465 static char const *fontmsgprologue =
1467 " The following entries in the [fonts] section of the wine.conf file are\n"
1468 " obsolete or invalid:\n";
1470 static char const *fontmsgepilogue =
1471 " These entries should be eliminated or updated.\n"
1472 " See the documentation/fonts file for more information.\n";
1474 static int XFONT_CheckIniSection()
1478 PROFILE_EnumerateWineIniSection("Fonts", &XFONT_CheckIniCallback,
1481 MSG(fontmsgepilogue);
1486 static void XFONT_CheckIniCallback(
1491 /* Ignore any keys that start with potential comment characters "'", '#',
1493 if(key[0] == '\'' || key[0] == '#' || key[0] == ';' || key[0] == '\0')
1496 /* Make sure this is a valid key */
1497 if((strncasecmp(key, INIAliasSection, 5) == 0) ||
1498 (strncasecmp(key, INIIgnoreSection, 6) == 0) ||
1499 (strcasecmp( key, INIDefault) == 0) ||
1500 (strcasecmp( key, INIDefaultFixed) == 0) ||
1501 (strcasecmp( key, INIGlobalMetrics) == 0) ||
1502 (strcasecmp( key, INIResolution) == 0) ||
1503 (strcasecmp( key, INIDefaultSerif) == 0) ||
1504 (strcasecmp( key, INIDefaultSansSerif) ==0) )
1506 /* Valid key; make sure the value doesn't contain a wildcard */
1507 if(strchr(value, '*')) {
1508 if(*(int *)found == 0) {
1509 MSG(fontmsgprologue);
1513 MSG(" %s=%s [no wildcards allowed]\n", key, value);
1517 /* Not a valid key */
1518 if(*(int *)found == 0) {
1519 MSG(fontmsgprologue);
1523 MSG(" %s=%s [obsolete]\n", key, value);
1529 /***********************************************************************
1530 * XFONT_GetPointResolution()
1534 * Here we initialize DefResolution which is used in the
1535 * XFONT_Match() penalty function. We also load the point
1536 * resolution value (higher values result in larger fonts).
1538 static int XFONT_GetPointResolution( DeviceCaps* pDevCaps )
1540 int i, j, point_resolution, num = 3;
1541 int allowed_xfont_resolutions[3] = { 72, 75, 100 };
1542 int best = 0, best_diff = 65536;
1544 DefResolution = point_resolution = PROFILE_GetWineIniInt( INIFontSection, INIResolution, 0 );
1545 if( !DefResolution ) DefResolution = point_resolution = pDevCaps->logPixelsY;
1546 else pDevCaps->logPixelsX = pDevCaps->logPixelsY = DefResolution;
1548 for( i = best = 0; i < num; i++ )
1550 j = abs( DefResolution - allowed_xfont_resolutions[i] );
1557 DefResolution = allowed_xfont_resolutions[best];
1558 return point_resolution;
1561 /***********************************************************************
1562 * XFONT_BuildDefaultAliases
1566 * Alias "Helv", and "Tms Rmn" to the DefaultSansSerif and DefaultSerif
1567 * fonts respectively. Create font alias templates for "MS Sans Serif"
1568 * and "MS Serif", also pointing to DefaultSansSerif and DefaultSerif.
1570 static int XFONT_BuildDefaultAliases( char** buffer, int* buf_size )
1573 aliasTemplate fatDefaultSerif = { "-bitstream-charter-", "Charter" };
1574 aliasTemplate fatDefaultSansSerif = { "-adobe-helvetica-", "Helvetica" };
1578 /* Make sure our buffer is big enough; update calling function's
1579 buf_size if we change it. */
1581 if( *buf_size < 128 )
1583 *buffer = HeapReAlloc( SystemHeap, 0, *buffer, 256 );
1587 /* Get the X11 name of the default serif font from the Wine INI file.
1588 (-bitstream-charter- is the default.) */
1590 PROFILE_GetWineIniString( INIFontSection, INIDefaultSerif,
1591 fatDefaultSerif.fatResource, *buffer, 128 );
1593 /* Find the Windows typeface which corresponds to the X11 font. */
1595 for( fr = fontList; fr; fr = fr->next )
1596 if( !strcasecmp( fr->resource, *buffer ) ) break;
1598 /* Update the Alias Table entry for "Tms Rmn" with the default serif font's
1599 typeface. Update the Alias Template for "MS Serif" with the default
1600 serif font's X11 name. Note that this method leaves us dependant on
1601 the order of the Alias Table and the Alias Templates. Also, we don't
1602 check for or handle a situation in which -bitstream-charter- is not
1607 TRACE(font, "Using \'%s\' as default serif font\n", fr->lfFaceName);
1608 aliasTable[1].faTypeFace = fr->lfFaceName;
1609 faTemplate[1].fatResource = fr->resource;
1613 WARN(font, "No typeface found for \'%s\'; using \'%s\'\n", *buffer,
1614 fatDefaultSerif.fatAlias);
1615 aliasTable[1].faTypeFace = fatDefaultSerif.fatAlias; /* Charter */
1616 faTemplate[1].fatResource = fatDefaultSerif.fatResource;
1619 /* Get the X11 name of the default sans serif font from the Wine INI file.
1620 (-adobe-helvetica- is the default.) */
1622 PROFILE_GetWineIniString (INIFontSection, INIDefaultSansSerif,
1623 fatDefaultSansSerif.fatResource, *buffer, 128 );
1625 /* Find the Windows typeface which corresponds to the X11 font. */
1627 for( fr = fontList; fr; fr = fr->next )
1628 if ( !strcasecmp( fr->resource, *buffer ) ) break;
1630 /* Update the Alias Table entry for "Helv" with the default sans serif font's
1631 typeface. Update the Alias Template for "MS Sans Serif" with the
1632 default sans serif font's X11 name. Note that this method leaves us
1633 dependant on the order of the Alias Table and the Alias Templates.
1634 Also, we don't check for or handle a situation in which
1635 -adobe-helvetica- is not available. */
1639 TRACE(font, "Using \'%s\' as default sans serif font\n", fr->lfFaceName);
1640 aliasTable[0].faTypeFace = fr->lfFaceName;
1641 faTemplate[0].fatResource = fr->resource;
1645 WARN(font, "No typeface found for \'%s\'; using \'%s\'\n", *buffer,
1646 fatDefaultSansSerif.fatAlias);
1647 aliasTable[0].faTypeFace = fatDefaultSansSerif.fatAlias; /* Helvetica */
1648 faTemplate[0].fatResource = fatDefaultSansSerif.fatResource;
1654 /***********************************************************************
1657 * Initialize font resource list and allocate font cache.
1659 BOOL X11DRV_FONT_Init( DeviceCaps* pDevCaps )
1662 fontResource* fr, *pfr;
1664 unsigned x_checksum;
1665 int i, j, res, x_count, fd = -1, buf_size = 0;
1666 char* lpstr, *lpch, *lpmetrics, *buffer;
1669 XFONT_CheckIniSection();
1671 res = XFONT_GetPointResolution( pDevCaps );
1673 x_pattern = TSXListFonts(display, "*", MAX_FONT_FAMILIES * 16, &x_count );
1675 TRACE(font,"Font Mapper: initializing %i fonts [LPY=%i, XDR=%i, DR=%i]\n",
1676 x_count, pDevCaps->logPixelsY, DefResolution, res);
1677 for( i = x_checksum = 0; i < x_count; i++ )
1680 printf("%i\t: %s\n", i, x_pattern[i] );
1683 j = strlen( x_pattern[i] );
1684 if( j ) x_checksum ^= __genericCheckSum( x_pattern[i], j );
1686 x_checksum |= X_PFONT_MAGIC;
1689 buffer = HeapAlloc( SystemHeap, 0, buf_size );
1692 /* deal with systemwide font metrics cache */
1694 if( PROFILE_GetWineIniString( INIFontSection, INIGlobalMetrics, "", buffer, 128 ) )
1695 fd = open( buffer, O_RDONLY );
1697 if( XFONT_ReadCachedMetrics(fd, res, x_checksum, x_count) == FALSE )
1700 buffer = XFONT_UserMetricsCache( buffer, &buf_size );
1703 fd = open( buffer, O_RDONLY );
1704 if( XFONT_ReadCachedMetrics(fd, res, x_checksum, x_count) == FALSE )
1705 lpmetrics = HEAP_strdupA( SystemHeap, 0, buffer ); /* update later on */
1710 if( fontList == NULL ) /* build metrics from scratch */
1715 for( i = n_ff = 0; i < x_count; i++ )
1717 typeface = lpch = x_pattern[i];
1719 lpch = LFD_Advance(typeface, 3); /* extra '-' in the beginning */
1720 if( !*lpch ) continue;
1723 j = lpch - typeface; /* resource name length */
1725 /* find a family to insert into */
1727 for( pfr = NULL, fr = fontList; fr; fr = fr->next )
1729 if( !strncasecmp(fr->resource, typeface, j) &&
1730 strlen(fr->resource) == j ) break;
1734 if( !fi ) fi = (fontInfo*) HeapAlloc(SystemHeap, 0, sizeof(fontInfo));
1736 if( !fr ) /* add new family */
1738 if( n_ff >= MAX_FONT_FAMILIES ) break;
1739 if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1742 fr = (fontResource*) HeapAlloc(SystemHeap, 0, sizeof(fontResource));
1743 memset(fr, 0, sizeof(fontResource));
1744 fr->resource = (char*) HeapAlloc(SystemHeap, 0, j + 1 );
1745 lstrcpynA( fr->resource, typeface, j + 1 );
1747 TRACE(font," family: %s\n", fr->resource );
1749 if( pfr ) pfr->next = fr;
1752 else if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1754 /* check if we already have something better than "fi" */
1756 for( pfi = fr->fi, j = 0; pfi && j <= 0; pfi = pfi->next )
1757 if( (j = XFONT_IsSubset( pfi, fi )) < 0 )
1758 pfi->fi_flags |= FI_SUBSET; /* superseded by "fi" */
1759 if( j > 0 ) continue;
1761 /* add new font instance "fi" to the "fr" font resource */
1763 if( fi->fi_flags & FI_SCALABLE )
1765 /* set scalable font height to 24 to get an origin for extrapolation */
1767 j = strlen(typeface); j += 0x10;
1769 buffer = (char*)HeapReAlloc( SystemHeap, 0, buffer, buf_size = j );
1771 lpch = LFD_Advance(typeface, 7);
1772 memcpy( buffer, typeface, (j = lpch - typeface) );
1773 lpch = LFD_Advance(lpch, 4);
1774 sprintf( buffer + j, "%d-%d-%d-*-%c-*-", fi->lfd_height,
1775 fi->lfd_decipoints, fi->lfd_resolution,
1776 (*lpch == '-')?'*':*lpch );
1777 lpch = LFD_Advance(lpch, 2);
1778 strcat( lpstr = buffer, lpch);
1780 else lpstr = typeface;
1782 if( (x_fs = TSXLoadQueryFont(display, lpstr)) )
1784 fi->df.dfHorizRes = fi->df.dfVertRes = res;
1786 XFONT_SetFontMetric( fi, fr, x_fs );
1787 TSXFreeFont( display, x_fs );
1789 TRACE(font,"\t[% 2ipt] '%s'\n", fi->df.dfPoints, typeface );
1791 XFONT_CheckFIList( fr, fi, REMOVE_SUBSETS );
1792 fi = NULL; /* preventing reuse */
1796 ERR(font, "failed to load %s\n", lpstr );
1798 XFONT_CheckFIList( fr, fi, UNMARK_SUBSETS );
1802 if( lpmetrics ) /* update cached metrics */
1804 fd = open( lpmetrics, O_CREAT | O_TRUNC | O_RDWR, 0644 ); /* -rw-r--r-- */
1805 if( XFONT_WriteCachedMetrics( fd, x_checksum, x_count, n_ff ) == FALSE )
1806 if( fd ) remove( lpmetrics ); /* couldn't write entire file */
1807 HeapFree( SystemHeap, 0, lpmetrics );
1811 if( fi ) HeapFree(SystemHeap, 0, fi);
1812 TSXFreeFontNames(x_pattern);
1814 /* check if we're dealing with X11 R6 server */
1816 strcpy(buffer, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
1817 if( (x_fs = TSXLoadQueryFont(display, buffer)) )
1819 XTextCaps |= TC_SF_X_YINDEP;
1820 TSXFreeFont(display, x_fs);
1823 XFONT_WindowsNames( buffer );
1824 XFONT_BuildDefaultAliases( &buffer, &buf_size );
1825 XFONT_LoadAliases( &buffer, &buf_size );
1826 XFONT_LoadPenalties( &buffer, &buf_size );
1827 HeapFree(SystemHeap, 0, buffer);
1829 InitializeCriticalSection( &crtsc_fonts_X11 );
1830 MakeCriticalSectionGlobal( &crtsc_fonts_X11 );
1832 /* fontList initialization is over, allocate X font cache */
1834 fontCache = (fontObject*) HeapAlloc(SystemHeap, 0, fontCacheSize * sizeof(fontObject));
1835 XFONT_GrowFreeList(0, fontCacheSize - 1);
1837 TRACE(font,"done!\n");
1839 /* update text caps parameter */
1841 pDevCaps->textCaps = XTextCaps;
1843 RAW_ASCENT = TSXInternAtom(display, "RAW_ASCENT", TRUE);
1844 RAW_DESCENT = TSXInternAtom(display, "RAW_DESCENT", TRUE);
1850 /***********************************************************************
1851 * XFONT_RemoveFontResource
1853 * Caller should check if the font resource is in use. If it is it should
1854 * set FR_REMOVED flag to delay removal until the resource is not in use
1857 void XFONT_RemoveFontResource( fontResource** ppfr )
1860 fontResource* pfr = *ppfr;
1865 pfi = pfr->fi->next;
1866 HeapFree( SystemHeap, 0, pfr->fi );
1869 HeapFree( SystemHeap, 0, pfr );
1872 /***********************************************************************
1875 * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1877 static INT XFONT_IsSubset(fontInfo* match, fontInfo* fi)
1881 /* 0 - keep both, 1 - keep match, -1 - keep fi */
1883 m = (BYTE*)&fi->df.dfPixWidth - (BYTE*)&fi->df.dfItalic;
1884 if( memcmp(&match->df.dfItalic, &fi->df.dfItalic, m )) return 0;
1886 if( (!((fi->fi_flags & FI_SCALABLE) + (match->fi_flags & FI_SCALABLE))
1887 && fi->lfd_height != match->lfd_height) ||
1888 (!((fi->fi_flags & FI_POLYWEIGHT) + (match->fi_flags & FI_POLYWEIGHT))
1889 && fi->df.dfWeight != match->df.dfWeight) ) return 0;
1891 m = (int)(match->fi_flags & (FI_POLYWEIGHT | FI_SCALABLE)) -
1892 (int)(fi->fi_flags & (FI_SCALABLE | FI_POLYWEIGHT));
1894 if( m == (FI_POLYWEIGHT - FI_SCALABLE) ||
1895 m == (FI_SCALABLE - FI_POLYWEIGHT) ) return 0; /* keep both */
1896 else if( m >= 0 ) return 1; /* 'match' is better */
1898 return -1; /* 'fi' is better */
1901 /***********************************************************************
1904 * Compute the matching score between the logical font and the device font.
1906 * contributions from highest to lowest:
1910 * family flags (only when the facename is not present)
1912 * weight, italics, underlines, strikeouts
1914 * NOTE: you can experiment with different penalty weights to see what happens.
1915 * http://premium.microsoft.com/msdn/library/techart/f365/f36b/f37b/d38b/sa8bf.htm
1917 static UINT XFONT_Match( fontMatch* pfm )
1919 fontInfo* pfi = pfm->pfi; /* device font to match */
1920 LPLOGFONT16 plf = pfm->plf; /* wanted logical font */
1922 BOOL bR6 = pfm->flags & FO_MATCH_XYINDEP; /* from TextCaps */
1923 BOOL bScale = pfi->fi_flags & FI_SCALABLE;
1926 TRACE(font,"\t[ %-2ipt h=%-3i w=%-3i %s%s]\n", pfi->df.dfPoints,
1927 pfi->df.dfPixHeight, pfi->df.dfAvgWidth,
1928 (pfi->df.dfWeight > 400) ? "Bold " : "Normal ",
1929 (pfi->df.dfItalic) ? "Italic" : "" );
1933 if( plf->lfCharSet == DEFAULT_CHARSET )
1935 if( (pfi->df.dfCharSet!= ANSI_CHARSET) && (pfi->df.dfCharSet!=DEFAULT_CHARSET) )
1938 else if (plf->lfCharSet != pfi->df.dfCharSet) penalty += 0x200;
1940 /* FIXME: Hack to demote symbols and nil fonts. Should take into
1941 account if a program ever actually asked for this type of
1943 if ( (strcmp(pfm->pfr->lfFaceName,"Symbol")==0) || (strcmp(pfm->pfr->lfFaceName,"Nil")==0) )
1944 penalty += 0x200; /* very stiff penality */
1946 /* TMPF_FIXED_PITCH means exactly the opposite */
1948 if( plf->lfPitchAndFamily & FIXED_PITCH )
1950 if( pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH ) penalty += 0x100;
1952 else if( !(pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH) ) penalty += 0x2;
1954 if( plf->lfHeight > 0 )
1955 d = (h = pfi->df.dfPixHeight) - plf->lfHeight;
1956 else if( plf->lfHeight < -1 )
1957 d = (h = pfi->df.dfPoints) + plf->lfHeight;
1960 if( d && h && plf->lfHeight )
1962 UINT16 height = ( plf->lfHeight > 0 ) ? plf->lfHeight
1963 : ((-plf->lfHeight * pfi->df.dfPixHeight) / h);
1964 if( bScale ) pfm->height = height;
1965 else if( (plf->lfQuality != PROOF_QUALITY) && bR6 )
1967 if( d > 0 ) /* do not shrink raster fonts */
1969 pfm->height = pfi->df.dfPixHeight;
1970 penalty += (pfi->df.dfPixHeight - height) * 0x4;
1972 else /* expand only in integer multiples */
1974 pfm->height = height - height%pfi->df.dfPixHeight;
1975 penalty += (height - pfm->height + 1) * height / pfi->df.dfPixHeight;
1978 else /* can't be scaled at all */
1980 if( plf->lfQuality != PROOF_QUALITY) pfm->flags |= FO_SYNTH_HEIGHT;
1981 pfm->height = pfi->df.dfPixHeight;
1982 penalty += (d > 0)? d * 0x8 : -d * 0x10;
1985 else pfm->height = pfi->df.dfPixHeight;
1987 if((pfm->flags & FO_MATCH_PAF) &&
1988 (plf->lfPitchAndFamily & FF_FAMILY) != (pfi->df.dfPitchAndFamily & FF_FAMILY) )
1993 if( bR6 && bScale ) h = 0;
1996 /* FIXME: not complete */
1998 pfm->flags |= FO_SYNTH_WIDTH;
1999 h = abs(plf->lfWidth - (pfm->height * pfi->df.dfAvgWidth)/pfi->df.dfPixHeight);
2001 penalty += h * ( d ) ? 0x2 : 0x1 ;
2003 else if( !(pfi->fi_flags & FI_NORMAL) ) penalty++;
2005 if( plf->lfWeight != FW_DONTCARE )
2007 penalty += abs(plf->lfWeight - pfi->df.dfWeight) / 40;
2008 if( plf->lfWeight > pfi->df.dfWeight ) pfm->flags |= FO_SYNTH_BOLD;
2009 } else if( pfi->df.dfWeight >= FW_BOLD ) penalty++; /* choose normal by default */
2011 if( plf->lfItalic != pfi->df.dfItalic )
2014 pfm->flags |= FO_SYNTH_ITALIC;
2017 if( plf->lfUnderline ) pfm->flags |= FO_SYNTH_UNDERLINE;
2018 if( plf->lfStrikeOut ) pfm->flags |= FO_SYNTH_STRIKEOUT;
2020 if( penalty && pfi->lfd_resolution != DefResolution )
2023 TRACE(font," returning %i\n", penalty );
2028 /***********************************************************************
2031 * Scan a particular font resource for the best match.
2033 static UINT XFONT_MatchFIList( fontMatch* pfm )
2035 BOOL skipRaster = (pfm->flags & FO_MATCH_NORASTER);
2036 UINT current_score, score = (UINT)(-1);
2037 UINT16 origflags = pfm->flags; /* Preserve FO_MATCH_XYINDEP */
2038 fontMatch fm = *pfm;
2040 for( fm.pfi = pfm->pfr->fi; fm.pfi && score; fm.pfi = fm.pfi->next,
2041 fm.flags = origflags )
2043 if( skipRaster && !(fm.pfi->fi_flags & FI_SCALABLE) )
2046 current_score = XFONT_Match( &fm );
2047 if( score > current_score )
2049 memcpy( pfm, &fm, sizeof(fontMatch) );
2050 score = current_score;
2056 /***********************************************************************
2059 * REMOVE_SUBSETS - attach new fi and purge subsets
2060 * UNMARK_SUBSETS - remove subset flags from all fi entries
2062 static void XFONT_CheckFIList( fontResource* fr, fontInfo* fi, int action)
2065 fontInfo* pfi, *prev;
2067 for( prev = NULL, pfi = fr->fi; pfi; )
2069 if( action == REMOVE_SUBSETS )
2071 if( pfi->fi_flags & FI_SUBSET )
2073 fontInfo* subset = pfi;
2077 if( prev ) prev->next = pfi = pfi->next;
2078 else fr->fi = pfi = pfi->next;
2079 HeapFree( SystemHeap, 0, subset );
2083 else pfi->fi_flags &= ~FI_SUBSET;
2089 if( action == REMOVE_SUBSETS ) /* also add the superset */
2091 if( fi->fi_flags & FI_SCALABLE )
2096 else if( prev ) prev->next = fi; else fr->fi = fi;
2100 if( i ) TRACE(font,"\t purged %i subsets [%i]\n", i , fr->fi_count);
2103 /***********************************************************************
2106 static fontResource* XFONT_FindFIList( fontResource* pfr, const char* pTypeFace )
2110 if( !strcasecmp( pfr->lfFaceName, pTypeFace ) ) break;
2116 /***********************************************************************
2117 * XFONT_MatchDeviceFont
2119 * Scan font resource tree.
2121 static BOOL XFONT_MatchDeviceFont( fontResource* start, fontMatch* pfm )
2123 fontResource** ppfr;
2124 fontMatch fm = *pfm;
2127 if( fm.plf->lfFaceName[0] )
2132 for( fa = aliasTable; fa; fa = fa->next )
2133 if( !strcmp( fa->faAlias, fm.plf->lfFaceName ) )
2135 str = fa->faTypeFace;
2138 fm.pfr = XFONT_FindFIList( start, str ? str : fm.plf->lfFaceName );
2141 if( fm.pfr ) /* match family */
2143 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2145 if( fm.pfr->fr_flags & FR_REMOVED )
2149 XFONT_MatchFIList( &fm );
2154 if( !pfm->pfi ) /* match all available fonts */
2156 UINT current_score, score = (UINT)(-1);
2158 fm.flags |= FO_MATCH_PAF;
2159 for( ppfr = &fontList; *ppfr && score; ppfr = &(*ppfr)->next )
2161 if( (*ppfr)->fr_flags & FR_REMOVED )
2163 if( (*ppfr)->fo_count == 0 )
2164 XFONT_RemoveFontResource( ppfr );
2170 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2172 current_score = XFONT_MatchFIList( &fm );
2173 if( current_score < score )
2175 score = current_score;
2184 /***********************************************************************
2187 static void XFONT_GrowFreeList(int start, int end)
2189 /* add all entries from 'start' up to and including 'end' */
2191 memset( fontCache + start, 0, (end - start + 1) * sizeof(fontObject) );
2193 fontCache[end].lru = fontLF;
2194 fontCache[end].count = -1;
2196 while( start < end )
2198 fontCache[start].count = -1;
2199 fontCache[start].lru = start + 1;
2204 static fontObject* XFONT_LookupCachedFont( LPLOGFONT16 plf, UINT16* checksum )
2206 UINT16 cs = __lfCheckSum( plf );
2207 int i = fontMRU, prev = -1;
2212 if( fontCache[i].lfchecksum == cs &&
2213 !(fontCache[i].fo_flags & FO_REMOVED) )
2215 /* FIXME: something more intelligent here */
2217 if( !memcmp( plf, &fontCache[i].lf,
2218 sizeof(LOGFONT16) - LF_FACESIZE ) &&
2219 !strncasecmp( plf->lfFaceName, fontCache[i].lf.lfFaceName,
2222 /* remove temporarily from the lru list */
2225 fontCache[prev].lru = fontCache[i].lru;
2227 fontMRU = (INT16)fontCache[i].lru;
2228 return (fontCache + i);
2232 i = (INT16)fontCache[i].lru;
2237 static fontObject* XFONT_GetCacheEntry()
2243 int prev_i, prev_j, j;
2245 TRACE(font,"font cache is full\n");
2247 /* lookup the least recently used font */
2249 for( prev_i = prev_j = j = -1, i = fontMRU; i >= 0; i = (INT16)fontCache[i].lru )
2251 if( fontCache[i].count <= 0 &&
2252 !(fontCache[i].fo_flags & FO_SYSTEM) )
2260 if( j >= 0 ) /* unload font */
2262 /* detach from the lru list */
2264 TRACE(font,"\tfreeing entry %i\n", j );
2266 fontCache[j].fr->fo_count--;
2269 fontCache[prev_j].lru = fontCache[j].lru;
2270 else fontMRU = (INT16)fontCache[j].lru;
2272 /* FIXME: lpXForm, lpPixmap */
2273 if(fontCache[j].lpX11Trans)
2274 HeapFree( SystemHeap, 0, fontCache[j].lpX11Trans );
2276 TSXFreeFont( display, fontCache[j].fs );
2278 memset( fontCache + j, 0, sizeof(fontObject) );
2279 return (fontCache + j);
2281 else /* expand cache */
2283 fontObject* newCache;
2285 prev_i = fontCacheSize + FONTCACHE;
2287 TRACE(font,"\tgrowing font cache from %i to %i\n", fontCacheSize, prev_i );
2289 if( (newCache = (fontObject*)HeapReAlloc(SystemHeap, 0,
2290 fontCache, prev_i)) )
2293 fontCacheSize = prev_i;
2294 fontCache = newCache;
2295 XFONT_GrowFreeList( i, fontCacheSize - 1);
2301 /* detach from the free list */
2304 fontLF = (INT16)fontCache[i].lru;
2305 fontCache[i].count = 0;
2306 return (fontCache + i);
2309 static int XFONT_ReleaseCacheEntry(fontObject* pfo)
2311 UINT u = (UINT)(pfo - fontCache);
2313 if( u < fontCacheSize ) return (--fontCache[u].count);
2317 /**********************************************************************
2320 static BOOL XFONT_SetX11Trans( fontObject *pfo )
2326 TSXGetFontProperty( pfo->fs, XA_FONT, &nameAtom );
2327 fontName = TSXGetAtomName( display, nameAtom );
2328 cp = LFD_Advance( fontName, 7 );
2334 while((cp = strchr(cp, '~')))
2337 #define PX pfo->lpX11Trans
2339 sscanf(start, "[%f%f%f%f]", &PX->a, &PX->b, &PX->c, &PX->d);
2342 TSXGetFontProperty( pfo->fs, RAW_ASCENT, &PX->RAW_ASCENT );
2343 TSXGetFontProperty( pfo->fs, RAW_DESCENT, &PX->RAW_DESCENT );
2345 PX->pixelsize = hypot(PX->a, PX->b);
2346 PX->ascent = PX->pixelsize / 1000.0 * PX->RAW_ASCENT;
2347 PX->descent = PX->pixelsize / 1000.0 * PX->RAW_DESCENT;
2349 TRACE(font, "[%f %f %f %f] RA = %ld RD = %ld\n", pfo->lpX11Trans->a,
2350 pfo->lpX11Trans->b, pfo->lpX11Trans->c, pfo->lpX11Trans->d,
2351 pfo->lpX11Trans->RAW_ASCENT, pfo->lpX11Trans->RAW_DESCENT);
2357 /***********************************************************************
2358 * X Device Font Objects
2360 static X_PHYSFONT XFONT_RealizeFont( LPLOGFONT16 plf )
2363 fontObject* pfo = XFONT_LookupCachedFont( plf, &checksum );
2376 if( XTextCaps & TC_SF_X_YINDEP ) fm.flags = FO_MATCH_XYINDEP;
2378 /* allocate new font cache entry */
2380 if( (pfo = XFONT_GetCacheEntry()) )
2382 LPSTR lpLFD = HeapAlloc( GetProcessHeap(), 0, MAX_LFD_LENGTH );
2384 if( lpLFD ) /* initialize entry and load font */
2386 UINT uRelaxLevel = 0;
2388 TRACE(font,"(%u) '%s' h=%i weight=%i %s\n",
2389 plf->lfCharSet, plf->lfFaceName, plf->lfHeight,
2390 plf->lfWeight, (plf->lfItalic) ? "Italic" : "" );
2392 if(abs(plf->lfHeight) > MAX_FONT_SIZE) {
2394 "plf->lfHeight = %d, this is probably not right. Setting to 12\n",
2399 XFONT_MatchDeviceFont( fontList, &fm );
2403 pfo->fr->fo_count++;
2404 pfo->fo_flags = fm.flags & ~FO_MATCH_MASK;
2406 memcpy( &pfo->lf, plf, sizeof(LOGFONT16) );
2407 pfo->lfchecksum = checksum;
2411 LFD_ComposeLFD( pfo, fm.height, lpLFD, uRelaxLevel++ );
2412 if( (pfo->fs = TSXLoadQueryFont( display, lpLFD )) ) break;
2413 } while( uRelaxLevel );
2416 if(pfo->lf.lfEscapement != 0) {
2417 pfo->lpX11Trans = HeapAlloc(SystemHeap, 0,
2418 sizeof(XFONTTRANS));
2419 if(!XFONT_SetX11Trans( pfo )) {
2420 HeapFree(SystemHeap, 0, pfo->lpX11Trans);
2421 pfo->lpX11Trans = NULL;
2425 if( XFONT_GetLeading( &pfo->fi->df, pfo->fs, &i, NULL,
2428 if(!pfo->lpX11Trans)
2429 pfo->foAvgCharWidth =
2430 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].width;
2432 pfo->foAvgCharWidth =
2433 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].attributes
2434 * pfo->lpX11Trans->pixelsize / 1000.0;
2436 pfo->foAvgCharWidth = (INT16)XFONT_GetAvgCharWidth(
2437 &pfo->fi->df, pfo->fs, pfo->lpX11Trans );
2438 pfo->foMaxCharWidth = (INT16)XFONT_GetMaxCharWidth(pfo);
2439 pfo->foInternalLeading = (INT16)i;
2441 /* FIXME: If we've got a soft font or
2442 * there are FO_SYNTH_... flags for the
2443 * non PROOF_QUALITY request, the engine
2444 * should rasterize characters into mono
2445 * pixmaps and store them in the pfo->lpPixmap
2446 * array (pfo->fs should be updated as well).
2447 * array (pfo->fs should be updated as well).
2448 * X11DRV_ExtTextOut() must be heavily modified
2449 * to support pixmap blitting and FO_SYNTH_...
2453 pfo->lpPixmap = NULL;
2455 HeapFree( GetProcessHeap(), 0, lpLFD );
2457 else /* attach back to the free list */
2461 fontLF = (pfo - fontCache);
2466 if( !pfo ) /* couldn't get a new entry, get one of the cached fonts */
2468 UINT current_score, score = (UINT)(-1);
2470 i = index = fontMRU;
2471 fm.flags |= FO_MATCH_PAF;
2474 pfo = fontCache + i;
2475 fm.pfr = pfo->fr; fm.pfi = pfo->fi;
2477 current_score = XFONT_Match( &fm );
2478 if( current_score < score ) index = i;
2482 pfo = fontCache + index;
2484 return (X_PHYSFONT)(X_PFONT_MAGIC | index);
2488 /* attach at the head of the lru list */
2492 fontMRU = (pfo - fontCache);
2494 TRACE(font,"physfont %i\n", fontMRU);
2496 return (X_PHYSFONT)(X_PFONT_MAGIC | fontMRU);
2499 /***********************************************************************
2500 * XFONT_GetFontObject
2502 fontObject* XFONT_GetFontObject( X_PHYSFONT pFont )
2504 if( CHECK_PFONT(pFont) ) return __PFONT(pFont);
2508 /***********************************************************************
2509 * XFONT_GetFontStruct
2511 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
2513 if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
2517 /***********************************************************************
2520 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
2522 if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
2528 /* X11DRV Interface ****************************************************
2530 * Exposed via the dc->funcs dispatch table. *
2532 ***********************************************************************/
2533 /***********************************************************************
2534 * X11DRV_FONT_SelectObject
2536 HFONT X11DRV_FONT_SelectObject( DC* dc, HFONT hfont, FONTOBJ* font )
2538 HFONT hPrevFont = 0;
2540 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2542 EnterCriticalSection( &crtsc_fonts_X11 );
2544 if( CHECK_PFONT(physDev->font) )
2545 XFONT_ReleaseCacheEntry( __PFONT(physDev->font) );
2547 /* FIXME: do we need to pass anything back from here? */
2548 memcpy(&lf,&font->logfont,sizeof(lf));
2549 lf.lfWidth = font->logfont.lfWidth * dc->vportExtX/dc->wndExtX;
2550 lf.lfHeight = font->logfont.lfHeight* dc->vportExtY/dc->wndExtY;
2552 physDev->font = XFONT_RealizeFont( &lf );
2553 hPrevFont = dc->w.hFont;
2554 dc->w.hFont = hfont;
2556 LeaveCriticalSection( &crtsc_fonts_X11 );
2562 /***********************************************************************
2564 * X11DRV_EnumDeviceFonts
2566 BOOL X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf,
2567 DEVICEFONTENUMPROC proc, LPARAM lp )
2571 fontResource* pfr = fontList;
2574 if( plf->lfFaceName[0] )
2576 /* enum all entries in this resource */
2577 pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
2581 for( pfi = pfr->fi; pfi; pfi = pfi->next )
2583 /* Note: XFONT_GetFontMetric() will have to
2584 release the crit section, font list will
2585 have to be retraversed on return */
2587 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2588 XFONT_GetFontMetric( pfi, &lf, &tm ), lp )) )
2594 else /* enum first entry in each resource */
2595 for( ; pfr ; pfr = pfr->next )
2599 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2600 XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
2609 /***********************************************************************
2610 * X11DRV_GetTextExtentPoint
2612 BOOL X11DRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT count,
2615 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2616 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2618 if( !pfo->lpX11Trans ) {
2619 int dir, ascent, descent;
2622 TSXTextExtents( pfo->fs, str, count, &dir, &ascent, &descent, &info );
2623 size->cx = abs((info.width + dc->w.breakRem + count *
2624 dc->w.charExtra) * dc->wndExtX / dc->vportExtX);
2625 size->cy = abs((pfo->fs->ascent + pfo->fs->descent) *
2626 dc->wndExtY / dc->vportExtY);
2630 float x = 0.0, y = 0.0;
2631 for(i = 0; i < count; i++) {
2632 x += pfo->fs->per_char ?
2633 pfo->fs->per_char[str[i] - pfo->fs->min_char_or_byte2].attributes :
2634 pfo->fs->min_bounds.attributes;
2636 y = pfo->lpX11Trans->RAW_ASCENT + pfo->lpX11Trans->RAW_DESCENT;
2637 TRACE(font, "x = %f y = %f\n", x, y);
2638 x *= pfo->lpX11Trans->pixelsize / 1000.0;
2639 y *= pfo->lpX11Trans->pixelsize / 1000.0;
2640 size->cx = fabs((x + dc->w.breakRem + count * dc->w.charExtra) *
2641 dc->wndExtX / dc->vportExtX);
2642 size->cy = fabs(y * dc->wndExtY / dc->vportExtY);
2650 /***********************************************************************
2651 * X11DRV_GetTextMetrics
2653 BOOL X11DRV_GetTextMetrics(DC *dc, TEXTMETRICA *metrics)
2655 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2657 if( CHECK_PFONT(physDev->font) )
2659 fontObject* pfo = __PFONT(physDev->font);
2660 XFONT_GetTextMetric( pfo, metrics );
2668 /***********************************************************************
2669 * X11DRV_GetCharWidth
2671 BOOL X11DRV_GetCharWidth( DC *dc, UINT firstChar, UINT lastChar,
2674 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2675 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2681 if (pfo->fs->per_char == NULL)
2682 for (i = firstChar; i <= lastChar; i++)
2684 *buffer++ = pfo->fs->min_bounds.attributes *
2685 pfo->lpX11Trans->pixelsize / 1000.0;
2687 *buffer++ = pfo->fs->min_bounds.width;
2690 XCharStruct *cs, *def;
2691 static XCharStruct __null_char = { 0, 0, 0, 0, 0, 0 };
2693 CI_GET_CHAR_INFO(pfo->fs, pfo->fs->default_char, &__null_char,
2696 for (i = firstChar; i <= lastChar; i++)
2698 if (i >= pfo->fs->min_char_or_byte2 &&
2699 i <= pfo->fs->max_char_or_byte2)
2701 cs = &pfo->fs->per_char[(i - pfo->fs->min_char_or_byte2)];
2702 if (CI_NONEXISTCHAR(cs)) cs = def;
2705 *buffer++ = MAX(cs->attributes, 0) *
2706 pfo->lpX11Trans->pixelsize / 1000.0;
2708 *buffer++ = MAX(cs->width, 0 );
2717 #endif /* !defined(X_DISPLAY_MISSING) */
2719 /***********************************************************************
2721 * Font Resource API *
2723 ***********************************************************************/
2724 /***********************************************************************
2725 * AddFontResource16 (GDI.119)
2727 * Can be either .FON, or .FNT, or .TTF, or .FOT font file.
2729 * FIXME: Load header and find the best-matching font in the fontList;
2730 * fixup dfPoints if all metrics are identical, otherwise create
2731 * new fontAlias. When soft font support is ready this will
2732 * simply create a new fontResource ('filename' will go into
2733 * the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE
2736 INT16 WINAPI AddFontResource16( LPCSTR filename )
2738 return AddFontResourceA( filename );
2742 /***********************************************************************
2743 * AddFontResource32A (GDI32.2)
2745 INT WINAPI AddFontResourceA( LPCSTR str )
2747 FIXME(font, "(%s): stub\n", debugres_a(str));
2752 /***********************************************************************
2753 * AddFontResource32W (GDI32.4)
2755 INT WINAPI AddFontResourceW( LPCWSTR str )
2757 FIXME(font, "(%s): stub\n", debugres_w(str) );
2761 /***********************************************************************
2762 * RemoveFontResource16 (GDI.136)
2764 BOOL16 WINAPI RemoveFontResource16( SEGPTR str )
2766 FIXME(font, "(%s): stub\n", debugres_a(PTR_SEG_TO_LIN(str)));
2771 /***********************************************************************
2772 * RemoveFontResource32A (GDI32.284)
2774 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
2776 /* This is how it should look like */
2778 fontResource** ppfr;
2779 BOOL32 retVal = FALSE;
2781 EnterCriticalSection( &crtsc_fonts_X11 );
2782 for( ppfr = &fontList; *ppfr; ppfr = &(*ppfr)->next )
2783 if( !strcasecmp( (*ppfr)->lfFaceName, str ) )
2785 if(((*ppfr)->fr_flags & (FR_SOFTFONT | FR_SOFTRESOURCE)) &&
2786 (*ppfr)->hOwnerProcess == GetCurrentProcess() )
2788 if( (*ppfr)->fo_count )
2789 (*ppfr)->fr_flags |= FR_REMOVED;
2791 XFONT_RemoveFontResource( ppfr );
2795 LeaveCriticalSection( &crtsc_fontList );
2798 FIXME(font, "(%s): stub\n", debugres_a(str));
2803 /***********************************************************************
2804 * RemoveFontResource32W (GDI32.286)
2806 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
2808 FIXME(font, "(%s): stub\n", debugres_w(str) );