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).
16 #include <sys/types.h>
20 #include <X11/Xatom.h>
29 #define X_PFONT_MAGIC (0xFADE0000)
30 #define X_FMC_MAGIC (0x0000CAFE)
32 #define MAX_FONT_FAMILIES 128
33 #define MAX_LFD_LENGTH 256
35 #define MAX_FONT_SIZE 5000 /* Max size in pixels */
37 #define REMOVE_SUBSETS 1
38 #define UNMARK_SUBSETS 0
40 #define DEF_SCALABLE_HEIGHT 24
41 #define DEF_SCALABLE_DP 240
43 #define FF_FAMILY (FF_MODERN | FF_SWISS | FF_ROMAN | FF_DECORATIVE | FF_SCRIPT)
45 typedef struct __fontAlias
49 struct __fontAlias
* next
;
58 /* Font alias table - these 2 aliases are always present */
59 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
61 static fontAlias __aliasTable
[2] = {
62 { NULL
, "Helv", &__aliasTable
[1] },
63 { NULL
, "Tms Rmn", NULL
}
66 static fontAlias
*aliasTable
= __aliasTable
;
68 /* Optional built-in aliases, they are installed only when X
69 * cannot supply us with original MS fonts */
70 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
72 static int faTemplateNum
= 4;
73 static aliasTemplate faTemplate
[4] = {
74 { NULL
, "MS Sans Serif" },
76 { "-adobe-times-", "Times New Roman" },
77 { "-adobe-helvetica-", "Arial" }
80 UINT16 XTextCaps
= TC_OP_CHARACTER
| TC_OP_STROKE
|
81 TC_CP_STROKE
| TC_CR_ANY
|
82 TC_SA_DOUBLE
| TC_SA_INTEGER
| TC_SA_CONTIN
|
83 TC_UA_ABLE
| TC_SO_ABLE
| TC_RA_ABLE
;
85 /* X11R6 adds TC_SF_X_YINDEP, maybe more... */
87 static const char* INIWinePrefix
= "/.wine";
88 static const char* INIFontMetrics
= "/.cachedmetrics.";
89 static const char* INIFontSection
= "fonts";
90 static const char* INIAliasSection
= "Alias";
91 static const char* INIIgnoreSection
= "Ignore";
92 static const char* INIDefault
= "Default";
93 static const char* INIDefaultFixed
= "DefaultFixed";
94 static const char* INIResolution
= "Resolution";
95 static const char* INIGlobalMetrics
= "FontMetrics";
96 static const char* INIDefaultSerif
= "DefaultSerif";
97 static const char* INIDefaultSansSerif
= "DefaultSansSerif";
99 static const char* LFDSeparator
= "*-";
101 /* suffix tables, must be less than 254 entries long */
103 static LPSTR suffx_iso
[] = { "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8",
104 "-9", "-10", "-11", "-12", "-13", "-14", "-15", NULL
};
105 static LPSTR suffx_iso646
[] = { "-irv", NULL
};
106 static LPSTR suffx_microsoft
[] = { "-cp1252", "-cp1251", "-cp1250", "-cp1253", "-cp1254", "-cp1255",
107 "-cp1256", "-cp1257", "-fontspecific", "-symbol", NULL
};
108 static LPSTR suffx_viscii
[] = { "-1", NULL
};
109 static LPSTR suffx_ansi
[] = { "-0", NULL
};
110 static LPSTR suffx_koi8
[] = { "-ru", "-r", NULL
};
111 static LPSTR suffx_null
[] = { NULL
};
113 /* charset mapping tables, have to have the same number of entries as corresponding suffix tables */
115 static BYTE chset_iso8859
[] = { ANSI_CHARSET
, EE_CHARSET
, ISO3_CHARSET
, ISO4_CHARSET
, RUSSIAN_CHARSET
,
116 ARABIC_CHARSET
, GREEK_CHARSET
, HEBREW_CHARSET
, TURKISH_CHARSET
, BALTIC_CHARSET
,
117 THAI_CHARSET
, SYMBOL_CHARSET
, SYMBOL_CHARSET
, SYMBOL_CHARSET
, ANSI_CHARSET
,
119 static BYTE chset_iso646
[] = { ANSI_CHARSET
, SYMBOL_CHARSET
};
120 static BYTE chset_microsoft
[] = { ANSI_CHARSET
, RUSSIAN_CHARSET
, EE_CHARSET
, GREEK_CHARSET
, TURKISH_CHARSET
,
121 HEBREW_CHARSET
, ARABIC_CHARSET
, BALTIC_CHARSET
, SYMBOL_CHARSET
, SYMBOL_CHARSET
,
123 static BYTE chset_ansi
[] = { ANSI_CHARSET
, ANSI_CHARSET
};
124 static BYTE chset_koi8
[] = { KOI8_CHARSET
, KOI8_CHARSET
, KOI8_CHARSET
};
125 static BYTE chset_tcvn
[] = { TCVN_CHARSET
, TCVN_CHARSET
};
126 static BYTE chset_tis620
[] = { THAI_CHARSET
};
127 static BYTE chset_fontspecific
[] = { SYMBOL_CHARSET
};
128 static BYTE chset_viscii
[] = { VISCII_CHARSET
, VISCII_CHARSET
};
136 } fontEncodingTemplate
;
138 /* Note: we can attach additional encoding mappings to the end
139 * of this table at runtime.
142 static fontEncodingTemplate __fETTable
[10] = {
143 { "iso8859", &suffx_iso
, &chset_iso8859
, &__fETTable
[1] },
144 { "iso646.1991", &suffx_iso646
, &chset_iso646
, &__fETTable
[2] },
145 { "microsoft", &suffx_microsoft
, &chset_microsoft
, &__fETTable
[3] },
146 { "ansi", &suffx_ansi
, &chset_ansi
, &__fETTable
[4] },
147 { "ascii", &suffx_ansi
, &chset_ansi
, &__fETTable
[5] },
148 { "fontspecific", &suffx_null
, &chset_fontspecific
, &__fETTable
[6] },
149 { "koi8", &suffx_koi8
, &chset_koi8
, &__fETTable
[7] },
150 { "tcvn", &suffx_ansi
, &chset_tcvn
, &__fETTable
[8] },
151 { "tis620", &suffx_null
, &chset_tis620
, &__fETTable
[9] },
152 { "viscii1.1", &suffx_viscii
, &chset_viscii
, NULL
}
154 static fontEncodingTemplate
* fETTable
= __fETTable
;
156 static unsigned DefResolution
= 0;
158 static CRITICAL_SECTION crtsc_fonts_X11
;
160 static fontResource
* fontList
= NULL
;
161 static fontObject
* fontCache
= NULL
; /* array */
162 static int fontCacheSize
= FONTCACHE
;
163 static int fontLF
= -1, fontMRU
= -1; /* last free, most recently used */
165 #define __PFONT(pFont) ( fontCache + ((UINT32)(pFont) & 0x0000FFFF) )
166 #define CHECK_PFONT(pFont) ( (((UINT32)(pFont) & 0xFFFF0000) == X_PFONT_MAGIC) &&\
167 (((UINT32)(pFont) & 0x0000FFFF) < fontCacheSize) )
169 static INT32
XFONT_IsSubset(fontInfo
*, fontInfo
*);
170 static void XFONT_CheckFIList(fontResource
*, fontInfo
*, int subset_action
);
171 static void XFONT_GrowFreeList(int start
, int end
);
172 static void XFONT_RemoveFontResource(fontResource
** ppfr
);
175 static Atom RAW_ASCENT
;
176 static Atom RAW_DESCENT
;
178 /***********************************************************************
179 * Helper macros from X distribution
182 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
183 (((cs)->rbearing|(cs)->lbearing| \
184 (cs)->ascent|(cs)->descent) == 0))
186 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
189 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
190 if (fs->per_char == NULL) { \
191 cs = &fs->min_bounds; \
193 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
194 if (CI_NONEXISTCHAR(cs)) cs = def; \
199 #define CI_GET_DEFAULT_INFO(fs,cs) \
200 CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
202 /***********************************************************************
205 static UINT16
__lfCheckSum( LPLOGFONT16 plf
)
207 CHAR font
[LF_FACESIZE
];
211 #define ptr ((UINT16*)plf)
212 for( i
= 0; i
< 9; i
++ ) checksum
^= *ptr
++;
215 #define ptr ((CHAR*)plf)
216 do { font
[i
++] = tolower(*ptr
++); } while (( i
< LF_FACESIZE
) && (*ptr
) && (*ptr
!=' '));
217 for( ptr
= font
, i
>>= 1; i
> 0; i
-- )
219 #define ptr ((UINT16*)plf)
225 static UINT16
__genericCheckSum( const void *ptr
, int size
)
227 unsigned int checksum
= 0;
228 const char *p
= (const char *)ptr
;
230 checksum
^= (checksum
<< 3) + (checksum
>> 29) + *p
++;
232 return checksum
& 0xffff;
235 /*************************************************************************
236 * LFD parse/compose routines
238 static char* LFD_Advance(LPSTR lpFont
, UINT16 uParmsNo
)
243 for( ; j
< uParmsNo
&& *lpch
; lpch
++ ) if( *lpch
== LFDSeparator
[1] ) j
++;
247 static void LFD_GetWeight( fontInfo
* fi
, LPSTR lpStr
, int j
)
249 if( j
== 1 && *lpStr
== '0' )
250 fi
->fi_flags
|= FI_POLYWEIGHT
;
253 if( !strncasecmp( "bold", lpStr
, 4) )
254 fi
->df
.dfWeight
= FW_BOLD
;
255 else if( !strncasecmp( "demi", lpStr
, 4) )
257 fi
->fi_flags
|= FI_FW_DEMI
;
258 fi
->df
.dfWeight
= FW_DEMIBOLD
;
260 else if( !strncasecmp( "book", lpStr
, 4) )
262 fi
->fi_flags
|= FI_FW_BOOK
;
263 fi
->df
.dfWeight
= FW_REGULAR
;
268 if( !strncasecmp( "light", lpStr
, 5) )
269 fi
->df
.dfWeight
= FW_LIGHT
;
270 else if( !strncasecmp( "black", lpStr
, 5) )
271 fi
->df
.dfWeight
= FW_BLACK
;
273 else if( j
== 6 && !strncasecmp( "medium", lpStr
, 6) )
274 fi
->df
.dfWeight
= FW_REGULAR
;
275 else if( j
== 8 && !strncasecmp( "demibold", lpStr
, 8) )
276 fi
->df
.dfWeight
= FW_DEMIBOLD
;
278 fi
->df
.dfWeight
= FW_DONTCARE
; /* FIXME: try to get something
279 * from the weight property */
282 static int LFD_GetSlant( fontInfo
* fi
, LPSTR lpStr
, int l
)
286 switch( tolower( *lpStr
) )
288 case '0': fi
->fi_flags
|= FI_POLYSLANT
; /* haven't seen this one yet */
290 case 'r': fi
->df
.dfItalic
= 0;
293 fi
->fi_flags
|= FI_OBLIQUE
;
294 case 'i': fi
->df
.dfItalic
= 1;
302 /*************************************************************************
307 * Fill in some fields in the fontInfo struct.
309 static int LFD_InitFontInfo( fontInfo
* fi
, LPSTR lpstr
)
312 int i
, j
, dec_style_check
, scalability
;
314 fontEncodingTemplate
* boba
;
316 memset(fi
, 0, sizeof(fontInfo
) );
319 lpch
= LFD_Advance( lpstr
, 1);
320 if( !*lpch
) return FALSE
;
321 j
= lpch
- lpstr
- 1;
322 LFD_GetWeight( fi
, lpstr
, j
);
325 lpch
= LFD_Advance( lpstr
= lpch
, 1);
326 if( !*lpch
) return FALSE
;
327 j
= lpch
- lpstr
- 1;
328 dec_style_check
= LFD_GetSlant( fi
, lpstr
, j
);
331 lpch
= LFD_Advance( lpstr
= lpch
, 1);
332 if( !*lpch
) return FALSE
;
333 if( strncasecmp( "normal", lpstr
, 6) ) /* XXX 'narrow', 'condensed', etc... */
334 dec_style_check
= TRUE
;
336 fi
->fi_flags
|= FI_NORMAL
;
339 lpch
= LFD_Advance( lpstr
= lpch
, 1);
340 if( !*lpch
) return FALSE
;
341 j
= lpch
- lpstr
- 1;
342 if( j
> 3 ) /* find out is there "sans" or "script" */
347 if( strstr(lpstr
, "sans") )
349 fi
->df
.dfPitchAndFamily
|= FF_SWISS
;
352 if( strstr(lpstr
, "script") )
354 fi
->df
.dfPitchAndFamily
|= FF_SCRIPT
;
357 if( !j
&& dec_style_check
)
358 fi
->df
.dfPitchAndFamily
|= FF_DECORATIVE
;
359 *(lpch
- 1) = LFDSeparator
[1];
362 /* pixel height, decipoint height, and res_x */
364 for( i
= scalability
= 0; i
< 3; i
++ )
366 lpch
= LFD_Advance( lpstr
= lpch
, 1);
367 if( !*lpch
) return FALSE
;
368 if( lpch
- lpstr
== 1 || lpch
- lpstr
> 4 ) return FALSE
; /* ridiculous */
371 if( !(tmp
[i
] = atoi(lpstr
)) ) scalability
++;
372 *(lpch
- 1) = LFDSeparator
[1];
374 if( scalability
== 3 ) /* Type1 */
376 fi
->fi_flags
|= FI_SCALABLE
;
377 fi
->lfd_height
= DEF_SCALABLE_HEIGHT
; fi
->lfd_decipoints
= DEF_SCALABLE_DP
;
378 fi
->lfd_resolution
= DefResolution
;
380 else if( scalability
== 0 ) /* Bitmap */
382 fi
->lfd_height
= tmp
[0]; fi
->lfd_decipoints
= tmp
[1];
383 fi
->lfd_resolution
= tmp
[2];
385 else return FALSE
; /* #$%^!!! X11R6 mutant garbage */
387 /* res_y - skip, spacing - */
388 lpstr
= LFD_Advance( lpch
, 1);
391 case '\0': return FALSE
;
393 case 'p': fi
->fi_flags
|= FI_VARIABLEPITCH
;
395 case 'c': fi
->df
.dfPitchAndFamily
|= FF_MODERN
;
396 fi
->fi_flags
|= FI_FIXEDEX
;
398 case 'm': fi
->fi_flags
|= FI_FIXEDPITCH
;
401 fi
->df
.dfPitchAndFamily
|= DEFAULT_PITCH
| FF_DONTCARE
;
403 lpstr
= LFD_Advance(lpstr
, 1);
404 if( !*lpstr
) return FALSE
;
406 /* average width - */
407 lpch
= LFD_Advance( lpstr
, 1);
408 if( !*lpch
) return FALSE
;
409 if( lpch
- lpstr
== 1 || lpch
- lpstr
> 4 ) return FALSE
; /* ridiculous */
411 if( !(fi
->lfd_width
= atoi(lpstr
)) && !scalability
) return FALSE
;
412 *(lpch
- 1) = LFDSeparator
[1];
414 /* charset registry, charset encoding - */
415 if( strstr(lpch
, "jisx") ||
416 strstr(lpch
, "ksc") ||
417 strstr(lpch
, "gb2312") ||
418 strstr(lpch
, "big5") ||
419 strstr(lpch
, "unicode") ) return FALSE
; /* 2-byte stuff */
421 fi
->df
.dfCharSet
= ANSI_CHARSET
;
423 for( i
= 0, boba
= fETTable
; boba
; boba
= boba
->next
, i
++ )
425 tmp
[0] = strlen( boba
->prefix
);
426 if( !strncasecmp( lpch
, boba
->prefix
, tmp
[0] ) )
428 if( lpch
[tmp
[0]] == '-' )
430 lpstr
= lpch
+ tmp
[0];
431 for( j
= 0; (*(boba
->psuffix
))[j
]; j
++ )
433 tmp
[1] = strlen( (*(boba
->psuffix
))[j
] );
434 if( !strncasecmp( lpstr
, (*(boba
->psuffix
))[j
], tmp
[1] ) )
436 fi
->df
.dfCharSet
= (*(boba
->pcharset
))[j
];
440 /* Note : LFD_ComposeLFD will produce 'prefix-*' encoding *
441 * if (*(boba->psuffix))[j] is NULL here */
445 for( j
= 0; (*(boba
->psuffix
))[j
] ; j
++ );
446 fi
->df
.dfCharSet
= (*(boba
->pcharset
))[j
];
447 j
= lpch
[tmp
[0]] ? 254 : 255;
452 if( !boba
) return FALSE
;
454 /* i - index into fETTable
455 * j - index into suffix array for fETTable[i]
457 * 254 - weird suffix (i.e. no '-' right after prefix )
458 * 255 - no suffix at all.
461 fi
->fi_encoding
= 256 * (UINT16
)i
+ (UINT16
)j
;
467 /*************************************************************************
470 * Note: uRelax is a treatment not a cure. Font mapping algorithm
471 * should be bulletproof enough to allow us to avoid hacks like
472 * if( uRelax == 200 ) even despite LFD being so braindead.
474 static BOOL32
LFD_ComposeLFD( fontObject
* fo
,
475 INT32 height
, LPSTR lpLFD
, UINT32 uRelax
)
477 fontEncodingTemplate
* boba
;
478 int i
, h
, w
, ch
, point
= 0;
481 char h_string
[64], point_string
[64];
483 *(lpLFD
+MAX_LFD_LENGTH
-1)=0;
484 lstrcpy32A( lpLFD
, fo
->fr
->resource
);
487 switch( fo
->fi
->df
.dfWeight
)
490 strcat( lpLFD
, "bold" ); break;
492 if( fo
->fi
->fi_flags
& FI_FW_BOOK
)
493 strcat( lpLFD
, "book" );
495 strcat( lpLFD
, "medium" );
498 strcat( lpLFD
, "demi" );
499 if( !( fo
->fi
->fi_flags
& FI_FW_DEMI
) )
500 strcat ( lpLFD
, "bold" );
503 strcat( lpLFD
, "black" ); break;
505 strcat( lpLFD
, "light" ); break;
507 strcat( lpLFD
, "*" );
511 if( fo
->fi
->df
.dfItalic
)
512 if( fo
->fi
->fi_flags
& FI_OBLIQUE
)
513 strcat( lpLFD
, "-o" );
515 strcat( lpLFD
, "-i" );
517 strcat( lpLFD
, (uRelax
< 2) ? "-r" : "-*" );
519 /* add width style and skip serifs */
520 if( fo
->fi
->fi_flags
& FI_NORMAL
)
521 strcat( lpLFD
, "-normal-*-");
523 strcat( lpLFD
, "-*-*-" );
525 /* add pixelheight, pointheight, and resolution
527 * FIXME: fill in lpXForm and lpPixmap for rotated fonts
529 if( fo
->fo_flags
& FO_SYNTH_HEIGHT
) h
= fo
->fi
->lfd_height
;
530 else h
= (fo
->fi
->lfd_height
* height
) / fo
->fi
->df
.dfPixHeight
;
532 if( XTextCaps
& TC_SF_X_YINDEP
)
534 if( fo
->lf
.lfWidth
&& !(fo
->fo_flags
& FO_SYNTH_WIDTH
) )
535 point
= (fo
->fi
->lfd_decipoints
* fo
->lf
.lfWidth
) / fo
->fi
->df
.dfAvgWidth
;
537 if( fo
->fi
->fi_flags
& FI_SCALABLE
) /* adjust h/w ratio */
538 point
= h
* 72 * 10 / fo
->fi
->lfd_resolution
;
541 /* handle rotated fonts */
542 if (fo
->lf
.lfEscapement
) {
543 /* escapement is in tenths of degrees, theta is in radians */
544 double theta
= M_PI
*fo
->lf
.lfEscapement
/1800.;
545 double h_matrix
[4] = {h
*cos(theta
), h
*sin(theta
), -h
*sin(theta
), h
*cos(theta
)};
546 double point_matrix
[4] = {point
*cos(theta
), point
*sin(theta
), -point
*sin(theta
), point
*cos(theta
)};
548 sprintf(h_string
, "[%+f%+f%+f%+f]", h_matrix
[0], h_matrix
[1], h_matrix
[2], h_matrix
[3]);
549 sprintf(point_string
, "[%+f%+f%+f%+f]", point_matrix
[0], point_matrix
[1], point_matrix
[2], point_matrix
[3]);
550 while ((s
= strchr(h_string
, '-'))) *s
='~';
551 while ((s
= strchr(point_string
, '-'))) *s
='~';
553 sprintf(h_string
, "%d", h
);
554 sprintf(point_string
, "%d", point
);
558 /* spacing and width */
560 if( fo
->fi
->fi_flags
& FI_FIXEDPITCH
)
561 w
= ( fo
->fi
->fi_flags
& FI_FIXEDEX
) ? 'c' : 'm';
563 w
= ( fo
->fi
->fi_flags
& FI_VARIABLEPITCH
) ? 'p' : LFDSeparator
[0];
567 i
= fo
->fi
->fi_encoding
>> 8;
568 for( boba
= fETTable
; i
; i
--, boba
= boba
->next
);
570 strcpy( lpEncoding
, boba
->prefix
);
572 i
= fo
->fi
->fi_encoding
& 255;
575 case 254: strcat( lpEncoding
, "*" );
579 if( (*(boba
->psuffix
))[i
] )
580 strcat( lpEncoding
, (*(boba
->psuffix
))[i
] );
582 strcat( lpEncoding
, "-*" );
585 case 255: /* no suffix */
588 lpch
= lpLFD
+ lstrlen32A(lpLFD
);
589 ch
= (fo
->fi
->fi_flags
& FI_SCALABLE
) ? '0' : LFDSeparator
[0];
593 /* RealizeFont() will call us repeatedly with increasing uRelax
594 * until XLoadFont() succeeds. */
599 sprintf( lpch
, "%s-%s-%i-%c-%c-*-%s", h_string
,
601 fo
->fi
->lfd_resolution
, ch
, w
, lpEncoding
);
607 case 2: /* 2 will have replaced an 'r' in slant by '*' */
608 sprintf( lpch
, "%s-*-%i-%c-%c-*-%s", h_string
,
609 fo
->fi
->lfd_resolution
, ch
, w
, lpEncoding
);
613 sprintf( lpch
, "%s-*-%i-%c-*-*-%s",
614 h_string
, fo
->fi
->lfd_resolution
, ch
, lpEncoding
);
618 sprintf( lpch
, "%i-*-%i-%c-*-*-%s", fo
->fi
->lfd_height
,
619 fo
->fi
->lfd_resolution
, ch
, lpEncoding
);
623 sprintf( lpch
, "%i-*-*-*-*-*-%s", fo
->fi
->lfd_height
, lpEncoding
);
627 sprintf( lpch
, "%i-*-*-*-*-*-*-*", fo
->fi
->lfd_height
);
630 /* to avoid an infinite loop; those will allways match */
632 sprintf( lpLFD
, "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1" );
635 sprintf( lpLFD
, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" );
639 TRACE(font
,"\tLFD(uRelax=%d): %s\n", uRelax
, lpLFD
);
640 assert(*(lpLFD
+MAX_LFD_LENGTH
-1)==0); /* check if overwrittem */
645 /***********************************************************************
648 * font info - http://www.microsoft.com/kb/articles/q65/1/23.htm
649 * Windows font metrics - http://www.microsoft.com/kb/articles/q32/6/67.htm
651 static BOOL32
XFONT_GetLeading( LPIFONTINFO16 pFI
, XFontStruct
* x_fs
, INT32
*
652 pIL
, INT32
* pEL
, XFONTTRANS
*XFT
)
654 unsigned long height
;
655 unsigned min
= (unsigned char)pFI
->dfFirstChar
;
656 unsigned max
= (unsigned char)pFI
->dfLastChar
;
657 BOOL32 bHaveCapHeight
= (pFI
->dfCharSet
== ANSI_CHARSET
&& 'X' >= min
&& 'X' <= max
);
662 Atom RAW_CAP_HEIGHT
= TSXInternAtom(display
, "RAW_CAP_HEIGHT", TRUE
);
663 if(TSXGetFontProperty(x_fs
, RAW_CAP_HEIGHT
, &height
))
665 (INT32
)(XFT
->pixelsize
/ 1000.0 * height
);
668 return bHaveCapHeight
&& x_fs
->per_char
;
671 if( TSXGetFontProperty(x_fs
, XA_CAP_HEIGHT
, &height
) == FALSE
)
675 height
= x_fs
->per_char
['X' - min
].ascent
;
677 if (x_fs
->ascent
>= x_fs
->max_bounds
.ascent
)
678 height
= x_fs
->max_bounds
.ascent
;
681 height
= x_fs
->ascent
;
683 *pEL
= x_fs
->max_bounds
.ascent
- height
;
686 height
= x_fs
->min_bounds
.ascent
;
689 *pIL
= x_fs
->ascent
- height
;
690 return (bHaveCapHeight
&& x_fs
->per_char
);
693 static INT32
XFONT_GetAvgCharWidth( LPIFONTINFO16 pFI
, XFontStruct
* x_fs
,
696 unsigned min
= (unsigned char)pFI
->dfFirstChar
;
697 unsigned max
= (unsigned char)pFI
->dfLastChar
;
702 for( j
= 0, width
= 0, chars
= 0, max
-= min
; j
<= max
; j
++ )
703 if( !CI_NONEXISTCHAR(x_fs
->per_char
+ j
) )
706 width
+= x_fs
->per_char
[j
].width
;
708 width
+= x_fs
->per_char
[j
].attributes
*
709 XFT
->pixelsize
/ 1000.0;
712 return (width
/ chars
);
715 return x_fs
->min_bounds
.width
;
718 static INT32
XFONT_GetMaxCharWidth(fontObject
*pfo
)
720 unsigned min
= (unsigned char)pfo
->fs
->min_char_or_byte2
;
721 unsigned max
= (unsigned char)pfo
->fs
->max_char_or_byte2
;
724 return abs(pfo
->fs
->max_bounds
.width
);
726 if( pfo
->fs
->per_char
)
729 for( j
= 0, maxwidth
= 0, max
-= min
; j
<= max
; j
++ )
730 if( !CI_NONEXISTCHAR(pfo
->fs
->per_char
+ j
) )
731 if(maxwidth
< pfo
->fs
->per_char
[j
].attributes
)
732 maxwidth
= pfo
->fs
->per_char
[j
].attributes
;
734 maxwidth
*= pfo
->lpX11Trans
->pixelsize
/ 1000.0;
737 return pfo
->foAvgCharWidth
;
740 /***********************************************************************
741 * XFONT_SetFontMetric
745 * Initializes IFONTINFO16. dfHorizRes and dfVertRes must be already set.
747 static void XFONT_SetFontMetric(fontInfo
* fi
, fontResource
* fr
, XFontStruct
* xfs
)
752 fi
->df
.dfFirstChar
= (BYTE
)(min
= xfs
->min_char_or_byte2
);
753 fi
->df
.dfLastChar
= (BYTE
)(max
= xfs
->max_char_or_byte2
);
755 fi
->df
.dfDefaultChar
= (BYTE
)xfs
->default_char
;
756 fi
->df
.dfBreakChar
= (BYTE
)(( ' ' < min
|| ' ' > max
) ? xfs
->default_char
: ' ');
758 fi
->df
.dfPixHeight
= (INT16
)((fi
->df
.dfAscent
= (INT16
)xfs
->ascent
) + xfs
->descent
);
759 fi
->df
.dfPixWidth
= (xfs
->per_char
) ? 0 : xfs
->min_bounds
.width
;
760 fi
->df
.dfMaxWidth
= (INT16
)abs(xfs
->max_bounds
.width
);
762 if( XFONT_GetLeading( &fi
->df
, xfs
, &il
, &el
, NULL
) )
763 fi
->df
.dfAvgWidth
= (INT16
)xfs
->per_char
['X' - min
].width
;
765 fi
->df
.dfAvgWidth
= (INT16
)XFONT_GetAvgCharWidth( &fi
->df
, xfs
, NULL
);
767 fi
->df
.dfInternalLeading
= (INT16
)il
;
768 fi
->df
.dfExternalLeading
= (INT16
)el
;
770 fi
->df
.dfPoints
= (INT16
)(((INT32
)(fi
->df
.dfPixHeight
-
771 fi
->df
.dfInternalLeading
) * 72 + (fi
->df
.dfVertRes
>> 1)) / fi
->df
.dfVertRes
);
773 if( xfs
->min_bounds
.width
!= xfs
->max_bounds
.width
)
774 fi
->df
.dfPitchAndFamily
|= TMPF_FIXED_PITCH
; /* au contraire! */
775 if( fi
->fi_flags
& FI_SCALABLE
)
777 fi
->df
.dfType
= DEVICE_FONTTYPE
;
778 fi
->df
.dfPitchAndFamily
|= TMPF_DEVICE
;
780 else if( fi
->fi_flags
& FI_TRUETYPE
)
781 fi
->df
.dfType
= TRUETYPE_FONTTYPE
;
783 fi
->df
.dfType
= RASTER_FONTTYPE
;
785 fi
->df
.dfFace
= fr
->lfFaceName
;
788 /***********************************************************************
789 * XFONT_GetTextMetric
791 * GetTextMetrics() back end.
793 static void XFONT_GetTextMetric( fontObject
* pfo
, LPTEXTMETRIC32A pTM
)
795 LPIFONTINFO16 pdf
= &pfo
->fi
->df
;
797 if( ! pfo
->lpX11Trans
) {
798 pTM
->tmAscent
= pfo
->fs
->ascent
;
799 pTM
->tmDescent
= pfo
->fs
->descent
;
801 pTM
->tmAscent
= pfo
->lpX11Trans
->ascent
;
802 pTM
->tmDescent
= pfo
->lpX11Trans
->descent
;
804 pTM
->tmHeight
= pTM
->tmAscent
+ pTM
->tmDescent
;
806 pTM
->tmAveCharWidth
= pfo
->foAvgCharWidth
;
807 pTM
->tmMaxCharWidth
= pfo
->foMaxCharWidth
;
809 pTM
->tmInternalLeading
= pfo
->foInternalLeading
;
810 pTM
->tmExternalLeading
= pdf
->dfExternalLeading
;
812 pTM
->tmStruckOut
= (pfo
->fo_flags
& FO_SYNTH_STRIKEOUT
)
813 ? 1 : pdf
->dfStrikeOut
;
814 pTM
->tmUnderlined
= (pfo
->fo_flags
& FO_SYNTH_UNDERLINE
)
815 ? 1 : pdf
->dfUnderline
;
818 if( pfo
->fo_flags
& FO_SYNTH_ITALIC
)
820 pTM
->tmOverhang
+= pTM
->tmHeight
/3;
823 pTM
->tmItalic
= pdf
->dfItalic
;
825 pTM
->tmWeight
= pdf
->dfWeight
;
826 if( pfo
->fo_flags
& FO_SYNTH_BOLD
)
829 pTM
->tmWeight
+= 100;
832 *(INT32
*)&pTM
->tmFirstChar
= *(INT32
*)&pdf
->dfFirstChar
;
834 pTM
->tmCharSet
= pdf
->dfCharSet
;
835 pTM
->tmPitchAndFamily
= pdf
->dfPitchAndFamily
;
837 pTM
->tmDigitizedAspectX
= pdf
->dfHorizRes
;
838 pTM
->tmDigitizedAspectY
= pdf
->dfVertRes
;
841 /***********************************************************************
842 * XFONT_GetFontMetric
844 * Retrieve font metric info (enumeration).
846 static UINT32
XFONT_GetFontMetric( fontInfo
* pfi
, LPENUMLOGFONTEX16 pLF
,
847 LPNEWTEXTMETRIC16 pTM
)
849 memset( pLF
, 0, sizeof(*pLF
) );
850 memset( pTM
, 0, sizeof(*pTM
) );
852 #define plf ((LPLOGFONT16)pLF)
853 plf
->lfHeight
= pTM
->tmHeight
= pfi
->df
.dfPixHeight
;
854 plf
->lfWidth
= pTM
->tmAveCharWidth
= pfi
->df
.dfAvgWidth
;
855 plf
->lfWeight
= pTM
->tmWeight
= pfi
->df
.dfWeight
;
856 plf
->lfItalic
= pTM
->tmItalic
= pfi
->df
.dfItalic
;
857 plf
->lfUnderline
= pTM
->tmUnderlined
= pfi
->df
.dfUnderline
;
858 plf
->lfStrikeOut
= pTM
->tmStruckOut
= pfi
->df
.dfStrikeOut
;
859 plf
->lfCharSet
= pTM
->tmCharSet
= pfi
->df
.dfCharSet
;
861 /* convert pitch values */
863 pTM
->tmPitchAndFamily
= pfi
->df
.dfPitchAndFamily
;
864 plf
->lfPitchAndFamily
= (pfi
->df
.dfPitchAndFamily
& 0xF1) + 1;
866 lstrcpyn32A( plf
->lfFaceName
, pfi
->df
.dfFace
, LF_FACESIZE
);
869 pTM
->tmAscent
= pfi
->df
.dfAscent
;
870 pTM
->tmDescent
= pTM
->tmHeight
- pTM
->tmAscent
;
871 pTM
->tmInternalLeading
= pfi
->df
.dfInternalLeading
;
872 pTM
->tmMaxCharWidth
= pfi
->df
.dfMaxWidth
;
873 pTM
->tmDigitizedAspectX
= pfi
->df
.dfHorizRes
;
874 pTM
->tmDigitizedAspectY
= pfi
->df
.dfVertRes
;
876 *(INT32
*)&pTM
->tmFirstChar
= *(INT32
*)&pfi
->df
.dfFirstChar
;
878 /* return font type */
880 return pfi
->df
.dfType
;
884 /***********************************************************************
889 * dfPitchAndFamily flags for some common typefaces.
891 static BYTE
XFONT_FixupFlags( LPCSTR lfFaceName
)
893 switch( lfFaceName
[0] )
896 case 'H': if(!strcasecmp(lfFaceName
, "Helvetica") )
900 case 'C': if(!strcasecmp(lfFaceName
, "Courier") ||
901 !strcasecmp(lfFaceName
, "Charter") )
905 case 'P': if( !strcasecmp(lfFaceName
,"Palatino") )
909 case 'T': if(!strncasecmp(lfFaceName
, "Times", 5) )
913 case 'U': if(!strcasecmp(lfFaceName
, "Utopia") )
917 case 'Z': if(!strcasecmp(lfFaceName
, "Zapf Dingbats") )
918 return FF_DECORATIVE
;
924 /***********************************************************************
925 * XFONT_CheckResourceName
929 static BOOL32
XFONT_CheckResourceName( LPSTR resource
, LPCSTR name
, INT32 n
)
931 resource
= LFD_Advance( resource
, 2 );
933 return (!strncasecmp( resource
, name
, n
));
938 /***********************************************************************
943 * Build generic Windows aliases for X font names.
945 * -misc-fixed- -> "Fixed"
946 * -sony-fixed- -> "Sony Fixed", etc...
948 static void XFONT_WindowsNames( char* buffer
)
950 fontResource
* fr
, *pfr
;
954 const char* relocTable
[] = { INIDefaultFixed
, INIDefault
, NULL
};
956 for( fr
= fontList
; fr
; fr
= fr
->next
)
958 if( fr
->fr_flags
& FR_NAMESET
) continue; /* skip already assigned */
960 lpstr
= LFD_Advance(fr
->resource
, 2);
961 i
= LFD_Advance( lpstr
, 1 ) - lpstr
;
963 for( pfr
= fontList
; pfr
!= fr
; pfr
= pfr
->next
)
964 if( pfr
->fr_flags
& FR_NAMESET
)
965 if( XFONT_CheckResourceName( pfr
->resource
, lpstr
, i
) )
968 if( pfr
!= fr
) /* prepend vendor name */
969 lpstr
= fr
->resource
+ 1;
971 for( i
= 0, up
= 1, lpch
= fr
->lfFaceName
; *lpstr
&& i
< 32;
972 lpch
++, lpstr
++, i
++ )
974 if( *lpstr
== LFDSeparator
[1] || *lpstr
== ' ' )
979 else if( isalpha(*lpstr
) && up
)
981 *lpch
= toupper(*lpstr
);
986 while (*(lpch
- 1) == ' ') *(--lpch
) = '\0';
988 if( (bFamilyStyle
= XFONT_FixupFlags( fr
->lfFaceName
)) )
991 for( fi
= fr
->fi
; fi
; fi
= fi
->next
)
992 fi
->df
.dfPitchAndFamily
|= bFamilyStyle
;
995 TRACE(font
,"typeface \'%s\'\n", fr
->lfFaceName
);
997 fr
->fr_flags
|= FR_NAMESET
;
1000 for( up
= 0; relocTable
[up
]; up
++ )
1001 if( PROFILE_GetWineIniString( INIFontSection
, relocTable
[up
], "", buffer
, 128 ) )
1003 while( *buffer
&& isspace(*buffer
) ) buffer
++;
1004 for( fr
= NULL
, pfr
= fontList
; pfr
; pfr
= pfr
->next
)
1006 i
= strlen( pfr
->resource
);
1007 if( !strncasecmp( pfr
->resource
, buffer
, i
) )
1011 fr
->next
= pfr
->next
;
1012 pfr
->next
= fontList
;
1022 /***********************************************************************
1025 static fontAlias
* XFONT_CreateAlias( LPCSTR lpTypeFace
, LPCSTR lpAlias
)
1028 fontAlias
* pfa
= aliasTable
;
1032 /* check if we already got one */
1033 if( !strcasecmp( pfa
->faTypeFace
, lpAlias
) )
1035 TRACE(font
,"\tredundant alias '%s' -> '%s'\n",
1036 lpAlias
, lpTypeFace
);
1039 if( pfa
->next
) pfa
= pfa
->next
;
1043 j
= lstrlen32A(lpTypeFace
) + 1;
1044 pfa
->next
= HeapAlloc( SystemHeap
, 0, sizeof(fontAlias
) +
1045 j
+ lstrlen32A(lpAlias
) + 1 );
1046 if((pfa
= pfa
->next
))
1049 pfa
->faTypeFace
= (LPSTR
)(pfa
+ 1);
1050 lstrcpy32A( pfa
->faTypeFace
, lpTypeFace
);
1051 pfa
->faAlias
= pfa
->faTypeFace
+ j
;
1052 lstrcpy32A( pfa
->faAlias
, lpAlias
);
1054 TRACE(font
, "\tadded alias '%s' for %s\n", lpAlias
, lpTypeFace
);
1061 /***********************************************************************
1064 * Read user-defined aliases from wine.conf. Format is as follows
1066 * Alias# = [Windows font name],[LFD font name], <substitute original name>
1069 * Alias0 = Arial, -adobe-helvetica-
1070 * Alias1 = Times New Roman, -bitstream-courier-, 1
1073 * Note that from 081797 and on we have built-in alias templates that take
1074 * care of the necessary Windows typefaces.
1076 static void XFONT_LoadAliases( char** buffer
, int *buf_size
)
1078 char* lpResource
, *lpAlias
;
1079 char subsection
[32];
1081 BOOL32 bHaveAlias
= TRUE
, bSubst
= FALSE
;
1083 if( *buf_size
< 128 )
1085 *buffer
= HeapReAlloc(SystemHeap
, 0, *buffer
, 256 );
1090 if( j
< faTemplateNum
)
1092 /* built-in templates first */
1094 lpResource
= faTemplate
[j
].fatResource
;
1095 lpAlias
= faTemplate
[j
].fatAlias
;
1100 /* then WINE.CONF */
1102 wsprintf32A( subsection
, "%s%i", INIAliasSection
, i
++ );
1104 if( (bHaveAlias
= PROFILE_GetWineIniString( INIFontSection
,
1105 subsection
, "", *buffer
, 128 )) )
1108 while( isspace(*lpAlias
) ) lpAlias
++;
1109 lpResource
= PROFILE_GetStringItem( lpAlias
);
1110 bSubst
= (PROFILE_GetStringItem( lpResource
)) ? TRUE
: FALSE
;
1118 length
= strlen( lpAlias
);
1119 if( lpResource
&& length
)
1121 fontResource
* fr
, *frMatch
= NULL
;
1123 for (fr
= fontList
; fr
; fr
= fr
->next
)
1125 if( !strcasecmp( fr
->resource
, lpResource
) ) frMatch
= fr
;
1126 if( XFONT_CheckResourceName( fr
->resource
, lpAlias
, length
) )
1128 /* alias is not needed since the real font is present */
1129 frMatch
= NULL
; break;
1137 fontAlias
*pfa
, *prev
= NULL
;
1139 for(pfa
= aliasTable
; pfa
; pfa
= pfa
->next
)
1141 /* Remove lpAlias from aliasTable - we should free the old entry */
1142 if(!strcmp(lpAlias
, pfa
->faAlias
))
1145 prev
->next
= pfa
->next
;
1147 aliasTable
= pfa
->next
;
1150 /* Update any references to the substituted font in aliasTable */
1151 if(!strcmp(frMatch
->lfFaceName
,
1153 pfa
->faTypeFace
= HEAP_strdupA( SystemHeap
, 0,
1158 TRACE(font
, "\tsubstituted '%s' with %s\n",
1159 frMatch
->lfFaceName
, lpAlias
);
1161 lstrcpyn32A( frMatch
->lfFaceName
, lpAlias
, LF_FACESIZE
);
1162 frMatch
->fr_flags
|= FR_NAMESET
;
1166 /* create new entry in the alias table */
1167 XFONT_CreateAlias( frMatch
->lfFaceName
, lpAlias
);
1171 else ERR(font
, " malformed font alias '%s'\n", *buffer
);
1177 /***********************************************************************
1178 * XFONT_LoadPenalties
1180 * Removes specified fonts from the font table to prevent Wine from
1183 * Ignore# = [LFD font name]
1186 * Ignore0 = -misc-nil-
1187 * Ignore1 = -sun-open look glyph-
1191 static void XFONT_LoadPenalties( char** buffer
, int *buf_size
)
1194 char subsection
[32];
1196 if( *buf_size
< 128 )
1198 *buffer
= HeapReAlloc(SystemHeap
, 0, *buffer
, 256 );
1204 wsprintf32A( subsection
, "%s%i", INIIgnoreSection
, i
++ );
1206 if( PROFILE_GetWineIniString( INIFontSection
,
1207 subsection
, "", *buffer
, 255 ) )
1209 fontResource
** ppfr
;
1210 int length
= strlen( *buffer
);
1212 for( ppfr
= &fontList
; *ppfr
; ppfr
= &((*ppfr
)->next
))
1214 if( !strncasecmp( (*ppfr
)->resource
, *buffer
, length
) )
1216 TRACE(font
, "Ignoring '%s'\n", (*ppfr
)->resource
);
1218 XFONT_RemoveFontResource( ppfr
);
1228 /***********************************************************************
1229 * XFONT_UserMetricsCache
1231 * Returns expanded name for the ~/.wine/.cachedmetrics file.
1232 * Now it also appends the current value of the $DISPLAY varaible.
1234 static char* XFONT_UserMetricsCache( char* buffer
, int* buf_size
)
1239 pchDisplay
= getenv( "DISPLAY" );
1240 if( !pchDisplay
) pchDisplay
= "0";
1242 pwd
= getpwuid(getuid());
1243 if( pwd
&& pwd
->pw_dir
)
1245 int i
= strlen( pwd
->pw_dir
) + strlen( INIWinePrefix
) +
1246 strlen( INIFontMetrics
) + strlen( pchDisplay
) + 2;
1248 buffer
= (char*) HeapReAlloc( SystemHeap
, 0, buffer
, *buf_size
= i
);
1249 strcpy( buffer
, pwd
->pw_dir
);
1250 strcat( buffer
, INIWinePrefix
);
1251 strcat( buffer
, INIFontMetrics
);
1252 strcat( buffer
, pchDisplay
);
1253 } else buffer
[0] = '\0';
1258 /***********************************************************************
1259 * XFONT_ReadCachedMetrics
1263 static BOOL32
XFONT_ReadCachedMetrics( int fd
, int res
, unsigned x_checksum
, int x_count
)
1270 /* read checksums */
1271 read( fd
, &u
, sizeof(unsigned) );
1272 read( fd
, &i
, sizeof(int) );
1274 if( u
== x_checksum
&& i
== x_count
)
1276 off_t length
, offset
= 3 * sizeof(int);
1278 /* read total size */
1279 read( fd
, &i
, sizeof(int) );
1280 length
= lseek( fd
, 0, SEEK_END
);
1282 if( length
== (i
+ offset
) )
1284 lseek( fd
, offset
, SEEK_SET
);
1285 fontList
= (fontResource
*)HeapAlloc( SystemHeap
, 0, i
);
1288 fontResource
* pfr
= fontList
;
1289 fontInfo
* pfi
= NULL
;
1291 TRACE(font
,"Reading cached font metrics:\n");
1293 read( fd
, fontList
, i
); /* read all metrics at once */
1294 while( offset
< length
)
1296 offset
+= sizeof(fontResource
) + sizeof(fontInfo
);
1297 pfr
->fi
= pfi
= (fontInfo
*)(pfr
+ 1);
1301 if( offset
> length
||
1302 (int)(pfi
->next
) != j
++ ) goto fail
;
1304 pfi
->df
.dfFace
= pfr
->lfFaceName
;
1305 pfi
->df
.dfHorizRes
= pfi
->df
.dfVertRes
= res
;
1306 pfi
->df
.dfPoints
= (INT16
)(((INT32
)(pfi
->df
.dfPixHeight
-
1307 pfi
->df
.dfInternalLeading
) * 72 + (res
>> 1)) / res
);
1308 pfi
->next
= pfi
+ 1;
1310 if( j
> pfr
->fi_count
) break;
1313 offset
+= sizeof(fontInfo
);
1318 pfr
->next
= (fontResource
*)(pfi
+ 1);
1323 if( pfr
->next
== NULL
&&
1324 *(int*)(pfi
+ 1) == X_FMC_MAGIC
)
1326 /* read LFD stubs */
1327 char* lpch
= (char*)((int*)(pfi
+ 1) + 1);
1328 offset
+= sizeof(int);
1329 for( pfr
= fontList
; pfr
; pfr
= pfr
->next
)
1331 TRACE(font
,"\t%s, %i instances\n", lpch
, pfr
->fi_count
);
1332 pfr
->resource
= lpch
;
1335 if( ++offset
> length
) goto fail
;
1336 if( !*lpch
++ ) break;
1346 if( fontList
) HeapFree( SystemHeap
, 0, fontList
);
1353 /***********************************************************************
1354 * XFONT_WriteCachedMetrics
1358 static BOOL32
XFONT_WriteCachedMetrics( int fd
, unsigned x_checksum
, int x_count
, int n_ff
)
1367 /* font metrics file:
1371 * +0008 total size to load
1372 * +000C prepackaged font metrics
1375 * +...x + 4 LFD stubs
1378 write( fd
, &x_checksum
, sizeof(unsigned) );
1379 write( fd
, &x_count
, sizeof(int) );
1381 for( j
= i
= 0, pfr
= fontList
; pfr
; pfr
= pfr
->next
)
1383 i
+= strlen( pfr
->resource
) + 1;
1386 i
+= n_ff
* sizeof(fontResource
) + j
* sizeof(fontInfo
) + sizeof(int);
1387 write( fd
, &i
, sizeof(int) );
1389 TRACE(font
,"Writing font cache:\n");
1391 for( pfr
= fontList
; pfr
; pfr
= pfr
->next
)
1395 TRACE(font
,"\t%s, %i instances\n", pfr
->resource
, pfr
->fi_count
);
1397 i
= write( fd
, pfr
, sizeof(fontResource
) );
1398 if( i
== sizeof(fontResource
) )
1400 for( k
= 1, pfi
= pfr
->fi
; pfi
; pfi
= pfi
->next
)
1402 memcpy( &fi
, pfi
, sizeof(fi
) );
1404 fi
.df
.dfFace
= NULL
;
1405 fi
.next
= (fontInfo
*)k
; /* loader checks this */
1407 j
= write( fd
, &fi
, sizeof(fi
) );
1410 if( j
== sizeof(fontInfo
) ) continue;
1414 if( i
== sizeof(fontResource
) && j
== sizeof(fontInfo
) )
1416 i
= j
= X_FMC_MAGIC
;
1417 write( fd
, &i
, sizeof(int) );
1418 for( pfr
= fontList
; pfr
&& i
== j
; pfr
= pfr
->next
)
1420 i
= strlen( pfr
->resource
) + 1;
1421 j
= write( fd
, pfr
->resource
, i
);
1430 /***********************************************************************
1431 * XFONT_CheckIniSection
1435 * Examines wine.conf for old/invalid font entries and recommend changes to
1439 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
1440 * Original implementation.
1442 static void XFONT_CheckIniCallback(char const *, char const *, void *);
1444 static char const *fontmsgprologue
=
1446 " The following entries in the [fonts] section of the wine.conf file are\n"
1447 " obsolete or invalid:\n";
1449 static char const *fontmsgepilogue
=
1450 " These entries should be eliminated or updated.\n"
1451 " See the documentation/fonts file for more information.\n";
1453 static int XFONT_CheckIniSection()
1457 PROFILE_EnumerateWineIniSection("Fonts", &XFONT_CheckIniCallback
,
1460 MSG(fontmsgepilogue
);
1465 static void XFONT_CheckIniCallback(
1470 /* Ignore any keys that start with potential comment characters "'", '#',
1472 if(key
[0] == '\'' || key
[0] == '#' || key
[0] == ';' || key
[0] == '\0')
1475 /* Make sure this is a valid key */
1476 if((strncasecmp(key
, INIAliasSection
, 5) == 0) ||
1477 (strncasecmp(key
, INIIgnoreSection
, 6) == 0) ||
1478 (strcasecmp( key
, INIDefault
) == 0) ||
1479 (strcasecmp( key
, INIDefaultFixed
) == 0) ||
1480 (strcasecmp( key
, INIGlobalMetrics
) == 0) ||
1481 (strcasecmp( key
, INIResolution
) == 0) ||
1482 (strcasecmp( key
, INIDefaultSerif
) == 0) ||
1483 (strcasecmp( key
, INIDefaultSansSerif
) ==0) )
1485 /* Valid key; make sure the value doesn't contain a wildcard */
1486 if(strchr(value
, '*')) {
1487 if(*(int *)found
== 0) {
1488 MSG(fontmsgprologue
);
1492 MSG(" %s=%s [no wildcards allowed]\n", key
, value
);
1496 /* Not a valid key */
1497 if(*(int *)found
== 0) {
1498 MSG(fontmsgprologue
);
1502 MSG(" %s=%s [obsolete]\n", key
, value
);
1508 /***********************************************************************
1509 * XFONT_GetPointResolution()
1513 * Here we initialize DefResolution which is used in the
1514 * XFONT_Match() penalty function. We also load the point
1515 * resolution value (higher values result in larger fonts).
1517 static int XFONT_GetPointResolution( DeviceCaps
* pDevCaps
)
1519 int i
, j
, point_resolution
, num
= 3;
1520 int allowed_xfont_resolutions
[3] = { 72, 75, 100 };
1521 int best
= 0, best_diff
= 65536;
1523 DefResolution
= point_resolution
= PROFILE_GetWineIniInt( INIFontSection
, INIResolution
, 0 );
1524 if( !DefResolution
) DefResolution
= point_resolution
= pDevCaps
->logPixelsY
;
1525 else pDevCaps
->logPixelsX
= pDevCaps
->logPixelsY
= DefResolution
;
1527 for( i
= best
= 0; i
< num
; i
++ )
1529 j
= abs( DefResolution
- allowed_xfont_resolutions
[i
] );
1536 DefResolution
= allowed_xfont_resolutions
[best
];
1537 return point_resolution
;
1540 /***********************************************************************
1541 * XFONT_BuildDefaultAliases
1545 * Alias "Helv", and "Tms Rmn" to the DefaultSansSerif and DefaultSerif
1546 * fonts respectively. Create font alias templates for "MS Sans Serif"
1547 * and "MS Serif", also pointing to DefaultSansSerif and DefaultSerif.
1549 static int XFONT_BuildDefaultAliases( char** buffer
, int* buf_size
)
1552 aliasTemplate fatDefaultSerif
= { "-bitstream-charter-", "Charter" };
1553 aliasTemplate fatDefaultSansSerif
= { "-adobe-helvetica-", "Helvetica" };
1557 /* Make sure our buffer is big enough; update calling function's
1558 buf_size if we change it. */
1560 if( *buf_size
< 128 )
1562 *buffer
= HeapReAlloc( SystemHeap
, 0, *buffer
, 256 );
1566 /* Get the X11 name of the default serif font from the Wine INI file.
1567 (-bitstream-charter- is the default.) */
1569 PROFILE_GetWineIniString( INIFontSection
, INIDefaultSerif
,
1570 fatDefaultSerif
.fatResource
, *buffer
, 128 );
1572 /* Find the Windows typeface which corresponds to the X11 font. */
1574 for( fr
= fontList
; fr
; fr
= fr
->next
)
1575 if( !strcasecmp( fr
->resource
, *buffer
) ) break;
1577 /* Update the Alias Table entry for "Tms Rmn" with the default serif font's
1578 typeface. Update the Alias Template for "MS Serif" with the default
1579 serif font's X11 name. Note that this method leaves us dependant on
1580 the order of the Alias Table and the Alias Templates. Also, we don't
1581 check for or handle a situation in which -bitstream-charter- is not
1586 TRACE(font
, "Using \'%s\' as default serif font\n", fr
->lfFaceName
);
1587 aliasTable
[1].faTypeFace
= fr
->lfFaceName
;
1588 faTemplate
[1].fatResource
= fr
->resource
;
1592 WARN(font
, "No typeface found for \'%s\'; using \'%s\'\n", *buffer
,
1593 fatDefaultSerif
.fatAlias
);
1594 aliasTable
[1].faTypeFace
= fatDefaultSerif
.fatAlias
; /* Charter */
1595 faTemplate
[1].fatResource
= fatDefaultSerif
.fatResource
;
1598 /* Get the X11 name of the default sans serif font from the Wine INI file.
1599 (-adobe-helvetica- is the default.) */
1601 PROFILE_GetWineIniString (INIFontSection
, INIDefaultSansSerif
,
1602 fatDefaultSansSerif
.fatResource
, *buffer
, 128 );
1604 /* Find the Windows typeface which corresponds to the X11 font. */
1606 for( fr
= fontList
; fr
; fr
= fr
->next
)
1607 if ( !strcasecmp( fr
->resource
, *buffer
) ) break;
1609 /* Update the Alias Table entry for "Helv" with the default sans serif font's
1610 typeface. Update the Alias Template for "MS Sans Serif" with the
1611 default sans serif font's X11 name. Note that this method leaves us
1612 dependant on the order of the Alias Table and the Alias Templates.
1613 Also, we don't check for or handle a situation in which
1614 -adobe-helvetica- is not available. */
1618 TRACE(font
, "Using \'%s\' as default sans serif font\n", fr
->lfFaceName
);
1619 aliasTable
[0].faTypeFace
= fr
->lfFaceName
;
1620 faTemplate
[0].fatResource
= fr
->resource
;
1624 WARN(font
, "No typeface found for \'%s\'; using \'%s\'\n", *buffer
,
1625 fatDefaultSansSerif
.fatAlias
);
1626 aliasTable
[0].faTypeFace
= fatDefaultSansSerif
.fatAlias
; /* Helvetica */
1627 faTemplate
[0].fatResource
= fatDefaultSansSerif
.fatResource
;
1633 /***********************************************************************
1636 * Initialize font resource list and allocate font cache.
1638 BOOL32
X11DRV_FONT_Init( DeviceCaps
* pDevCaps
)
1641 fontResource
* fr
, *pfr
;
1643 unsigned x_checksum
;
1644 int i
, j
, res
, x_count
, fd
= -1, buf_size
= 0;
1645 char* lpstr
, *lpch
, *lpmetrics
, *buffer
;
1648 XFONT_CheckIniSection();
1650 res
= XFONT_GetPointResolution( pDevCaps
);
1652 x_pattern
= TSXListFonts(display
, "*", MAX_FONT_FAMILIES
* 16, &x_count
);
1654 TRACE(font
,"Font Mapper: initializing %i fonts [LPY=%i, XDR=%i, DR=%i]\n",
1655 x_count
, pDevCaps
->logPixelsY
, DefResolution
, res
);
1656 for( i
= x_checksum
= 0; i
< x_count
; i
++ )
1659 printf("%i\t: %s\n", i
, x_pattern
[i
] );
1662 j
= strlen( x_pattern
[i
] );
1663 if( j
) x_checksum
^= __genericCheckSum( x_pattern
[i
], j
);
1665 x_checksum
|= X_PFONT_MAGIC
;
1668 buffer
= HeapAlloc( SystemHeap
, 0, buf_size
);
1671 /* deal with systemwide font metrics cache */
1673 if( PROFILE_GetWineIniString( INIFontSection
, INIGlobalMetrics
, "", buffer
, 128 ) )
1674 fd
= open( buffer
, O_RDONLY
);
1676 if( XFONT_ReadCachedMetrics(fd
, res
, x_checksum
, x_count
) == FALSE
)
1679 buffer
= XFONT_UserMetricsCache( buffer
, &buf_size
);
1682 fd
= open( buffer
, O_RDONLY
);
1683 if( XFONT_ReadCachedMetrics(fd
, res
, x_checksum
, x_count
) == FALSE
)
1684 lpmetrics
= HEAP_strdupA( SystemHeap
, 0, buffer
); /* update later on */
1689 if( fontList
== NULL
) /* build metrics from scratch */
1694 for( i
= n_ff
= 0; i
< x_count
; i
++ )
1696 typeface
= lpch
= x_pattern
[i
];
1698 lpch
= LFD_Advance(typeface
, 3); /* extra '-' in the beginning */
1699 if( !*lpch
) continue;
1702 j
= lpch
- typeface
; /* resource name length */
1704 /* find a family to insert into */
1706 for( pfr
= NULL
, fr
= fontList
; fr
; fr
= fr
->next
)
1708 if( !strncasecmp(fr
->resource
, typeface
, j
) &&
1709 strlen(fr
->resource
) == j
) break;
1713 if( !fi
) fi
= (fontInfo
*) HeapAlloc(SystemHeap
, 0, sizeof(fontInfo
));
1715 if( !fr
) /* add new family */
1717 if( n_ff
>= MAX_FONT_FAMILIES
) break;
1718 if( !LFD_InitFontInfo( fi
, lpstr
) ) continue;
1721 fr
= (fontResource
*) HeapAlloc(SystemHeap
, 0, sizeof(fontResource
));
1722 memset(fr
, 0, sizeof(fontResource
));
1723 fr
->resource
= (char*) HeapAlloc(SystemHeap
, 0, j
+ 1 );
1724 lstrcpyn32A( fr
->resource
, typeface
, j
+ 1 );
1726 TRACE(font
," family: %s\n", fr
->resource
);
1728 if( pfr
) pfr
->next
= fr
;
1731 else if( !LFD_InitFontInfo( fi
, lpstr
) ) continue;
1733 /* check if we already have something better than "fi" */
1735 for( pfi
= fr
->fi
, j
= 0; pfi
&& j
<= 0; pfi
= pfi
->next
)
1736 if( (j
= XFONT_IsSubset( pfi
, fi
)) < 0 )
1737 pfi
->fi_flags
|= FI_SUBSET
; /* superseded by "fi" */
1738 if( j
> 0 ) continue;
1740 /* add new font instance "fi" to the "fr" font resource */
1742 if( fi
->fi_flags
& FI_SCALABLE
)
1744 /* set scalable font height to 24 to get an origin for extrapolation */
1746 j
= strlen(typeface
); j
+= 0x10;
1748 buffer
= (char*)HeapReAlloc( SystemHeap
, 0, buffer
, buf_size
= j
);
1750 lpch
= LFD_Advance(typeface
, 7);
1751 memcpy( buffer
, typeface
, (j
= lpch
- typeface
) );
1752 lpch
= LFD_Advance(lpch
, 4);
1753 sprintf( buffer
+ j
, "%d-%d-%d-*-%c-*-", fi
->lfd_height
,
1754 fi
->lfd_decipoints
, fi
->lfd_resolution
,
1755 (*lpch
== '-')?'*':*lpch
);
1756 lpch
= LFD_Advance(lpch
, 2);
1757 strcat( lpstr
= buffer
, lpch
);
1759 else lpstr
= typeface
;
1761 if( (x_fs
= TSXLoadQueryFont(display
, lpstr
)) )
1763 fi
->df
.dfHorizRes
= fi
->df
.dfVertRes
= res
;
1765 XFONT_SetFontMetric( fi
, fr
, x_fs
);
1766 TSXFreeFont( display
, x_fs
);
1768 TRACE(font
,"\t[% 2ipt] '%s'\n", fi
->df
.dfPoints
, typeface
);
1770 XFONT_CheckFIList( fr
, fi
, REMOVE_SUBSETS
);
1771 fi
= NULL
; /* preventing reuse */
1775 ERR(font
, "failed to load %s\n", lpstr
);
1777 XFONT_CheckFIList( fr
, fi
, UNMARK_SUBSETS
);
1781 if( lpmetrics
) /* update cached metrics */
1783 fd
= open( lpmetrics
, O_CREAT
| O_TRUNC
| O_RDWR
, 0644 ); /* -rw-r--r-- */
1784 if( XFONT_WriteCachedMetrics( fd
, x_checksum
, x_count
, n_ff
) == FALSE
)
1785 if( fd
) remove( lpmetrics
); /* couldn't write entire file */
1786 HeapFree( SystemHeap
, 0, lpmetrics
);
1790 if( fi
) HeapFree(SystemHeap
, 0, fi
);
1791 TSXFreeFontNames(x_pattern
);
1793 /* check if we're dealing with X11 R6 server */
1795 strcpy(buffer
, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
1796 if( (x_fs
= TSXLoadQueryFont(display
, buffer
)) )
1798 XTextCaps
|= TC_SF_X_YINDEP
;
1799 TSXFreeFont(display
, x_fs
);
1802 XFONT_WindowsNames( buffer
);
1803 XFONT_BuildDefaultAliases( &buffer
, &buf_size
);
1804 XFONT_LoadAliases( &buffer
, &buf_size
);
1805 XFONT_LoadPenalties( &buffer
, &buf_size
);
1806 HeapFree(SystemHeap
, 0, buffer
);
1808 InitializeCriticalSection( &crtsc_fonts_X11
);
1810 /* fontList initialization is over, allocate X font cache */
1812 fontCache
= (fontObject
*) HeapAlloc(SystemHeap
, 0, fontCacheSize
* sizeof(fontObject
));
1813 XFONT_GrowFreeList(0, fontCacheSize
- 1);
1815 TRACE(font
,"done!\n");
1817 /* update text caps parameter */
1819 pDevCaps
->textCaps
= XTextCaps
;
1821 RAW_ASCENT
= TSXInternAtom(display
, "RAW_ASCENT", TRUE
);
1822 RAW_DESCENT
= TSXInternAtom(display
, "RAW_DESCENT", TRUE
);
1828 /***********************************************************************
1829 * XFONT_RemoveFontResource
1831 * Caller should check if the font resource is in use. If it is it should
1832 * set FR_REMOVED flag to delay removal until the resource is not in use
1835 void XFONT_RemoveFontResource( fontResource
** ppfr
)
1838 fontResource
* pfr
= *ppfr
;
1843 pfi
= pfr
->fi
->next
;
1844 HeapFree( SystemHeap
, 0, pfr
->fi
);
1847 HeapFree( SystemHeap
, 0, pfr
);
1850 /***********************************************************************
1853 * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1855 static INT32
XFONT_IsSubset(fontInfo
* match
, fontInfo
* fi
)
1859 /* 0 - keep both, 1 - keep match, -1 - keep fi */
1861 m
= (BYTE
*)&fi
->df
.dfPixWidth
- (BYTE
*)&fi
->df
.dfItalic
;
1862 if( memcmp(&match
->df
.dfItalic
, &fi
->df
.dfItalic
, m
)) return 0;
1864 if( (!((fi
->fi_flags
& FI_SCALABLE
) + (match
->fi_flags
& FI_SCALABLE
))
1865 && fi
->lfd_height
!= match
->lfd_height
) ||
1866 (!((fi
->fi_flags
& FI_POLYWEIGHT
) + (match
->fi_flags
& FI_POLYWEIGHT
))
1867 && fi
->df
.dfWeight
!= match
->df
.dfWeight
) ) return 0;
1869 m
= (int)(match
->fi_flags
& (FI_POLYWEIGHT
| FI_SCALABLE
)) -
1870 (int)(fi
->fi_flags
& (FI_SCALABLE
| FI_POLYWEIGHT
));
1872 if( m
== (FI_POLYWEIGHT
- FI_SCALABLE
) ||
1873 m
== (FI_SCALABLE
- FI_POLYWEIGHT
) ) return 0; /* keep both */
1874 else if( m
>= 0 ) return 1; /* 'match' is better */
1876 return -1; /* 'fi' is better */
1879 /***********************************************************************
1882 * Compute the matching score between the logical font and the device font.
1884 * contributions from highest to lowest:
1888 * family flags (only when the facename is not present)
1890 * weight, italics, underlines, strikeouts
1892 * NOTE: you can experiment with different penalty weights to see what happens.
1893 * http://premium.microsoft.com/msdn/library/techart/f365/f36b/f37b/d38b/sa8bf.htm
1895 static UINT32
XFONT_Match( fontMatch
* pfm
)
1897 fontInfo
* pfi
= pfm
->pfi
; /* device font to match */
1898 LPLOGFONT16 plf
= pfm
->plf
; /* wanted logical font */
1900 BOOL32 bR6
= pfm
->flags
& FO_MATCH_XYINDEP
; /* from TextCaps */
1901 BOOL32 bScale
= pfi
->fi_flags
& FI_SCALABLE
;
1904 TRACE(font
,"\t[ %-2ipt h=%-3i w=%-3i %s%s]\n", pfi
->df
.dfPoints
,
1905 pfi
->df
.dfPixHeight
, pfi
->df
.dfAvgWidth
,
1906 (pfi
->df
.dfWeight
> 400) ? "Bold " : "Normal ",
1907 (pfi
->df
.dfItalic
) ? "Italic" : "" );
1911 if( plf
->lfCharSet
== DEFAULT_CHARSET
)
1913 if( (pfi
->df
.dfCharSet
!= ANSI_CHARSET
) && (pfi
->df
.dfCharSet
!=DEFAULT_CHARSET
) )
1916 else if (plf
->lfCharSet
!= pfi
->df
.dfCharSet
) penalty
+= 0x200;
1918 /* FIXME: Hack to demote symbols and nil fonts. Should take into
1919 account if a program ever actually asked for this type of
1921 if ( (strcmp(pfm
->pfr
->lfFaceName
,"Symbol")==0) || (strcmp(pfm
->pfr
->lfFaceName
,"Nil")==0) )
1922 penalty
+= 0x200; /* very stiff penality */
1924 /* TMPF_FIXED_PITCH means exactly the opposite */
1926 if( plf
->lfPitchAndFamily
& FIXED_PITCH
)
1928 if( pfi
->df
.dfPitchAndFamily
& TMPF_FIXED_PITCH
) penalty
+= 0x100;
1930 else if( !(pfi
->df
.dfPitchAndFamily
& TMPF_FIXED_PITCH
) ) penalty
+= 0x2;
1932 if( plf
->lfHeight
> 0 )
1933 d
= (h
= pfi
->df
.dfPixHeight
) - plf
->lfHeight
;
1934 else if( plf
->lfHeight
< -1 )
1935 d
= (h
= pfi
->df
.dfPoints
) + plf
->lfHeight
;
1938 if( d
&& plf
->lfHeight
)
1940 UINT16 height
= ( plf
->lfHeight
> 0 ) ? plf
->lfHeight
1941 : ((-plf
->lfHeight
* pfi
->df
.dfPixHeight
) / h
);
1942 if( bScale
) pfm
->height
= height
;
1943 else if( (plf
->lfQuality
!= PROOF_QUALITY
) && bR6
)
1945 if( d
> 0 ) /* do not shrink raster fonts */
1947 pfm
->height
= pfi
->df
.dfPixHeight
;
1948 penalty
+= (pfi
->df
.dfPixHeight
- height
) * 0x4;
1950 else /* expand only in integer multiples */
1952 pfm
->height
= height
- height
%pfi
->df
.dfPixHeight
;
1953 penalty
+= (height
- pfm
->height
+ 1) * height
/ pfi
->df
.dfPixHeight
;
1956 else /* can't be scaled at all */
1958 if( plf
->lfQuality
!= PROOF_QUALITY
) pfm
->flags
|= FO_SYNTH_HEIGHT
;
1959 pfm
->height
= pfi
->df
.dfPixHeight
;
1960 penalty
+= (d
> 0)? d
* 0x8 : -d
* 0x10;
1962 } else pfm
->height
= pfi
->df
.dfPixHeight
;
1964 if((pfm
->flags
& FO_MATCH_PAF
) &&
1965 (plf
->lfPitchAndFamily
& FF_FAMILY
) != (pfi
->df
.dfPitchAndFamily
& FF_FAMILY
) )
1970 if( bR6
&& bScale
) h
= 0;
1973 /* FIXME: not complete */
1975 pfm
->flags
|= FO_SYNTH_WIDTH
;
1976 h
= abs(plf
->lfWidth
- (pfm
->height
* pfi
->df
.dfAvgWidth
)/pfi
->df
.dfPixHeight
);
1978 penalty
+= h
* ( d
) ? 0x2 : 0x1 ;
1980 else if( !(pfi
->fi_flags
& FI_NORMAL
) ) penalty
++;
1982 if( plf
->lfWeight
!= FW_DONTCARE
)
1984 penalty
+= abs(plf
->lfWeight
- pfi
->df
.dfWeight
) / 40;
1985 if( plf
->lfWeight
> pfi
->df
.dfWeight
) pfm
->flags
|= FO_SYNTH_BOLD
;
1986 } else if( pfi
->df
.dfWeight
>= FW_BOLD
) penalty
++; /* choose normal by default */
1988 if( plf
->lfItalic
!= pfi
->df
.dfItalic
)
1991 pfm
->flags
|= FO_SYNTH_ITALIC
;
1994 if( plf
->lfUnderline
) pfm
->flags
|= FO_SYNTH_UNDERLINE
;
1995 if( plf
->lfStrikeOut
) pfm
->flags
|= FO_SYNTH_STRIKEOUT
;
1997 if( penalty
&& pfi
->lfd_resolution
!= DefResolution
)
2000 TRACE(font
," returning %i\n", penalty
);
2005 /***********************************************************************
2008 * Scan a particular font resource for the best match.
2010 static UINT32
XFONT_MatchFIList( fontMatch
* pfm
)
2012 BOOL32 skipRaster
= (pfm
->flags
& FO_MATCH_NORASTER
);
2013 UINT32 current_score
, score
= (UINT32
)(-1);
2014 UINT16 origflags
= pfm
->flags
; /* Preserve FO_MATCH_XYINDEP */
2015 fontMatch fm
= *pfm
;
2017 for( fm
.pfi
= pfm
->pfr
->fi
; fm
.pfi
&& score
; fm
.pfi
= fm
.pfi
->next
,
2018 fm
.flags
= origflags
)
2020 if( skipRaster
&& !(fm
.pfi
->fi_flags
& FI_SCALABLE
) )
2023 current_score
= XFONT_Match( &fm
);
2024 if( score
> current_score
)
2026 memcpy( pfm
, &fm
, sizeof(fontMatch
) );
2027 score
= current_score
;
2033 /***********************************************************************
2036 * REMOVE_SUBSETS - attach new fi and purge subsets
2037 * UNMARK_SUBSETS - remove subset flags from all fi entries
2039 static void XFONT_CheckFIList( fontResource
* fr
, fontInfo
* fi
, int action
)
2042 fontInfo
* pfi
, *prev
;
2044 for( prev
= NULL
, pfi
= fr
->fi
; pfi
; )
2046 if( action
== REMOVE_SUBSETS
)
2048 if( pfi
->fi_flags
& FI_SUBSET
)
2050 fontInfo
* subset
= pfi
;
2054 if( prev
) prev
->next
= pfi
= pfi
->next
;
2055 else fr
->fi
= pfi
= pfi
->next
;
2056 HeapFree( SystemHeap
, 0, subset
);
2060 else pfi
->fi_flags
&= ~FI_SUBSET
;
2066 if( action
== REMOVE_SUBSETS
) /* also add the superset */
2068 if( fi
->fi_flags
& FI_SCALABLE
)
2073 else if( prev
) prev
->next
= fi
; else fr
->fi
= fi
;
2077 if( i
) TRACE(font
,"\t purged %i subsets [%i]\n", i
, fr
->fi_count
);
2080 /***********************************************************************
2083 static fontResource
* XFONT_FindFIList( fontResource
* pfr
, const char* pTypeFace
)
2087 if( !strcasecmp( pfr
->lfFaceName
, pTypeFace
) ) break;
2093 /***********************************************************************
2094 * XFONT_MatchDeviceFont
2096 * Scan font resource tree.
2098 static BOOL32
XFONT_MatchDeviceFont( fontResource
* start
, fontMatch
* pfm
)
2100 fontResource
** ppfr
;
2101 fontMatch fm
= *pfm
;
2104 if( fm
.plf
->lfFaceName
[0] )
2109 for( fa
= aliasTable
; fa
; fa
= fa
->next
)
2110 if( !strcmp( fa
->faAlias
, fm
.plf
->lfFaceName
) )
2112 str
= fa
->faTypeFace
;
2115 fm
.pfr
= XFONT_FindFIList( start
, str
? str
: fm
.plf
->lfFaceName
);
2118 if( fm
.pfr
) /* match family */
2120 TRACE(font
, "%s\n", fm
.pfr
->lfFaceName
);
2122 if( fm
.pfr
->fr_flags
& FR_REMOVED
)
2126 XFONT_MatchFIList( &fm
);
2131 if( !pfm
->pfi
) /* match all available fonts */
2133 UINT32 current_score
, score
= (UINT32
)(-1);
2135 fm
.flags
|= FO_MATCH_PAF
;
2136 for( ppfr
= &fontList
; *ppfr
&& score
; ppfr
= &(*ppfr
)->next
)
2138 if( (*ppfr
)->fr_flags
& FR_REMOVED
)
2140 if( (*ppfr
)->fo_count
== 0 )
2141 XFONT_RemoveFontResource( ppfr
);
2147 TRACE(font
, "%s\n", fm
.pfr
->lfFaceName
);
2149 current_score
= XFONT_MatchFIList( &fm
);
2150 if( current_score
< score
)
2152 score
= current_score
;
2161 /***********************************************************************
2164 static void XFONT_GrowFreeList(int start
, int end
)
2166 /* add all entries from 'start' up to and including 'end' */
2168 memset( fontCache
+ start
, 0, (end
- start
+ 1) * sizeof(fontObject
) );
2170 fontCache
[end
].lru
= fontLF
;
2171 fontCache
[end
].count
= -1;
2173 while( start
< end
)
2175 fontCache
[start
].count
= -1;
2176 fontCache
[start
].lru
= start
+ 1;
2181 static fontObject
* XFONT_LookupCachedFont( LPLOGFONT16 plf
, UINT16
* checksum
)
2183 UINT16 cs
= __lfCheckSum( plf
);
2184 int i
= fontMRU
, prev
= -1;
2189 if( fontCache
[i
].lfchecksum
== cs
&&
2190 !(fontCache
[i
].fo_flags
& FO_REMOVED
) )
2192 /* FIXME: something more intelligent here */
2194 if( !memcmp( plf
, &fontCache
[i
].lf
,
2195 sizeof(LOGFONT16
) - LF_FACESIZE
) &&
2196 !strncasecmp( plf
->lfFaceName
, fontCache
[i
].lf
.lfFaceName
,
2199 /* remove temporarily from the lru list */
2202 fontCache
[prev
].lru
= fontCache
[i
].lru
;
2204 fontMRU
= (INT16
)fontCache
[i
].lru
;
2205 return (fontCache
+ i
);
2209 i
= (INT16
)fontCache
[i
].lru
;
2214 static fontObject
* XFONT_GetCacheEntry()
2220 int prev_i
, prev_j
, j
;
2222 TRACE(font
,"font cache is full\n");
2224 /* lookup the least recently used font */
2226 for( prev_i
= prev_j
= j
= -1, i
= fontMRU
; i
>= 0; i
= (INT16
)fontCache
[i
].lru
)
2228 if( fontCache
[i
].count
<= 0 &&
2229 !(fontCache
[i
].fo_flags
& FO_SYSTEM
) )
2237 if( j
>= 0 ) /* unload font */
2239 /* detach from the lru list */
2241 TRACE(font
,"\tfreeing entry %i\n", j
);
2243 fontCache
[j
].fr
->fo_count
--;
2246 fontCache
[prev_j
].lru
= fontCache
[j
].lru
;
2247 else fontMRU
= (INT16
)fontCache
[j
].lru
;
2249 /* FIXME: lpXForm, lpPixmap */
2250 if(fontCache
[j
].lpX11Trans
)
2251 HeapFree( SystemHeap
, 0, fontCache
[j
].lpX11Trans
);
2253 TSXFreeFont( display
, fontCache
[j
].fs
);
2255 memset( fontCache
+ j
, 0, sizeof(fontObject
) );
2256 return (fontCache
+ j
);
2258 else /* expand cache */
2260 fontObject
* newCache
;
2262 prev_i
= fontCacheSize
+ FONTCACHE
;
2264 TRACE(font
,"\tgrowing font cache from %i to %i\n", fontCacheSize
, prev_i
);
2266 if( (newCache
= (fontObject
*)HeapReAlloc(SystemHeap
, 0,
2267 fontCache
, prev_i
)) )
2270 fontCacheSize
= prev_i
;
2271 fontCache
= newCache
;
2272 XFONT_GrowFreeList( i
, fontCacheSize
- 1);
2278 /* detach from the free list */
2281 fontLF
= (INT16
)fontCache
[i
].lru
;
2282 fontCache
[i
].count
= 0;
2283 return (fontCache
+ i
);
2286 static int XFONT_ReleaseCacheEntry(fontObject
* pfo
)
2288 UINT32 u
= (UINT32
)(pfo
- fontCache
);
2290 if( u
< fontCacheSize
) return (--fontCache
[u
].count
);
2294 /**********************************************************************
2297 static BOOL32
XFONT_SetX11Trans( fontObject
*pfo
)
2303 TSXGetFontProperty( pfo
->fs
, XA_FONT
, &nameAtom
);
2304 fontName
= TSXGetAtomName( display
, nameAtom
);
2305 cp
= LFD_Advance( fontName
, 7 );
2311 while((cp
= strchr(cp
, '~')))
2314 #define PX pfo->lpX11Trans
2316 sscanf(start
, "[%f%f%f%f]", &PX
->a
, &PX
->b
, &PX
->c
, &PX
->d
);
2319 TSXGetFontProperty( pfo
->fs
, RAW_ASCENT
, &PX
->RAW_ASCENT
);
2320 TSXGetFontProperty( pfo
->fs
, RAW_DESCENT
, &PX
->RAW_DESCENT
);
2322 PX
->pixelsize
= hypot(PX
->a
, PX
->b
);
2323 PX
->ascent
= PX
->pixelsize
/ 1000.0 * PX
->RAW_ASCENT
;
2324 PX
->descent
= PX
->pixelsize
/ 1000.0 * PX
->RAW_DESCENT
;
2326 TRACE(font
, "[%f %f %f %f] RA = %ld RD = %ld\n", pfo
->lpX11Trans
->a
,
2327 pfo
->lpX11Trans
->b
, pfo
->lpX11Trans
->c
, pfo
->lpX11Trans
->d
,
2328 pfo
->lpX11Trans
->RAW_ASCENT
, pfo
->lpX11Trans
->RAW_DESCENT
);
2334 /***********************************************************************
2335 * X Device Font Objects
2337 static X_PHYSFONT
XFONT_RealizeFont( LPLOGFONT16 plf
)
2340 fontObject
* pfo
= XFONT_LookupCachedFont( plf
, &checksum
);
2344 fontMatch fm
= { NULL
, NULL
, 0, 0, plf
};
2347 if( XTextCaps
& TC_SF_X_YINDEP
) fm
.flags
= FO_MATCH_XYINDEP
;
2349 /* allocate new font cache entry */
2351 if( (pfo
= XFONT_GetCacheEntry()) )
2353 LPSTR lpLFD
= HeapAlloc( GetProcessHeap(), 0, MAX_LFD_LENGTH
);
2355 if( lpLFD
) /* initialize entry and load font */
2357 UINT32 uRelaxLevel
= 0;
2359 TRACE(font
,"(%u) '%s' h=%i weight=%i %s\n",
2360 plf
->lfCharSet
, plf
->lfFaceName
, plf
->lfHeight
,
2361 plf
->lfWeight
, (plf
->lfItalic
) ? "Italic" : "" );
2363 if(abs(plf
->lfHeight
) > MAX_FONT_SIZE
) {
2365 "plf->lfHeight = %d, this is probably not right. Setting to 100\n",
2367 plf
->lfHeight
= 100;
2370 XFONT_MatchDeviceFont( fontList
, &fm
);
2374 pfo
->fr
->fo_count
++;
2375 pfo
->fo_flags
= fm
.flags
& ~FO_MATCH_MASK
;
2377 memcpy( &pfo
->lf
, plf
, sizeof(LOGFONT16
) );
2378 pfo
->lfchecksum
= checksum
;
2382 LFD_ComposeLFD( pfo
, fm
.height
, lpLFD
, uRelaxLevel
++ );
2383 if( (pfo
->fs
= TSXLoadQueryFont( display
, lpLFD
)) ) break;
2384 } while( uRelaxLevel
);
2387 if(pfo
->lf
.lfEscapement
!= 0) {
2388 pfo
->lpX11Trans
= HeapAlloc(SystemHeap
, 0,
2389 sizeof(XFONTTRANS
));
2390 if(!XFONT_SetX11Trans( pfo
)) {
2391 HeapFree(SystemHeap
, 0, pfo
->lpX11Trans
);
2392 pfo
->lpX11Trans
= NULL
;
2396 if( XFONT_GetLeading( &pfo
->fi
->df
, pfo
->fs
, &i
, NULL
,
2399 if(!pfo
->lpX11Trans
)
2400 pfo
->foAvgCharWidth
=
2401 (INT16
)pfo
->fs
->per_char
['X' - pfo
->fs
->min_char_or_byte2
].width
;
2403 pfo
->foAvgCharWidth
=
2404 (INT16
)pfo
->fs
->per_char
['X' - pfo
->fs
->min_char_or_byte2
].attributes
2405 * pfo
->lpX11Trans
->pixelsize
/ 1000.0;
2407 pfo
->foAvgCharWidth
= (INT16
)XFONT_GetAvgCharWidth(
2408 &pfo
->fi
->df
, pfo
->fs
, pfo
->lpX11Trans
);
2409 pfo
->foMaxCharWidth
= (INT16
)XFONT_GetMaxCharWidth(pfo
);
2410 pfo
->foInternalLeading
= (INT16
)i
;
2412 /* FIXME: If we've got a soft font or
2413 * there are FO_SYNTH_... flags for the
2414 * non PROOF_QUALITY request, the engine
2415 * should rasterize characters into mono
2416 * pixmaps and store them in the pfo->lpPixmap
2417 * array (pfo->fs should be updated as well).
2418 * array (pfo->fs should be updated as well).
2419 * X11DRV_ExtTextOut() must be heavily modified
2420 * to support pixmap blitting and FO_SYNTH_...
2424 pfo
->lpPixmap
= NULL
;
2426 HeapFree( GetProcessHeap(), 0, lpLFD
);
2428 else /* attach back to the free list */
2432 fontLF
= (pfo
- fontCache
);
2437 if( !pfo
) /* couldn't get a new entry, get one of the cached fonts */
2439 UINT32 current_score
, score
= (UINT32
)(-1);
2441 i
= index
= fontMRU
;
2442 fm
.flags
|= FO_MATCH_PAF
;
2445 pfo
= fontCache
+ i
;
2446 fm
.pfr
= pfo
->fr
; fm
.pfi
= pfo
->fi
;
2448 current_score
= XFONT_Match( &fm
);
2449 if( current_score
< score
) index
= i
;
2453 pfo
= fontCache
+ index
;
2455 return (X_PHYSFONT
)(X_PFONT_MAGIC
| index
);
2459 /* attach at the head of the lru list */
2463 fontMRU
= (pfo
- fontCache
);
2465 TRACE(font
,"physfont %i\n", fontMRU
);
2467 return (X_PHYSFONT
)(X_PFONT_MAGIC
| fontMRU
);
2470 /***********************************************************************
2471 * XFONT_GetFontObject
2473 fontObject
* XFONT_GetFontObject( X_PHYSFONT pFont
)
2475 if( CHECK_PFONT(pFont
) ) return __PFONT(pFont
);
2479 /***********************************************************************
2480 * XFONT_GetFontStruct
2482 XFontStruct
* XFONT_GetFontStruct( X_PHYSFONT pFont
)
2484 if( CHECK_PFONT(pFont
) ) return __PFONT(pFont
)->fs
;
2488 /***********************************************************************
2491 LPIFONTINFO16
XFONT_GetFontInfo( X_PHYSFONT pFont
)
2493 if( CHECK_PFONT(pFont
) ) return &(__PFONT(pFont
)->fi
->df
);
2499 /* X11DRV Interface ****************************************************
2501 * Exposed via the dc->funcs dispatch table. *
2503 ***********************************************************************/
2504 /***********************************************************************
2505 * X11DRV_FONT_SelectObject
2507 HFONT32
X11DRV_FONT_SelectObject( DC
* dc
, HFONT32 hfont
, FONTOBJ
* font
)
2509 HFONT32 hPrevFont
= 0;
2511 X11DRV_PDEVICE
*physDev
= (X11DRV_PDEVICE
*)dc
->physDev
;
2513 EnterCriticalSection( &crtsc_fonts_X11
);
2515 if( CHECK_PFONT(physDev
->font
) )
2516 XFONT_ReleaseCacheEntry( __PFONT(physDev
->font
) );
2518 /* FIXME: do we need to pass anything back from here? */
2519 memcpy(&lf
,&font
->logfont
,sizeof(lf
));
2520 lf
.lfWidth
= font
->logfont
.lfWidth
* dc
->vportExtX
/dc
->wndExtX
;
2521 lf
.lfHeight
= font
->logfont
.lfHeight
* dc
->vportExtY
/dc
->wndExtY
;
2523 physDev
->font
= XFONT_RealizeFont( &lf
);
2524 hPrevFont
= dc
->w
.hFont
;
2525 dc
->w
.hFont
= hfont
;
2527 LeaveCriticalSection( &crtsc_fonts_X11
);
2533 /***********************************************************************
2535 * X11DRV_EnumDeviceFonts
2537 BOOL32
X11DRV_EnumDeviceFonts( DC
* dc
, LPLOGFONT16 plf
,
2538 DEVICEFONTENUMPROC proc
, LPARAM lp
)
2542 fontResource
* pfr
= fontList
;
2545 if( plf
->lfFaceName
[0] )
2547 /* enum all entries in this resource */
2548 pfr
= XFONT_FindFIList( pfr
, plf
->lfFaceName
);
2552 for( pfi
= pfr
->fi
; pfi
; pfi
= pfi
->next
)
2554 /* Note: XFONT_GetFontMetric() will have to
2555 release the crit section, font list will
2556 have to be retraversed on return */
2558 if( (b
= (*proc
)( (LPENUMLOGFONT16
)&lf
, &tm
,
2559 XFONT_GetFontMetric( pfi
, &lf
, &tm
), lp
)) )
2565 else /* enum first entry in each resource */
2566 for( ; pfr
; pfr
= pfr
->next
)
2570 if( (b
= (*proc
)( (LPENUMLOGFONT16
)&lf
, &tm
,
2571 XFONT_GetFontMetric( pfr
->fi
, &lf
, &tm
), lp
)) )
2580 /***********************************************************************
2581 * X11DRV_GetTextExtentPoint
2583 BOOL32
X11DRV_GetTextExtentPoint( DC
*dc
, LPCSTR str
, INT32 count
,
2586 X11DRV_PDEVICE
*physDev
= (X11DRV_PDEVICE
*)dc
->physDev
;
2587 fontObject
* pfo
= XFONT_GetFontObject( physDev
->font
);
2589 if( !pfo
->lpX11Trans
) {
2590 int dir
, ascent
, descent
;
2593 TSXTextExtents( pfo
->fs
, str
, count
, &dir
, &ascent
, &descent
, &info
);
2594 size
->cx
= abs((info
.width
+ dc
->w
.breakRem
+ count
*
2595 dc
->w
.charExtra
) * dc
->wndExtX
/ dc
->vportExtX
);
2596 size
->cy
= abs((pfo
->fs
->ascent
+ pfo
->fs
->descent
) *
2597 dc
->wndExtY
/ dc
->vportExtY
);
2601 float x
= 0.0, y
= 0.0;
2602 for(i
= 0; i
< count
; i
++) {
2603 x
+= pfo
->fs
->per_char
?
2604 pfo
->fs
->per_char
[str
[i
] - pfo
->fs
->min_char_or_byte2
].attributes
:
2605 pfo
->fs
->min_bounds
.attributes
;
2607 y
= pfo
->lpX11Trans
->RAW_ASCENT
+ pfo
->lpX11Trans
->RAW_DESCENT
;
2608 TRACE(font
, "x = %f y = %f\n", x
, y
);
2609 x
*= pfo
->lpX11Trans
->pixelsize
/ 1000.0;
2610 y
*= pfo
->lpX11Trans
->pixelsize
/ 1000.0;
2611 size
->cx
= fabsf((x
+ dc
->w
.breakRem
+ count
* dc
->w
.charExtra
) *
2612 dc
->wndExtX
/ dc
->vportExtX
);
2613 size
->cy
= fabsf(y
* dc
->wndExtY
/ dc
->vportExtY
);
2621 /***********************************************************************
2622 * X11DRV_GetTextMetrics
2624 BOOL32
X11DRV_GetTextMetrics(DC
*dc
, TEXTMETRIC32A
*metrics
)
2626 X11DRV_PDEVICE
*physDev
= (X11DRV_PDEVICE
*)dc
->physDev
;
2628 if( CHECK_PFONT(physDev
->font
) )
2630 fontObject
* pfo
= __PFONT(physDev
->font
);
2631 XFONT_GetTextMetric( pfo
, metrics
);
2639 /***********************************************************************
2640 * X11DRV_GetCharWidth
2642 BOOL32
X11DRV_GetCharWidth( DC
*dc
, UINT32 firstChar
, UINT32 lastChar
,
2645 X11DRV_PDEVICE
*physDev
= (X11DRV_PDEVICE
*)dc
->physDev
;
2646 fontObject
* pfo
= XFONT_GetFontObject( physDev
->font
);
2652 if (pfo
->fs
->per_char
== NULL
)
2653 for (i
= firstChar
; i
<= lastChar
; i
++)
2655 *buffer
++ = pfo
->fs
->min_bounds
.attributes
*
2656 pfo
->lpX11Trans
->pixelsize
/ 1000.0;
2658 *buffer
++ = pfo
->fs
->min_bounds
.width
;
2661 XCharStruct
*cs
, *def
;
2662 static XCharStruct __null_char
= { 0, 0, 0, 0, 0, 0 };
2664 CI_GET_CHAR_INFO(pfo
->fs
, pfo
->fs
->default_char
, &__null_char
,
2667 for (i
= firstChar
; i
<= lastChar
; i
++)
2669 if (i
>= pfo
->fs
->min_char_or_byte2
&&
2670 i
<= pfo
->fs
->max_char_or_byte2
)
2672 cs
= &pfo
->fs
->per_char
[(i
- pfo
->fs
->min_char_or_byte2
)];
2673 if (CI_NONEXISTCHAR(cs
)) cs
= def
;
2676 *buffer
++ = MAX(cs
->attributes
, 0) *
2677 pfo
->lpX11Trans
->pixelsize
/ 1000.0;
2679 *buffer
++ = MAX(cs
->width
, 0 );
2688 /***********************************************************************
2690 * Font Resource API *
2692 ***********************************************************************/
2693 /***********************************************************************
2694 * AddFontResource16 (GDI.119)
2696 * Can be either .FON, or .FNT, or .TTF, or .FOT font file.
2698 * FIXME: Load header and find the best-matching font in the fontList;
2699 * fixup dfPoints if all metrics are identical, otherwise create
2700 * new fontAlias. When soft font support is ready this will
2701 * simply create a new fontResource ('filename' will go into
2702 * the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE
2705 INT16 WINAPI
AddFontResource16( LPCSTR filename
)
2707 return AddFontResource32A( filename
);
2711 /***********************************************************************
2712 * AddFontResource32A (GDI32.2)
2714 INT32 WINAPI
AddFontResource32A( LPCSTR str
)
2716 FIXME(font
, "(%s): stub\n", debugres_a(str
));
2721 /***********************************************************************
2722 * AddFontResource32W (GDI32.4)
2724 INT32 WINAPI
AddFontResource32W( LPCWSTR str
)
2726 FIXME(font
, "(%s): stub\n", debugres_w(str
) );
2730 /***********************************************************************
2731 * RemoveFontResource16 (GDI.136)
2733 BOOL16 WINAPI
RemoveFontResource16( SEGPTR str
)
2735 FIXME(font
, "(%s): stub\n", debugres_a(PTR_SEG_TO_LIN(str
)));
2740 /***********************************************************************
2741 * RemoveFontResource32A (GDI32.284)
2743 BOOL32 WINAPI
RemoveFontResource32A( LPCSTR str
)
2745 /* This is how it should look like */
2747 fontResource** ppfr;
2748 BOOL32 retVal = FALSE;
2750 EnterCriticalSection( &crtsc_fonts_X11 );
2751 for( ppfr = &fontList; *ppfr; ppfr = &(*ppfr)->next )
2752 if( !strcasecmp( (*ppfr)->lfFaceName, str ) )
2754 if(((*ppfr)->fr_flags & (FR_SOFTFONT | FR_SOFTRESOURCE)) &&
2755 (*ppfr)->hOwnerProcess == GetCurrentProcess() )
2757 if( (*ppfr)->fo_count )
2758 (*ppfr)->fr_flags |= FR_REMOVED;
2760 XFONT_RemoveFontResource( ppfr );
2764 LeaveCriticalSection( &crtsc_fontList );
2767 FIXME(font
, "(%s): stub\n", debugres_a(str
));
2772 /***********************************************************************
2773 * RemoveFontResource32W (GDI32.286)
2775 BOOL32 WINAPI
RemoveFontResource32W( LPCWSTR str
)
2777 FIXME(font
, "(%s): stub\n", debugres_w(str
) );