Fixed the prototype of CreateDIBPatternBrushPt
[wine/multimedia.git] / graphics / x11drv / xfont.c
blobf532425276dac7a9f83130cbf04302d98a53dec4
1 /*
2 * X11 physical font objects
4 * Copyright 1997 Alex Korobka
6 * TODO: Mapping algorithm tweaks, FO_SYNTH_... flags (ExtTextOut() will
7 * have to be changed for that), dynamic font loading (FreeType).
8 */
10 #include <ctype.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <pwd.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include "ts_xlib.h"
20 #include <X11/Xatom.h>
21 #include <math.h>
22 #include <assert.h>
23 #include "heap.h"
24 #include "options.h"
25 #include "x11font.h"
26 #include "font.h"
27 #include "debug.h"
29 #define X_PFONT_MAGIC (0xFADE0000)
30 #define X_FMC_MAGIC (0x0000CAFE)
32 #define MAX_FONT_FAMILIES 128
33 #define MAX_LFD_LENGTH 256
35 #define MAX_FONT_SIZE 5000 /* Max size in pixels */
37 #define REMOVE_SUBSETS 1
38 #define UNMARK_SUBSETS 0
40 #define DEF_SCALABLE_HEIGHT 24
41 #define DEF_SCALABLE_DP 240
43 #define FF_FAMILY (FF_MODERN | FF_SWISS | FF_ROMAN | FF_DECORATIVE | FF_SCRIPT)
45 typedef struct __fontAlias
47 LPSTR faTypeFace;
48 LPSTR faAlias;
49 struct __fontAlias* next;
50 } fontAlias;
52 typedef struct
54 LPSTR fatResource;
55 LPSTR fatAlias;
56 } aliasTemplate;
58 /* Font alias table - these 2 aliases are always present */
59 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
61 static fontAlias __aliasTable[2] = {
62 { NULL, "Helv", &__aliasTable[1] },
63 { NULL, "Tms Rmn", NULL }
66 static fontAlias *aliasTable = __aliasTable;
68 /* Optional built-in aliases, they are installed only when X
69 * cannot supply us with original MS fonts */
70 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
72 static int faTemplateNum = 4;
73 static aliasTemplate faTemplate[4] = {
74 { NULL, "MS Sans Serif" },
75 { NULL, "MS Serif" },
76 { "-adobe-times-", "Times New Roman" },
77 { "-adobe-helvetica-", "Arial" }
80 UINT16 XTextCaps = TC_OP_CHARACTER | TC_OP_STROKE |
81 TC_CP_STROKE | TC_CR_ANY |
82 TC_SA_DOUBLE | TC_SA_INTEGER | TC_SA_CONTIN |
83 TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
85 /* X11R6 adds TC_SF_X_YINDEP, maybe more... */
87 static const char* INIWinePrefix = "/.wine";
88 static const char* INIFontMetrics = "/.cachedmetrics";
89 static const char* INIFontSection = "fonts";
90 static const char* INISubSection = "Alias";
91 static const char* INIDefault = "Default";
92 static const char* INIDefaultFixed = "DefaultFixed";
93 static const char* INIResolution = "Resolution";
94 static const char* INIGlobalMetrics = "FontMetrics";
95 static const char* INIDefaultSerif = "DefaultSerif";
96 static const char* INIDefaultSansSerif = "DefaultSansSerif";
98 static const char* LFDSeparator = "*-";
99 static const char* MSEncoding = "microsoft-";
100 static const char* iso8859Encoding = "iso8859-";
101 static const char* iso646Encoding = "iso646.1991-";
102 static const char* ansiEncoding = "ansi-";
103 static unsigned DefResolution = 0;
105 static fontResource* fontList = NULL;
106 static fontObject* fontCache = NULL; /* array */
107 static int fontCacheSize = FONTCACHE;
108 static int fontLF = -1, fontMRU = -1; /* last free, most recently used */
110 #define __PFONT(pFont) ( fontCache + ((UINT32)(pFont) & 0x0000FFFF) )
111 #define CHECK_PFONT(pFont) ( (((UINT32)(pFont) & 0xFFFF0000) == X_PFONT_MAGIC) &&\
112 (((UINT32)(pFont) & 0x0000FFFF) < fontCacheSize) )
114 static INT32 XFONT_IsSubset(fontInfo*, fontInfo*);
115 static void XFONT_CheckFIList(fontResource*, fontInfo*, int subset_action);
116 static void XFONT_GrowFreeList(int start, int end);
119 static Atom RAW_ASCENT;
120 static Atom RAW_DESCENT;
122 /***********************************************************************
123 * Helper macros from X distribution
126 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
127 (((cs)->rbearing|(cs)->lbearing| \
128 (cs)->ascent|(cs)->descent) == 0))
130 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
132 cs = def; \
133 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
134 if (fs->per_char == NULL) { \
135 cs = &fs->min_bounds; \
136 } else { \
137 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
138 if (CI_NONEXISTCHAR(cs)) cs = def; \
143 #define CI_GET_DEFAULT_INFO(fs,cs) \
144 CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
146 /***********************************************************************
147 * Checksums
149 static UINT16 __lfCheckSum( LPLOGFONT16 plf )
151 CHAR font[LF_FACESIZE];
152 UINT16 checksum = 0;
153 UINT16 i;
155 #define ptr ((UINT16*)plf)
156 for( i = 0; i < 9; i++ ) checksum ^= *ptr++;
157 #undef ptr
158 i = 0;
159 #define ptr ((CHAR*)plf)
160 do { font[i++] = tolower(*ptr++); } while (( i < LF_FACESIZE) && (*ptr) && (*ptr!=' '));
161 for( ptr = font, i >>= 1; i > 0; i-- )
162 #undef ptr
163 #define ptr ((UINT16*)plf)
164 checksum ^= *ptr++;
165 #undef ptr
166 return checksum;
169 static UINT16 __genericCheckSum( const void *ptr, int size )
171 unsigned int checksum = 0;
172 const char *p = (const char *)ptr;
173 while (size-- > 0)
174 checksum ^= (checksum << 3) + (checksum >> 29) + *p++;
176 return checksum & 0xffff;
179 /*************************************************************************
180 * LFD parse/compose routines
182 static char* LFD_Advance(LPSTR lpFont, UINT16 uParmsNo)
184 int j = 0;
185 char* lpch = lpFont;
187 for( ; j < uParmsNo && *lpch; lpch++ ) if( *lpch == LFDSeparator[1] ) j++;
188 return lpch;
191 static void LFD_GetWeight( fontInfo* fi, LPSTR lpStr, int j)
193 if( j == 1 && *lpStr == '0' )
194 fi->fi_flags |= FI_POLYWEIGHT;
195 else if( j == 4 )
197 if( !strncasecmp( "bold", lpStr, 4) )
198 fi->df.dfWeight = FW_BOLD;
199 else if( !strncasecmp( "demi", lpStr, 4) )
201 fi->fi_flags |= FI_FW_DEMI;
202 fi->df.dfWeight = FW_DEMIBOLD;
204 else if( !strncasecmp( "book", lpStr, 4) )
206 fi->fi_flags |= FI_FW_BOOK;
207 fi->df.dfWeight = FW_REGULAR;
210 else if( j == 5 )
212 if( !strncasecmp( "light", lpStr, 5) )
213 fi->df.dfWeight = FW_LIGHT;
214 else if( !strncasecmp( "black", lpStr, 5) )
215 fi->df.dfWeight = FW_BLACK;
217 else if( j == 6 && !strncasecmp( "medium", lpStr, 6) )
218 fi->df.dfWeight = FW_REGULAR;
219 else if( j == 8 && !strncasecmp( "demibold", lpStr, 8) )
220 fi->df.dfWeight = FW_DEMIBOLD;
221 else
222 fi->df.dfWeight = FW_DONTCARE; /* FIXME: try to get something
223 * from the weight property */
226 static int LFD_GetSlant( fontInfo* fi, LPSTR lpStr, int l)
228 if( l == 1 )
230 switch( tolower( *lpStr ) )
232 case '0': fi->fi_flags |= FI_POLYSLANT; /* haven't seen this one yet */
233 default:
234 case 'r': fi->df.dfItalic = 0;
235 break;
236 case 'o':
237 fi->fi_flags |= FI_OBLIQUE;
238 case 'i': fi->df.dfItalic = 1;
239 break;
241 return 0;
243 return 1;
246 /*************************************************************************
247 * LFD_InitFontInfo
249 * Fill in some fields in the fontInfo struct.
251 static int LFD_InitFontInfo( fontInfo* fi, LPSTR lpstr )
253 LPSTR lpch;
254 int i, j, dec_style_check, scalability;
255 UINT16 tmp[3];
257 memset(fi, 0, sizeof(fontInfo) );
259 /* weight name - */
260 lpch = LFD_Advance( lpstr, 1);
261 if( !*lpch ) return FALSE;
262 j = lpch - lpstr - 1;
263 LFD_GetWeight( fi, lpstr, j );
265 /* slant - */
266 lpch = LFD_Advance( lpstr = lpch, 1);
267 if( !*lpch ) return FALSE;
268 j = lpch - lpstr - 1;
269 dec_style_check = LFD_GetSlant( fi, lpstr, j );
271 /* width name - */
272 lpch = LFD_Advance( lpstr = lpch, 1);
273 if( !*lpch ) return FALSE;
274 if( strncasecmp( "normal", lpstr, 6) ) /* XXX 'narrow', 'condensed', etc... */
275 dec_style_check = TRUE;
276 else
277 fi->fi_flags |= FI_NORMAL;
279 /* style - */
280 lpch = LFD_Advance( lpstr = lpch, 1);
281 if( !*lpch ) return FALSE;
282 j = lpch - lpstr - 1;
283 if( j > 3 ) /* find out is there "sans" or "script" */
285 j = 0;
286 *(lpch - 1) = '\0';
288 if( strstr(lpstr, "sans") )
290 fi->df.dfPitchAndFamily |= FF_SWISS;
291 j = 1;
293 if( strstr(lpstr, "script") )
295 fi->df.dfPitchAndFamily |= FF_SCRIPT;
296 j = 1;
298 if( !j && dec_style_check )
299 fi->df.dfPitchAndFamily |= FF_DECORATIVE;
300 *(lpch - 1) = LFDSeparator[1];
303 /* pixel height, decipoint height, and res_x */
305 for( i = scalability = 0; i < 3; i++ )
307 lpch = LFD_Advance( lpstr = lpch, 1);
308 if( !*lpch ) return FALSE;
309 if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
311 *(lpch - 1) = '\0';
312 if( !(tmp[i] = atoi(lpstr)) ) scalability++;
313 *(lpch - 1) = LFDSeparator[1];
315 if( scalability == 3 ) /* Type1 */
317 fi->fi_flags |= FI_SCALABLE;
318 fi->lfd_height = DEF_SCALABLE_HEIGHT; fi->lfd_decipoints = DEF_SCALABLE_DP;
319 fi->lfd_resolution = DefResolution;
321 else if( scalability == 0 ) /* Bitmap */
323 fi->lfd_height = tmp[0]; fi->lfd_decipoints = tmp[1];
324 fi->lfd_resolution = tmp[2];
326 else return FALSE; /* #$%^!!! X11R6 mutant garbage */
328 /* res_y - skip, spacing - */
329 lpstr = LFD_Advance( lpch, 1);
330 switch( *lpstr )
332 case '\0': return FALSE;
334 case 'p': fi->fi_flags |= FI_VARIABLEPITCH;
335 break;
336 case 'c': fi->df.dfPitchAndFamily |= FF_MODERN;
337 fi->fi_flags |= FI_FIXEDEX;
338 /* fall through */
339 case 'm': fi->fi_flags |= FI_FIXEDPITCH;
340 break;
341 default:
342 fi->df.dfPitchAndFamily |= DEFAULT_PITCH | FF_DONTCARE;
344 lpstr = LFD_Advance(lpstr, 1);
345 if( !*lpstr ) return FALSE;
347 /* average width - */
348 lpch = LFD_Advance( lpstr, 1);
349 if( !*lpch ) return FALSE;
350 if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
351 *(lpch - 1) = '\0';
352 if( !(fi->lfd_width = atoi(lpstr)) && !scalability ) return FALSE;
353 *(lpch - 1) = LFDSeparator[1];
355 /* charset registry, charset encoding - */
356 if( strstr(lpch, "jisx") ||
357 strstr(lpch, "ksc") ||
358 strstr(lpch, "gb2312") ||
359 strstr(lpch, "big5") ||
360 strstr(lpch, "unicode") ) return FALSE; /* 2-byte stuff */
362 fi->df.dfCharSet = ANSI_CHARSET;
363 if( strstr(lpch, iso8859Encoding) ) {
364 fi->fi_flags |= FI_ENC_ISO8859;
365 if( strstr(lpch, "iso8859-15") ) fi->df.dfCharSet = ANSI_CHARSET;
366 else if( strstr(lpch, "iso8859-11") ) fi->df.dfCharSet = THAI_CHARSET;
367 else if( strstr(lpch, "iso8859-10") ) fi->df.dfCharSet = BALTIC_CHARSET;
368 else if( strstr(lpch, "iso8859-9") ) fi->df.dfCharSet = TURKISH_CHARSET;
369 else if( strstr(lpch, "iso8859-8") ) fi->df.dfCharSet = HEBREW_CHARSET;
370 else if( strstr(lpch, "iso8859-7") ) fi->df.dfCharSet = GREEK_CHARSET;
371 else if( strstr(lpch, "iso8859-6") ) fi->df.dfCharSet = ARABIC_CHARSET;
372 else if( strstr(lpch, "iso8859-5") ) fi->df.dfCharSet = RUSSIAN_CHARSET;
373 else if( strstr(lpch, "iso8859-4") ) fi->df.dfCharSet = ISO4_CHARSET;
374 else if( strstr(lpch, "iso8859-3") ) fi->df.dfCharSet = ISO3_CHARSET;
375 else if( strstr(lpch, "iso8859-2") ) fi->df.dfCharSet = EE_CHARSET;
376 else if( strstr(lpch, "iso8859-1") ) fi->df.dfCharSet = ANSI_CHARSET;
377 else fi->df.dfCharSet = SYMBOL_CHARSET;
378 } else if( strstr(lpch, iso646Encoding) ) {
379 fi->fi_flags |= FI_ENC_ISO646;
380 } else if( strstr(lpch, ansiEncoding) ) { /* fnt2bdf produces -ansi-0 LFD */
381 fi->fi_flags |= FI_ENC_ANSI;
382 } else { /* ... and -microsoft-cp125x */
384 fi->df.dfCharSet = OEM_CHARSET;
385 if( !strncasecmp(lpch, "microsoft-", 10) ) {
386 fi->fi_flags |= FI_ENC_MSCODEPAGE;
387 if( strstr(lpch, "-cp1250") ) fi->df.dfCharSet = EE_CHARSET;
388 else if( strstr(lpch, "-cp1251") ) fi->df.dfCharSet = RUSSIAN_CHARSET;
389 else if( strstr(lpch, "-cp1252") ) fi->df.dfCharSet = ANSI_CHARSET;
390 else if( strstr(lpch, "-cp1253") ) fi->df.dfCharSet = GREEK_CHARSET;
391 else if( strstr(lpch, "-cp1254") ) fi->df.dfCharSet = TURKISH_CHARSET;
392 else if( strstr(lpch, "-cp1255") ) fi->df.dfCharSet = HEBREW_CHARSET;
393 else if( strstr(lpch, "-cp1256") ) fi->df.dfCharSet = ARABIC_CHARSET;
394 else if( strstr(lpch, "-cp1257") ) fi->df.dfCharSet = BALTIC_CHARSET;
395 else if( strstr(lpch, "-fontspecific") ) fi->df.dfCharSet = ANSI_CHARSET;
396 else if( strstr(lpch, "-symbol") ) fi->df.dfCharSet = SYMBOL_CHARSET;
397 else fi->df.dfCharSet = SYMBOL_CHARSET;
398 } else if( !strncasecmp(lpch, "koi8-", 5) ) {
399 fi->df.dfCharSet = KOI8_CHARSET;
400 } else if( !strncasecmp(lpch, "viscii", 6) ) {
401 fi->fi_flags |= FI_ENC_ISO8859;
402 fi->df.dfCharSet = VISCII_CHARSET;
403 } else if( !strncasecmp(lpch, "tcvn-", 5) ) {
404 fi->df.dfCharSet = TCVN_CHARSET;
405 } else if( !strncasecmp(lpch, "tis620", 6) ) {
406 fi->fi_flags |= FI_ENC_ISO8859;
407 fi->df.dfCharSet = THAI_CHARSET;
408 } else if( !strncasecmp(lpch, "ascii", 5) ) {
409 fi->fi_flags |= FI_ENC_ISO646;
410 fi->df.dfCharSet = ANSI_CHARSET;
411 } else if( strstr(lpch, "fontspecific") ||
412 strstr(lpch, "microsoft-symbol") ) {
413 fi->df.dfCharSet = SYMBOL_CHARSET;
416 return TRUE;
420 /*************************************************************************
421 * LFD_ComposeLFD
423 static BOOL32 LFD_ComposeLFD( fontObject* fo,
424 INT32 height, LPSTR lpLFD, UINT32 uRelax )
426 int h, w, ch, point = 0;
427 char* lpch;
428 char lpEncoding[32];
429 char h_string[64], point_string[64];
431 *(lpLFD+MAX_LFD_LENGTH-1)=0;
432 lstrcpy32A( lpLFD, fo->fr->resource );
434 /* add weight */
435 switch( fo->fi->df.dfWeight )
437 case FW_BOLD:
438 strcat( lpLFD, "bold" ); break;
439 case FW_REGULAR:
440 if( fo->fi->fi_flags & FI_FW_BOOK )
441 strcat( lpLFD, "book" );
442 else
443 strcat( lpLFD, "medium" );
444 break;
445 case FW_DEMIBOLD:
446 strcat( lpLFD, "demi" );
447 if( !( fo->fi->fi_flags & FI_FW_DEMI) )
448 strcat ( lpLFD, "bold" );
449 break;
450 case FW_BLACK:
451 strcat( lpLFD, "black" ); break;
452 case FW_LIGHT:
453 strcat( lpLFD, "light" ); break;
454 default:
455 strcat( lpLFD, "*" );
458 /* add slant */
459 if( fo->fi->df.dfItalic )
460 if( fo->fi->fi_flags & FI_OBLIQUE )
461 strcat( lpLFD, "-o" );
462 else
463 strcat( lpLFD, "-i" );
464 else
465 strcat( lpLFD, (uRelax < 6) ? "-r" : "-*" );
467 /* add width style and skip serifs */
468 if( fo->fi->fi_flags & FI_NORMAL )
469 strcat( lpLFD, "-normal-*-");
470 else
471 strcat( lpLFD, "-*-*-" );
473 /* add pixelheight, pointheight, and resolution
475 * FIXME: fill in lpXForm and lpPixmap for rotated fonts
477 if( fo->fo_flags & FO_SYNTH_HEIGHT ) h = fo->fi->lfd_height;
478 else h = (fo->fi->lfd_height * height) / fo->fi->df.dfPixHeight;
480 if( XTextCaps & TC_SF_X_YINDEP )
482 if( fo->lf.lfWidth && !(fo->fo_flags & FO_SYNTH_WIDTH) )
483 point = (fo->fi->lfd_decipoints * fo->lf.lfWidth) / fo->fi->df.dfAvgWidth;
484 else
485 if( fo->fi->fi_flags & FI_SCALABLE ) /* adjust h/w ratio */
486 point = h * 72 * 10 / fo->fi->lfd_resolution;
489 /* handle rotated fonts */
490 if (fo->lf.lfEscapement) {
491 /* escapement is in tenths of degrees, theta is in radians */
492 double theta = M_PI*fo->lf.lfEscapement/1800.;
493 double h_matrix[4] = {h*cos(theta), h*sin(theta), -h*sin(theta), h*cos(theta)};
494 double point_matrix[4] = {point*cos(theta), point*sin(theta), -point*sin(theta), point*cos(theta)};
495 char *s;
496 sprintf(h_string, "[%+f%+f%+f%+f]", h_matrix[0], h_matrix[1], h_matrix[2], h_matrix[3]);
497 sprintf(point_string, "[%+f%+f%+f%+f]", point_matrix[0], point_matrix[1], point_matrix[2], point_matrix[3]);
498 while ((s = strchr(h_string, '-'))) *s='~';
499 while ((s = strchr(point_string, '-'))) *s='~';
500 } else {
501 sprintf(h_string, "%d", h);
502 sprintf(point_string, "%d", point);
506 /* spacing and width */
508 if( fo->fi->fi_flags & FI_FIXEDPITCH )
509 w = ( fo->fi->fi_flags & FI_FIXEDEX ) ? 'c' : 'm';
510 else
511 w = ( fo->fi->fi_flags & FI_VARIABLEPITCH ) ? 'p' : LFDSeparator[0];
513 /* encoding */
515 #define CHRS_CASE1(charset) case 0: \
516 case 3: \
517 case 6: \
518 case 9: \
519 case 12: sprintf(lpEncoding, charset ); break;
520 #define CHRS_CASE2(charset) case 1: \
521 case 4: \
522 case 7: \
523 case 10: \
524 case 13: sprintf(lpEncoding, charset ); break;
525 #define CHRS_CASE3(charset) case 2: \
526 case 5: \
527 case 8: \
528 case 11: \
529 case 14: sprintf(lpEncoding, charset ); break;
530 #define CHRS_DEF(charset) default: sprintf(lpEncoding, charset ); break;
532 if( fo->fi->df.dfCharSet == ANSI_CHARSET )
534 if( fo->fi->fi_flags & FI_ENC_ISO8859 )
535 switch (uRelax) {
536 CHRS_CASE1( "iso8859-1" );
537 CHRS_CASE2( "iso8859-1" );
538 CHRS_CASE3( "iso8859-15" );
539 CHRS_DEF( "iso8859-*" );
541 else if( fo->fi->fi_flags & FI_ENC_ISO646 )
542 switch (uRelax) {
543 CHRS_CASE1( "ascii-0" );
544 CHRS_DEF( "iso8859-1" );
546 else if( fo->fi->fi_flags & FI_ENC_MSCODEPAGE )
547 switch (uRelax) {
548 CHRS_CASE1( "microsoft-cp1252" );
549 CHRS_CASE2( "microsoft-fontspecific" );
550 CHRS_CASE3( "microsoft-cp125*" );
551 CHRS_DEF( "microsoft-*" );
553 else
554 switch (uRelax) {
555 CHRS_CASE1( "ansi-0" );
556 CHRS_CASE2( "microsoft-125*" );
557 CHRS_CASE3( "microsoft-*");
558 CHRS_DEF( "iso8859-*" );
561 else if( fo->fi->fi_flags & FI_ENC_MSCODEPAGE )
563 switch (fo->fi->df.dfCharSet) {
564 case EE_CHARSET:
565 switch (uRelax) {
566 CHRS_CASE1( "microsoft-1250" );
567 CHRS_CASE2( "iso8859-2" );
568 CHRS_DEF( "iso8859-*" );
569 } ; break;
570 case RUSSIAN_CHARSET:
571 switch (uRelax) {
572 CHRS_CASE1( "microsoft-1251" );
573 CHRS_CASE2( "iso8859-5" );
574 CHRS_CASE3( "koi8-*" );
575 CHRS_DEF( "iso8859-*" );
576 } ; break;
577 case ANSI_CHARSET:
578 switch (uRelax) {
579 CHRS_CASE1( "microsoft-1252" );
580 CHRS_CASE2( "iso8859-1" );
581 CHRS_CASE3( "iso8859-15" );
582 CHRS_DEF( "iso8859-*" );
583 } ; break;
584 case GREEK_CHARSET:
585 switch (uRelax) {
586 CHRS_CASE1( "microsoft-1253" );
587 CHRS_CASE2( "iso8859-7" );
588 CHRS_DEF( "iso8859-*" );
589 } ; break;
590 case TURKISH_CHARSET:
591 switch (uRelax) {
592 CHRS_CASE1( "microsoft-1254" );
593 CHRS_CASE2( "iso8859-9" );
594 CHRS_DEF( "iso8859-*" );
595 } ; break;
596 case HEBREW_CHARSET:
597 switch (uRelax) {
598 CHRS_CASE1( "microsoft-1255" );
599 CHRS_CASE2( "iso8859-8" );
600 CHRS_DEF( "iso8859-*" );
601 } ; break;
602 case ARABIC_CHARSET:
603 switch (uRelax) {
604 CHRS_CASE1( "microsoft-1256" );
605 CHRS_CASE2( "iso8859-6" );
606 CHRS_DEF( "iso8859-*" );
607 } ; break;
608 case BALTIC_CHARSET:
609 switch (uRelax) {
610 CHRS_CASE1( "microsoft-1257" );
611 CHRS_CASE2( "iso8859-10" );
612 CHRS_CASE3( "iso8859-15" );
613 CHRS_DEF( "iso8859-*" );
614 } ; break;
615 case THAI_CHARSET:
616 switch (uRelax) {
617 CHRS_CASE1( "iso8859-11" );
618 CHRS_CASE2( "tis620*" );
619 CHRS_DEF( "iso8859-*" );
620 } ; break;
621 case VISCII_CHARSET:
622 switch (uRelax) {
623 CHRS_CASE1( "viscii1.1-1" );
624 CHRS_CASE2( "viscii*" );
625 CHRS_DEF( "iso8859-*" );
626 } ; break;
627 case TCVN_CHARSET:
628 switch (uRelax) {
629 CHRS_CASE1( "tcvn-0" );
630 CHRS_CASE2( "tcvn*" );
631 CHRS_DEF( "iso8859-*" );
632 } ; break;
633 case KOI8_CHARSET:
634 switch (uRelax) {
635 CHRS_CASE1( "koi8-ru" );
636 CHRS_CASE2( "koi8-r" );
637 CHRS_CASE3( "koi8-*" );
638 CHRS_DEF( "iso8859-*" );
639 } ; break;
640 case ISO3_CHARSET:
641 switch (uRelax) {
642 CHRS_CASE1( "iso8859-3" );
643 CHRS_DEF( "iso8859-*" );
644 } ; break;
645 case ISO4_CHARSET:
646 switch (uRelax) {
647 CHRS_CASE1( "iso8859-4" );
648 CHRS_DEF( "iso8859-*" );
649 } ; break;
650 default:
651 switch (uRelax) {
652 CHRS_CASE1( "microsoft-symbol" );
653 CHRS_DEF( "microsoft-fontspecific" );
654 } ; break;
657 else {
658 switch (uRelax) {
659 CHRS_CASE1( "*-fontspecific" );
660 CHRS_CASE2( "*-symbol" );
661 CHRS_DEF( "*-*" ); /* whatever */
665 lpch = lpLFD + lstrlen32A(lpLFD);
666 ch = (fo->fi->fi_flags & FI_SCALABLE) ? '0' : LFDSeparator[0];
668 switch( uRelax )
670 /* RealizeFont() will call us repeatedly with increasing uRelax
671 * until XLoadFont() succeeds. */
673 case 0:
674 case 1:
675 case 2:
676 if( point )
678 sprintf( lpch, "%s-%s-%i-%c-%c-*-%s", h_string,
679 point_string,
680 fo->fi->lfd_resolution, ch, w, lpEncoding );
681 break;
683 /* fall through */
685 case 3:
686 case 4:
687 case 5:
688 case 6: /* 6-8 will have replaced an 'r' in slant by '*' */
689 case 7:
690 case 8:
691 sprintf( lpch, "%s-*-%i-%c-%c-*-%s", h_string,
692 fo->fi->lfd_resolution, ch, w, lpEncoding );
693 break;
695 case 9:
696 case 10:
697 case 11:
698 sprintf( lpch, "%s-*-%i-%c-*-*-%s",
699 h_string, fo->fi->lfd_resolution, ch, lpEncoding );
700 break;
702 case 12:
703 case 13:
704 case 14:
705 sprintf( lpch, "%i-*-%i-%c-*-*-%s", fo->fi->lfd_height,
706 fo->fi->lfd_resolution, ch, lpEncoding );
707 break;
709 case 15:
710 sprintf( lpch, "%i-*-*-*-*-*-%s", fo->fi->lfd_height, lpEncoding );
711 break;
713 default:
714 sprintf( lpch, "%i-*-*-*-*-*-*-*", fo->fi->lfd_height);
715 break;
717 /* to avoid an infinite loop; those will allways match */
718 case 200:
719 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1" );
720 break;
721 case 201:
722 sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" );
723 break;
726 TRACE(font,"\tLFD(uRelax=%d): %s\n", uRelax, lpLFD );
727 assert(*(lpLFD+MAX_LFD_LENGTH-1)==0); /* check if overwrittem */
728 return TRUE;
732 /***********************************************************************
733 * X Font Resources
735 * font info - http://www.microsoft.com/kb/articles/q65/1/23.htm
736 * Windows font metrics - http://www.microsoft.com/kb/articles/q32/6/67.htm
738 static BOOL32 XFONT_GetLeading( LPIFONTINFO16 pFI, XFontStruct* x_fs, INT32*
739 pIL, INT32* pEL, XFONTTRANS *XFT )
741 unsigned long height;
742 unsigned min = (unsigned char)pFI->dfFirstChar;
743 unsigned max = (unsigned char)pFI->dfLastChar;
744 BOOL32 bHaveCapHeight = (pFI->dfCharSet == ANSI_CHARSET && 'X' >= min && 'X' <= max );
746 if( pEL ) *pEL = 0;
748 if(XFT) {
749 Atom RAW_CAP_HEIGHT = TSXInternAtom(display, "RAW_CAP_HEIGHT", TRUE);
750 if(TSXGetFontProperty(x_fs, RAW_CAP_HEIGHT, &height))
751 *pIL = XFT->ascent -
752 (INT32)(XFT->pixelsize / 1000.0 * height);
753 else
754 *pIL = 0;
755 return bHaveCapHeight && x_fs->per_char;
758 if( TSXGetFontProperty(x_fs, XA_CAP_HEIGHT, &height) == FALSE )
760 if( x_fs->per_char )
761 if( bHaveCapHeight )
762 height = x_fs->per_char['X' - min].ascent;
763 else
764 if (x_fs->ascent >= x_fs->max_bounds.ascent)
765 height = x_fs->max_bounds.ascent;
766 else
768 height = x_fs->ascent;
769 if( pEL )
770 *pEL = x_fs->max_bounds.ascent - height;
772 else
773 height = x_fs->min_bounds.ascent;
776 *pIL = x_fs->ascent - height;
777 return (bHaveCapHeight && x_fs->per_char);
780 static INT32 XFONT_GetAvgCharWidth( LPIFONTINFO16 pFI, XFontStruct* x_fs,
781 XFONTTRANS *XFT)
783 unsigned min = (unsigned char)pFI->dfFirstChar;
784 unsigned max = (unsigned char)pFI->dfLastChar;
786 if( x_fs->per_char )
788 int width, chars, j;
789 for( j = 0, width = 0, chars = 0, max -= min; j <= max; j++ )
790 if( !CI_NONEXISTCHAR(x_fs->per_char + j) )
792 if(!XFT)
793 width += x_fs->per_char[j].width;
794 else
795 width += x_fs->per_char[j].attributes *
796 XFT->pixelsize / 1000.0;
797 chars++;
799 return (width / chars);
801 /* uniform width */
802 return x_fs->min_bounds.width;
805 static INT32 XFONT_GetMaxCharWidth(fontObject *pfo)
807 unsigned min = (unsigned char)pfo->fs->min_char_or_byte2;
808 unsigned max = (unsigned char)pfo->fs->max_char_or_byte2;
810 if(!pfo->lpX11Trans)
811 return abs(pfo->fs->max_bounds.width);
813 if( pfo->fs->per_char )
815 int maxwidth, j;
816 for( j = 0, maxwidth = 0, max -= min; j <= max; j++ )
817 if( !CI_NONEXISTCHAR(pfo->fs->per_char + j) )
818 if(maxwidth < pfo->fs->per_char[j].attributes)
819 maxwidth = pfo->fs->per_char[j].attributes;
821 maxwidth *= pfo->lpX11Trans->pixelsize / 1000.0;
822 return maxwidth;
824 return pfo->foAvgCharWidth;
827 /***********************************************************************
828 * XFONT_SetFontMetric
830 * Initializes IFONTINFO16. dfHorizRes and dfVertRes must be already set.
832 static void XFONT_SetFontMetric(fontInfo* fi, fontResource* fr, XFontStruct* xfs)
834 unsigned min, max;
835 INT32 el, il;
837 fi->df.dfFirstChar = (BYTE)(min = xfs->min_char_or_byte2);
838 fi->df.dfLastChar = (BYTE)(max = xfs->max_char_or_byte2);
840 fi->df.dfDefaultChar = (BYTE)xfs->default_char;
841 fi->df.dfBreakChar = (BYTE)(( ' ' < min || ' ' > max) ? xfs->default_char: ' ');
843 fi->df.dfPixHeight = (INT16)((fi->df.dfAscent = (INT16)xfs->ascent) + xfs->descent);
844 fi->df.dfPixWidth = (xfs->per_char) ? 0 : xfs->min_bounds.width;
845 fi->df.dfMaxWidth = (INT16)abs(xfs->max_bounds.width);
847 if( XFONT_GetLeading( &fi->df, xfs, &il, &el, NULL ) )
848 fi->df.dfAvgWidth = (INT16)xfs->per_char['X' - min].width;
849 else
850 fi->df.dfAvgWidth = (INT16)XFONT_GetAvgCharWidth( &fi->df, xfs, NULL);
852 fi->df.dfInternalLeading = (INT16)il;
853 fi->df.dfExternalLeading = (INT16)el;
855 fi->df.dfPoints = (INT16)(((INT32)(fi->df.dfPixHeight -
856 fi->df.dfInternalLeading) * 72 + (fi->df.dfVertRes >> 1)) / fi->df.dfVertRes);
858 if( xfs->min_bounds.width != xfs->max_bounds.width )
859 fi->df.dfPitchAndFamily |= TMPF_FIXED_PITCH; /* au contraire! */
860 if( fi->fi_flags & FI_SCALABLE )
862 fi->df.dfType = DEVICE_FONTTYPE;
863 fi->df.dfPitchAndFamily |= TMPF_DEVICE;
865 else if( fi->fi_flags & FI_TRUETYPE )
866 fi->df.dfType = TRUETYPE_FONTTYPE;
867 else
868 fi->df.dfType = RASTER_FONTTYPE;
870 fi->df.dfFace = fr->lfFaceName;
873 /***********************************************************************
874 * XFONT_GetTextMetric
876 static void XFONT_GetTextMetric( fontObject* pfo, LPTEXTMETRIC32A pTM )
878 LPIFONTINFO16 pdf = &pfo->fi->df;
880 if( ! pfo->lpX11Trans ) {
881 pTM->tmAscent = pfo->fs->ascent;
882 pTM->tmDescent = pfo->fs->descent;
883 } else {
884 pTM->tmAscent = pfo->lpX11Trans->ascent;
885 pTM->tmDescent = pfo->lpX11Trans->descent;
887 pTM->tmHeight = pTM->tmAscent + pTM->tmDescent;
889 pTM->tmAveCharWidth = pfo->foAvgCharWidth;
890 pTM->tmMaxCharWidth = pfo->foMaxCharWidth;
892 pTM->tmInternalLeading = pfo->foInternalLeading;
893 pTM->tmExternalLeading = pdf->dfExternalLeading;
895 pTM->tmStruckOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT )
896 ? 1 : pdf->dfStrikeOut;
897 pTM->tmUnderlined = (pfo->fo_flags & FO_SYNTH_UNDERLINE )
898 ? 1 : pdf->dfUnderline;
900 pTM->tmOverhang = 0;
901 if( pfo->fo_flags & FO_SYNTH_ITALIC )
903 pTM->tmOverhang += pTM->tmHeight/3;
904 pTM->tmItalic = 1;
905 } else
906 pTM->tmItalic = pdf->dfItalic;
908 pTM->tmWeight = pdf->dfWeight;
909 if( pfo->fo_flags & FO_SYNTH_BOLD )
911 pTM->tmOverhang++;
912 pTM->tmWeight += 100;
915 *(INT32*)&pTM->tmFirstChar = *(INT32*)&pdf->dfFirstChar;
917 pTM->tmCharSet = pdf->dfCharSet;
918 pTM->tmPitchAndFamily = pdf->dfPitchAndFamily;
920 pTM->tmDigitizedAspectX = pdf->dfHorizRes;
921 pTM->tmDigitizedAspectY = pdf->dfVertRes;
924 /***********************************************************************
925 * XFONT_GetFontMetric
927 * Retrieve font metric info (enumeration).
929 static UINT32 XFONT_GetFontMetric( fontInfo* pfi, LPENUMLOGFONTEX16 pLF,
930 LPNEWTEXTMETRIC16 pTM )
932 memset( pLF, 0, sizeof(*pLF) );
933 memset( pTM, 0, sizeof(*pTM) );
935 #define plf ((LPLOGFONT16)pLF)
936 plf->lfHeight = pTM->tmHeight = pfi->df.dfPixHeight;
937 plf->lfWidth = pTM->tmAveCharWidth = pfi->df.dfAvgWidth;
938 plf->lfWeight = pTM->tmWeight = pfi->df.dfWeight;
939 plf->lfItalic = pTM->tmItalic = pfi->df.dfItalic;
940 plf->lfUnderline = pTM->tmUnderlined = pfi->df.dfUnderline;
941 plf->lfStrikeOut = pTM->tmStruckOut = pfi->df.dfStrikeOut;
942 plf->lfCharSet = pTM->tmCharSet = pfi->df.dfCharSet;
944 /* convert pitch values */
946 pTM->tmPitchAndFamily = pfi->df.dfPitchAndFamily;
947 plf->lfPitchAndFamily = (pfi->df.dfPitchAndFamily & 0xF1) + 1;
949 lstrcpyn32A( plf->lfFaceName, pfi->df.dfFace, LF_FACESIZE );
950 #undef plf
952 pTM->tmAscent = pfi->df.dfAscent;
953 pTM->tmDescent = pTM->tmHeight - pTM->tmAscent;
954 pTM->tmInternalLeading = pfi->df.dfInternalLeading;
955 pTM->tmMaxCharWidth = pfi->df.dfMaxWidth;
956 pTM->tmDigitizedAspectX = pfi->df.dfHorizRes;
957 pTM->tmDigitizedAspectY = pfi->df.dfVertRes;
959 *(INT32*)&pTM->tmFirstChar = *(INT32*)&pfi->df.dfFirstChar;
961 /* return font type */
963 return pfi->df.dfType;
967 /***********************************************************************
968 * XFONT_FixupFlags
970 * dfPitchAndFamily flags for some common typefaces.
972 static BYTE XFONT_FixupFlags( LPCSTR lfFaceName )
974 switch( lfFaceName[0] )
976 case 'h':
977 case 'H': if(!strcasecmp(lfFaceName, "Helvetica") )
978 return FF_SWISS;
979 break;
980 case 'c':
981 case 'C': if(!strcasecmp(lfFaceName, "Courier") ||
982 !strcasecmp(lfFaceName, "Charter") )
983 return FF_ROMAN;
984 break;
985 case 'p':
986 case 'P': if( !strcasecmp(lfFaceName,"Palatino") )
987 return FF_ROMAN;
988 break;
989 case 't':
990 case 'T': if(!strncasecmp(lfFaceName, "Times", 5) )
991 return FF_ROMAN;
992 break;
993 case 'u':
994 case 'U': if(!strcasecmp(lfFaceName, "Utopia") )
995 return FF_ROMAN;
996 break;
997 case 'z':
998 case 'Z': if(!strcasecmp(lfFaceName, "Zapf Dingbats") )
999 return FF_DECORATIVE;
1001 return 0;
1005 /***********************************************************************
1006 * XFONT_CheckResourceName
1008 static BOOL32 XFONT_CheckResourceName( LPSTR resource, LPCSTR name, INT32 n )
1010 resource = LFD_Advance( resource, 2 );
1011 if( resource )
1012 return (!strncasecmp( resource, name, n ));
1013 return FALSE;
1017 /***********************************************************************
1018 * XFONT_WindowsNames
1020 * Build generic Windows aliases for X font names.
1022 * -misc-fixed- -> "Fixed"
1023 * -sony-fixed- -> "Sony Fixed", etc...
1025 static void XFONT_WindowsNames( char* buffer )
1027 fontResource* fr, *pfr;
1028 char* lpstr, *lpch;
1029 int i, up;
1030 BYTE bFamilyStyle;
1031 const char* relocTable[] = { INIDefaultFixed, INIDefault, NULL };
1033 for( fr = fontList; fr ; fr = fr->next )
1035 if( fr->fr_flags & FR_NAMESET ) continue; /* skip already assigned */
1037 lpstr = LFD_Advance(fr->resource, 2);
1038 i = LFD_Advance( lpstr, 1 ) - lpstr;
1040 for( pfr = fontList; pfr != fr ; pfr = pfr->next )
1041 if( pfr->fr_flags & FR_NAMESET )
1042 if( XFONT_CheckResourceName( pfr->resource, lpstr, i ) )
1043 break;
1045 if( pfr != fr ) /* prepend vendor name */
1046 lpstr = fr->resource + 1;
1048 for( i = 0, up = 1, lpch = fr->lfFaceName; *lpstr && i < 32;
1049 lpch++, lpstr++, i++ )
1051 if( *lpstr == LFDSeparator[1] || *lpstr == ' ' )
1053 *lpch = ' ';
1054 up = 1; continue;
1056 else if( isalpha(*lpstr) && up )
1058 *lpch = toupper(*lpstr);
1059 up = 0; continue;
1061 *lpch = *lpstr;
1063 while (*(lpch - 1) == ' ') *(--lpch) = '\0';
1065 if( (bFamilyStyle = XFONT_FixupFlags( fr->lfFaceName )) )
1067 fontInfo* fi;
1068 for( fi = fr->fi ; fi ; fi = fi->next )
1069 fi->df.dfPitchAndFamily |= bFamilyStyle;
1072 TRACE(font,"typeface \'%s\'\n", fr->lfFaceName);
1074 fr->fr_flags |= FR_NAMESET;
1077 for( up = 0; relocTable[up]; up++ )
1078 if( PROFILE_GetWineIniString( INIFontSection, relocTable[up], "", buffer, 128 ) )
1080 while( *buffer && isspace(*buffer) ) buffer++;
1081 for( fr = NULL, pfr = fontList; pfr; pfr = pfr->next )
1083 i = strlen( pfr->resource );
1084 if( !strncasecmp( pfr->resource, buffer, i) )
1086 if( fr )
1088 fr->next = pfr->next;
1089 pfr->next = fontList;
1090 fontList = pfr;
1092 break;
1094 fr = pfr;
1099 /***********************************************************************
1100 * XFONT_CreateAlias
1102 static fontAlias* XFONT_CreateAlias( LPCSTR lpTypeFace, LPCSTR lpAlias )
1104 int j;
1105 fontAlias* pfa = aliasTable;
1107 while( 1 )
1109 /* check if we already got one */
1110 if( !strcasecmp( pfa->faTypeFace, lpAlias ) )
1112 TRACE(font,"\tredundant alias '%s' -> '%s'\n",
1113 lpAlias, lpTypeFace );
1114 return NULL;
1116 if( pfa->next ) pfa = pfa->next;
1117 else break;
1120 j = lstrlen32A(lpTypeFace) + 1;
1121 pfa->next = HeapAlloc( SystemHeap, 0, sizeof(fontAlias) +
1122 j + lstrlen32A(lpAlias) + 1 );
1123 if((pfa = pfa->next))
1125 pfa->next = NULL;
1126 pfa->faTypeFace = (LPSTR)(pfa + 1);
1127 lstrcpy32A( pfa->faTypeFace, lpTypeFace );
1128 pfa->faAlias = pfa->faTypeFace + j;
1129 lstrcpy32A( pfa->faAlias, lpAlias );
1131 TRACE(font, "\tadded alias '%s' for %s\n", lpAlias, lpTypeFace );
1133 return pfa;
1135 return NULL;
1138 /***********************************************************************
1139 * XFONT_LoadAliases
1141 * Read user-defined aliases from wine.conf. Format is as follows
1143 * Alias# = [Windows font name],[LFD font name], <substitute original name>
1145 * Example:
1146 * Alias0 = Arial, -adobe-helvetica-
1147 * Alias1 = Times New Roman, -bitstream-courier-, 1
1148 * ...
1150 * Note that from 081797 and on we have built-in alias templates that take
1151 * care of the necessary Windows typefaces.
1153 static void XFONT_LoadAliases( char** buffer, int buf_size )
1155 char* lpResource, *lpAlias;
1156 char subsection[32];
1157 int i = 0, j = 0;
1158 BOOL32 bHaveAlias = TRUE, bSubst = FALSE;
1160 if( buf_size < 128 )
1161 *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
1164 if( j < faTemplateNum )
1166 /* built-in templates first */
1168 lpResource = faTemplate[j].fatResource;
1169 lpAlias = faTemplate[j].fatAlias;
1170 j++;
1172 else
1174 /* then WINE.CONF */
1176 wsprintf32A( subsection, "%s%i", INISubSection, i++ );
1178 if( (bHaveAlias = PROFILE_GetWineIniString( INIFontSection,
1179 subsection, "", *buffer, 128 )) )
1181 lpAlias = *buffer;
1182 while( isspace(*lpAlias) ) lpAlias++;
1183 lpResource = PROFILE_GetStringItem( lpAlias );
1184 bSubst = (PROFILE_GetStringItem( lpResource )) ? TRUE : FALSE;
1188 if( bHaveAlias )
1190 int length;
1192 length = strlen( lpAlias );
1193 if( lpResource && length )
1195 fontResource* fr, *frMatch = NULL;
1197 for (fr = fontList; fr ; fr = fr->next)
1199 if( !strcasecmp( fr->resource, lpResource ) ) frMatch = fr;
1200 if( XFONT_CheckResourceName( fr->resource, lpAlias, length ) )
1202 /* alias is not needed since the real font is present */
1203 frMatch = NULL; break;
1207 if( frMatch )
1209 if( bSubst )
1211 fontAlias *pfa, *prev = NULL;
1213 for(pfa = aliasTable; pfa; pfa = pfa->next)
1215 /* Remove lpAlias from aliasTable - we should free the old entry */
1216 if(!strcmp(lpAlias, pfa->faAlias))
1218 if(prev)
1219 prev->next = pfa->next;
1220 else
1221 aliasTable = pfa->next;
1224 /* Update any references to the substituted font in aliasTable */
1225 if(!strcmp(frMatch->lfFaceName,
1226 pfa->faTypeFace))
1227 pfa->faTypeFace = HEAP_strdupA( SystemHeap, 0,
1228 lpAlias );
1229 prev = pfa;
1232 TRACE(font, "\tsubstituted '%s' with %s\n",
1233 frMatch->lfFaceName, lpAlias );
1235 lstrcpyn32A( frMatch->lfFaceName, lpAlias, LF_FACESIZE );
1236 frMatch->fr_flags |= FR_NAMESET;
1238 else
1240 /* create new entry in the alias table */
1241 XFONT_CreateAlias( frMatch->lfFaceName, lpAlias );
1245 else ERR(font, " malformed font alias '%s'\n", *buffer );
1247 else break;
1248 } while(TRUE);
1251 /***********************************************************************
1252 * XFONT_UserMetricsCache
1254 * Returns expanded name for the ~/.wine/.cachedmetrics file.
1256 static char* XFONT_UserMetricsCache( char* buffer, int* buf_size )
1258 struct passwd* pwd;
1260 pwd = getpwuid(getuid());
1261 if( pwd && pwd->pw_dir )
1263 int i = strlen( pwd->pw_dir ) + strlen( INIWinePrefix ) +
1264 strlen( INIFontMetrics ) + 2;
1265 if( i > *buf_size )
1266 buffer = (char*) HeapReAlloc( SystemHeap, 0, buffer, *buf_size = i );
1267 strcpy( buffer, pwd->pw_dir );
1268 strcat( buffer, INIWinePrefix );
1269 strcat( buffer, INIFontMetrics );
1270 } else buffer[0] = '\0';
1271 return buffer;
1275 /***********************************************************************
1276 * XFONT_ReadCachedMetrics
1278 static BOOL32 XFONT_ReadCachedMetrics( int fd, int res, unsigned x_checksum, int x_count )
1280 if( fd >= 0 )
1282 unsigned u;
1283 int i, j;
1285 /* read checksums */
1286 read( fd, &u, sizeof(unsigned) );
1287 read( fd, &i, sizeof(int) );
1289 if( u == x_checksum && i == x_count )
1291 off_t length, offset = 3 * sizeof(int);
1293 /* read total size */
1294 read( fd, &i, sizeof(int) );
1295 length = lseek( fd, 0, SEEK_END );
1297 if( length == (i + offset) )
1299 lseek( fd, offset, SEEK_SET );
1300 fontList = (fontResource*)HeapAlloc( SystemHeap, 0, i);
1301 if( fontList )
1303 fontResource* pfr = fontList;
1304 fontInfo* pfi = NULL;
1306 TRACE(font,"Reading cached font metrics:\n");
1308 read( fd, fontList, i); /* read all metrics at once */
1309 while( offset < length )
1311 offset += sizeof(fontResource) + sizeof(fontInfo);
1312 pfr->fi = pfi = (fontInfo*)(pfr + 1);
1313 j = 1;
1314 while( TRUE )
1316 if( offset > length ||
1317 (int)(pfi->next) != j++ ) goto fail;
1319 pfi->df.dfFace = pfr->lfFaceName;
1320 pfi->df.dfHorizRes = pfi->df.dfVertRes = res;
1321 pfi->df.dfPoints = (INT16)(((INT32)(pfi->df.dfPixHeight -
1322 pfi->df.dfInternalLeading) * 72 + (res >> 1)) / res );
1323 pfi->next = pfi + 1;
1325 if( j > pfr->count ) break;
1327 pfi = pfi->next;
1328 offset += sizeof(fontInfo);
1330 pfi->next = NULL;
1331 if( pfr->next )
1333 pfr->next = (fontResource*)(pfi + 1);
1334 pfr = pfr->next;
1336 else break;
1338 if( pfr->next == NULL &&
1339 *(int*)(pfi + 1) == X_FMC_MAGIC )
1341 /* read LFD stubs */
1342 char* lpch = (char*)((int*)(pfi + 1) + 1);
1343 offset += sizeof(int);
1344 for( pfr = fontList; pfr; pfr = pfr->next )
1346 TRACE(font,"\t%s, %i instances\n", lpch, pfr->count );
1347 pfr->resource = lpch;
1348 while( TRUE )
1350 if( ++offset > length ) goto fail;
1351 if( !*lpch++ ) break;
1354 close( fd );
1355 return TRUE;
1360 fail:
1361 if( fontList ) HeapFree( SystemHeap, 0, fontList );
1362 fontList = NULL;
1363 close( fd );
1365 return FALSE;
1368 /***********************************************************************
1369 * XFONT_WriteCachedMetrics
1371 static BOOL32 XFONT_WriteCachedMetrics( int fd, unsigned x_checksum, int x_count, int n_ff )
1373 fontResource* pfr;
1374 fontInfo* pfi;
1376 if( fd >= 0 )
1378 int i, j, k;
1380 /* font metrics file:
1382 * +0000 x_checksum
1383 * +0004 x_count
1384 * +0008 total size to load
1385 * +000C prepackaged font metrics
1386 * ...
1387 * +...x X_FMC_MAGIC
1388 * +...x + 4 LFD stubs
1391 write( fd, &x_checksum, sizeof(unsigned) );
1392 write( fd, &x_count, sizeof(int) );
1394 for( j = i = 0, pfr = fontList; pfr; pfr = pfr->next )
1396 i += strlen( pfr->resource ) + 1;
1397 j += pfr->count;
1399 i += n_ff * sizeof(fontResource) + j * sizeof(fontInfo) + sizeof(int);
1400 write( fd, &i, sizeof(int) );
1402 TRACE(font,"Writing font cache:\n");
1404 for( pfr = fontList; pfr; pfr = pfr->next )
1406 fontInfo fi;
1408 TRACE(font,"\t%s, %i instances\n", pfr->resource, pfr->count );
1410 i = write( fd, pfr, sizeof(fontResource) );
1411 if( i == sizeof(fontResource) )
1413 for( k = 1, pfi = pfr->fi; pfi; pfi = pfi->next )
1415 memcpy( &fi, pfi, sizeof(fi) );
1417 fi.df.dfFace = NULL;
1418 fi.next = (fontInfo*)k; /* loader checks this */
1420 j = write( fd, &fi, sizeof(fi) );
1421 k++;
1423 if( j == sizeof(fontInfo) ) continue;
1425 break;
1427 if( i == sizeof(fontResource) && j == sizeof(fontInfo) )
1429 i = j = X_FMC_MAGIC;
1430 write( fd, &i, sizeof(int) );
1431 for( pfr = fontList; pfr && i == j; pfr = pfr->next )
1433 i = strlen( pfr->resource ) + 1;
1434 j = write( fd, pfr->resource, i );
1437 close( fd );
1438 return ( i == j );
1440 return TRUE;
1443 /***********************************************************************
1444 * XFONT_CheckIniSection
1446 * Examines wine.conf for old/invalid font entries and recommend changes to
1447 * the user.
1449 * Revision history
1450 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
1451 * Original implementation.
1453 static void XFONT_CheckIniCallback(char const *, char const *, void *);
1455 static char const *fontmsgprologue =
1456 "Wine warning:\n"
1457 " The following entries in the [fonts] section of the wine.conf file are\n"
1458 " obsolete or invalid:\n";
1460 static char const *fontmsgepilogue =
1461 " These entries should be eliminated or updated.\n"
1462 " See the documentation/fonts file for more information.\n";
1464 static int XFONT_CheckIniSection()
1466 int found = 0;
1468 PROFILE_EnumerateWineIniSection("Fonts", &XFONT_CheckIniCallback,
1469 (void *)&found);
1470 if(found)
1471 MSG(fontmsgepilogue);
1473 return 1;
1476 static void XFONT_CheckIniCallback(
1477 char const *key,
1478 char const *value,
1479 void *found)
1481 /* Ignore any keys that start with potential comment characters "'", '#',
1482 or ';'. */
1483 if(key[0] == '\'' || key[0] == '#' || key[0] == ';' || key[0] == '\0')
1484 return;
1486 /* Make sure this is a valid key */
1487 if((strncasecmp(key, INISubSection, 5) == 0) ||
1488 (strcasecmp( key, INIDefault) == 0) ||
1489 (strcasecmp( key, INIDefaultFixed) == 0) ||
1490 (strcasecmp( key, INIGlobalMetrics) == 0) ||
1491 (strcasecmp( key, INIResolution) == 0) ||
1492 (strcasecmp( key, INIDefaultSerif) == 0) ||
1493 (strcasecmp( key, INIDefaultSansSerif) ==0) )
1495 /* Valid key; make sure the value doesn't contain a wildcard */
1496 if(strchr(value, '*')) {
1497 if(*(int *)found == 0) {
1498 MSG(fontmsgprologue);
1499 ++*(int *)found;
1502 MSG(" %s=%s [no wildcards allowed]\n", key, value);
1505 else {
1506 /* Not a valid key */
1507 if(*(int *)found == 0) {
1508 MSG(fontmsgprologue);
1509 ++*(int *)found;
1512 MSG(" %s=%s [obsolete]\n", key, value);
1515 return;
1518 /***********************************************************************
1519 * XFONT_GetPointResolution()
1521 * Here we initialize DefResolution which is used in the
1522 * XFONT_Match() penalty function. We also load the point
1523 * resolution value (higher values result in larger fonts).
1525 static int XFONT_GetPointResolution( DeviceCaps* pDevCaps )
1527 int i, j, point_resolution, num = 3;
1528 int allowed_xfont_resolutions[3] = { 72, 75, 100 };
1529 int best = 0, best_diff = 65536;
1531 DefResolution = point_resolution = PROFILE_GetWineIniInt( INIFontSection, INIResolution, 0 );
1532 if( !DefResolution ) DefResolution = point_resolution = pDevCaps->logPixelsY;
1533 else pDevCaps->logPixelsX = pDevCaps->logPixelsY = DefResolution;
1535 for( i = best = 0; i < num; i++ )
1537 j = abs( DefResolution - allowed_xfont_resolutions[i] );
1538 if( j < best_diff )
1540 best = i;
1541 best_diff = j;
1544 DefResolution = allowed_xfont_resolutions[best];
1545 return point_resolution;
1548 /***********************************************************************
1549 * XFONT_BuildDefaultAliases
1551 * Alias "Helv", and "Tms Rmn" to the DefaultSansSerif and DefaultSerif
1552 * fonts respectively. Create font alias templates for "MS Sans Serif"
1553 * and "MS Serif", also pointing to DefaultSansSerif and DefaultSerif.
1555 static int XFONT_BuildDefaultAliases( char** buffer, int* buf_size )
1558 aliasTemplate fatDefaultSerif = { "-bitstream-charter-", "Charter" };
1559 aliasTemplate fatDefaultSansSerif = { "-adobe-helvetica-", "Helvetica" };
1561 fontResource* fr;
1563 /* Make sure our buffer is big enough; update calling function's
1564 buf_size if we change it. */
1566 if( *buf_size < 128 )
1568 *buffer = HeapReAlloc( SystemHeap, 0, *buffer, 256 );
1569 *buf_size = 256;
1572 /* Get the X11 name of the default serif font from the Wine INI file.
1573 (-bitstream-charter- is the default.) */
1575 PROFILE_GetWineIniString( INIFontSection, INIDefaultSerif,
1576 fatDefaultSerif.fatResource, *buffer, 128 );
1578 /* Find the Windows typeface which corresponds to the X11 font. */
1580 for( fr = fontList; fr; fr = fr->next )
1581 if( !strcasecmp( fr->resource, *buffer ) ) break;
1583 /* Update the Alias Table entry for "Tms Rmn" with the default serif font's
1584 typeface. Update the Alias Template for "MS Serif" with the default
1585 serif font's X11 name. Note that this method leaves us dependant on
1586 the order of the Alias Table and the Alias Templates. Also, we don't
1587 check for or handle a situation in which -bitstream-charter- is not
1588 available. */
1590 if( fr )
1592 TRACE(font, "Using \'%s\' as default serif font\n", fr->lfFaceName);
1593 aliasTable[1].faTypeFace = fr->lfFaceName;
1594 faTemplate[1].fatResource = fr->resource;
1596 else
1598 WARN(font, "No typeface found for \'%s\'; using \'%s\'\n", *buffer,
1599 fatDefaultSerif.fatAlias);
1600 aliasTable[1].faTypeFace = fatDefaultSerif.fatAlias; /* Charter */
1601 faTemplate[1].fatResource = fatDefaultSerif.fatResource;
1604 /* Get the X11 name of the default sans serif font from the Wine INI file.
1605 (-adobe-helvetica- is the default.) */
1607 PROFILE_GetWineIniString (INIFontSection, INIDefaultSansSerif,
1608 fatDefaultSansSerif.fatResource, *buffer, 128 );
1610 /* Find the Windows typeface which corresponds to the X11 font. */
1612 for( fr = fontList; fr; fr = fr->next )
1613 if ( !strcasecmp( fr->resource, *buffer ) ) break;
1615 /* Update the Alias Table entry for "Helv" with the default sans serif font's
1616 typeface. Update the Alias Template for "MS Sans Serif" with the
1617 default sans serif font's X11 name. Note that this method leaves us
1618 dependant on the order of the Alias Table and the Alias Templates.
1619 Also, we don't check for or handle a situation in which
1620 -adobe-helvetica- is not available. */
1622 if( fr )
1624 TRACE(font, "Using \'%s\' as default sans serif font\n", fr->lfFaceName);
1625 aliasTable[0].faTypeFace = fr->lfFaceName;
1626 faTemplate[0].fatResource = fr->resource;
1628 else
1630 WARN(font, "No typeface found for \'%s\'; using \'%s\'\n", *buffer,
1631 fatDefaultSansSerif.fatAlias);
1632 aliasTable[0].faTypeFace = fatDefaultSansSerif.fatAlias; /* Helvetica */
1633 faTemplate[0].fatResource = fatDefaultSansSerif.fatResource;
1636 return 0;
1639 /***********************************************************************
1640 * X11DRV_FONT_Init
1642 * Initialize font resource list and allocate font cache.
1644 BOOL32 X11DRV_FONT_Init( DeviceCaps* pDevCaps )
1646 XFontStruct* x_fs;
1647 fontResource* fr, *pfr;
1648 fontInfo* fi, *pfi;
1649 unsigned x_checksum;
1650 int i, j, res, x_count, fd = -1, buf_size = 0;
1651 char* lpstr, *lpch, *lpmetrics, *buffer;
1652 char** x_pattern;
1654 XFONT_CheckIniSection();
1656 res = XFONT_GetPointResolution( pDevCaps );
1658 x_pattern = TSXListFonts(display, "*", MAX_FONT_FAMILIES * 16, &x_count );
1660 TRACE(font,"Font Mapper: initializing %i fonts [LPY=%i, XDR=%i, DR=%i]\n",
1661 x_count, pDevCaps->logPixelsY, DefResolution, res);
1662 for( i = x_checksum = 0; i < x_count; i++ )
1664 #if 0
1665 printf("%i\t: %s\n", i, x_pattern[i] );
1666 #endif
1668 j = strlen( x_pattern[i] );
1669 if( j ) x_checksum ^= __genericCheckSum( x_pattern[i], j );
1671 x_checksum |= X_PFONT_MAGIC;
1673 buf_size = 128;
1674 buffer = HeapAlloc( SystemHeap, 0, buf_size );
1675 lpmetrics = NULL;
1677 /* deal with systemwide font metrics cache */
1679 if( PROFILE_GetWineIniString( INIFontSection, INIGlobalMetrics, "", buffer, 128 ) )
1680 fd = open( buffer, O_RDONLY );
1682 if( XFONT_ReadCachedMetrics(fd, res, x_checksum, x_count) == FALSE )
1684 /* try per-user */
1685 buffer = XFONT_UserMetricsCache( buffer, &buf_size );
1686 if( buffer[0] )
1688 fd = open( buffer, O_RDONLY );
1689 if( XFONT_ReadCachedMetrics(fd, res, x_checksum, x_count) == FALSE )
1690 lpmetrics = HEAP_strdupA( SystemHeap, 0, buffer ); /* update later on */
1694 fi = NULL;
1695 if( fontList == NULL ) /* build metrics from scratch */
1697 int n_ff;
1698 char* typeface;
1700 for( i = n_ff = 0; i < x_count; i++ )
1702 typeface = lpch = x_pattern[i];
1704 lpch = LFD_Advance(typeface, 3); /* extra '-' in the beginning */
1705 if( !*lpch ) continue;
1707 lpstr = lpch;
1708 j = lpch - typeface; /* resource name length */
1710 /* find a family to insert into */
1712 for( pfr = NULL, fr = fontList; fr; fr = fr->next )
1714 if( !strncasecmp(fr->resource, typeface, j) &&
1715 strlen(fr->resource) == j ) break;
1716 pfr = fr;
1719 if( !fi ) fi = (fontInfo*) HeapAlloc(SystemHeap, 0, sizeof(fontInfo));
1721 if( !fr ) /* add new family */
1723 if( n_ff >= MAX_FONT_FAMILIES ) break;
1724 if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1726 n_ff++;
1727 fr = (fontResource*) HeapAlloc(SystemHeap, 0, sizeof(fontResource));
1728 memset(fr, 0, sizeof(fontResource));
1729 fr->resource = (char*) HeapAlloc(SystemHeap, 0, j + 1 );
1730 lstrcpyn32A( fr->resource, typeface, j + 1 );
1732 TRACE(font," family: %s\n", fr->resource );
1734 if( pfr ) pfr->next = fr;
1735 else fontList = fr;
1737 else if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1739 /* check if we already have something better than "fi" */
1741 for( pfi = fr->fi, j = 0; pfi && j <= 0; pfi = pfi->next )
1742 if( (j = XFONT_IsSubset( pfi, fi )) < 0 )
1743 pfi->fi_flags |= FI_SUBSET; /* superseded by "fi" */
1744 if( j > 0 ) continue;
1746 /* add new font instance "fi" to the "fr" font resource */
1748 if( fi->fi_flags & FI_SCALABLE )
1750 /* set scalable font height to 24 to get an origin for extrapolation */
1752 j = strlen(typeface); j += 0x10;
1753 if( j > buf_size )
1754 buffer = (char*)HeapReAlloc( SystemHeap, 0, buffer, buf_size = j );
1756 lpch = LFD_Advance(typeface, 7);
1757 memcpy( buffer, typeface, (j = lpch - typeface) );
1758 lpch = LFD_Advance(lpch, 4);
1759 sprintf( buffer + j, "%d-%d-%d-*-%c-*-", fi->lfd_height,
1760 fi->lfd_decipoints, fi->lfd_resolution,
1761 (*lpch == '-')?'*':*lpch );
1762 lpch = LFD_Advance(lpch, 2);
1763 strcat( lpstr = buffer, lpch);
1765 else lpstr = typeface;
1767 if( (x_fs = TSXLoadQueryFont(display, lpstr)) )
1769 fi->df.dfHorizRes = fi->df.dfVertRes = res;
1771 XFONT_SetFontMetric( fi, fr, x_fs );
1772 TSXFreeFont( display, x_fs );
1774 TRACE(font,"\t[% 2ipt] '%s'\n", fi->df.dfPoints, typeface );
1776 XFONT_CheckFIList( fr, fi, REMOVE_SUBSETS );
1777 fi = NULL; /* preventing reuse */
1779 else
1781 ERR(font, "failed to load %s\n", lpstr );
1783 XFONT_CheckFIList( fr, fi, UNMARK_SUBSETS );
1787 if( lpmetrics ) /* update cached metrics */
1789 fd = open( lpmetrics, O_CREAT | O_TRUNC | O_RDWR, 0644 ); /* -rw-r--r-- */
1790 if( XFONT_WriteCachedMetrics( fd, x_checksum, x_count, n_ff ) == FALSE )
1791 if( fd ) remove( lpmetrics ); /* couldn't write entire file */
1792 HeapFree( SystemHeap, 0, lpmetrics );
1796 if( fi ) HeapFree(SystemHeap, 0, fi);
1797 TSXFreeFontNames(x_pattern);
1799 /* check if we're dealing with X11 R6 server */
1801 strcpy(buffer, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
1802 if( (x_fs = TSXLoadQueryFont(display, buffer)) )
1804 XTextCaps |= TC_SF_X_YINDEP;
1805 TSXFreeFont(display, x_fs);
1808 XFONT_WindowsNames( buffer );
1809 XFONT_BuildDefaultAliases( &buffer, &buf_size );
1810 XFONT_LoadAliases( &buffer, buf_size );
1811 HeapFree(SystemHeap, 0, buffer);
1814 /* fontList initialization is over, allocate X font cache */
1816 fontCache = (fontObject*) HeapAlloc(SystemHeap, 0, fontCacheSize * sizeof(fontObject));
1817 XFONT_GrowFreeList(0, fontCacheSize - 1);
1819 TRACE(font,"done!\n");
1821 /* update text caps parameter */
1823 pDevCaps->textCaps = XTextCaps;
1825 RAW_ASCENT = TSXInternAtom(display, "RAW_ASCENT", TRUE);
1826 RAW_DESCENT = TSXInternAtom(display, "RAW_DESCENT", TRUE);
1828 return TRUE;
1832 /***********************************************************************
1833 * X Font Matching
1835 * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1837 static INT32 XFONT_IsSubset(fontInfo* match, fontInfo* fi)
1839 INT32 m;
1841 /* 0 - keep both, 1 - keep match, -1 - keep fi */
1843 m = (BYTE*)&fi->df.dfPixWidth - (BYTE*)&fi->df.dfItalic;
1844 if( memcmp(&match->df.dfItalic, &fi->df.dfItalic, m )) return 0;
1846 if( (!((fi->fi_flags & FI_SCALABLE) + (match->fi_flags & FI_SCALABLE))
1847 && fi->lfd_height != match->lfd_height) ||
1848 (!((fi->fi_flags & FI_POLYWEIGHT) + (match->fi_flags & FI_POLYWEIGHT))
1849 && fi->df.dfWeight != match->df.dfWeight) ) return 0;
1851 m = (int)(match->fi_flags & (FI_POLYWEIGHT | FI_SCALABLE)) -
1852 (int)(fi->fi_flags & (FI_SCALABLE | FI_POLYWEIGHT));
1854 if( m == (FI_POLYWEIGHT - FI_SCALABLE) ||
1855 m == (FI_SCALABLE - FI_POLYWEIGHT) ) return 0; /* keep both */
1856 else if( m >= 0 ) return 1; /* 'match' is better */
1858 return -1; /* 'fi' is better */
1861 /***********************************************************************
1862 * XFONT_Match
1864 * Compute the matching score between the logical font and the device font.
1866 * contributions from highest to lowest:
1867 * charset
1868 * fixed pitch
1869 * height
1870 * family flags (only when the facename is not present)
1871 * width
1872 * weight, italics, underlines, strikeouts
1874 * NOTE: you can experiment with different penalty weights to see what happens.
1875 * http://premium.microsoft.com/msdn/library/techart/f365/f36b/f37b/d38b/sa8bf.htm
1877 static UINT32 XFONT_Match( fontMatch* pfm )
1879 fontInfo* pfi = pfm->pfi; /* device font to match */
1880 LPLOGFONT16 plf = pfm->plf; /* wanted logical font */
1881 UINT32 penalty = 0;
1882 BOOL32 bR6 = pfm->flags & FO_MATCH_XYINDEP; /* from TextCaps */
1883 BOOL32 bScale = pfi->fi_flags & FI_SCALABLE;
1884 INT32 d, h;
1886 TRACE(font,"\t[ %-2ipt h=%-3i w=%-3i %s%s]\n", pfi->df.dfPoints,
1887 pfi->df.dfPixHeight, pfi->df.dfAvgWidth,
1888 (pfi->df.dfWeight > 400) ? "Bold " : "Normal ",
1889 (pfi->df.dfItalic) ? "Italic" : "" );
1891 pfm->flags = 0;
1893 if( plf->lfCharSet == DEFAULT_CHARSET )
1895 if( (pfi->df.dfCharSet!= ANSI_CHARSET) && (pfi->df.dfCharSet!=DEFAULT_CHARSET) )
1896 penalty += 0x200;
1898 else if (plf->lfCharSet != pfi->df.dfCharSet) penalty += 0x200;
1900 /* FIXME: Hack to demote symbols and nil fonts. Should take into
1901 account if a program ever actually asked for this type of
1902 font */
1903 if ( (strcmp(pfm->pfr->lfFaceName,"Symbol")==0) || (strcmp(pfm->pfr->lfFaceName,"Nil")==0) )
1904 penalty += 0x200; /* very stiff penality */
1906 /* TMPF_FIXED_PITCH means exactly the opposite */
1908 if( plf->lfPitchAndFamily & FIXED_PITCH )
1910 if( pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH ) penalty += 0x100;
1912 else if( !(pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH) ) penalty += 0x2;
1914 if( plf->lfHeight > 0 )
1915 d = (h = pfi->df.dfPixHeight) - plf->lfHeight;
1916 else if( plf->lfHeight < -1 )
1917 d = (h = pfi->df.dfPoints) + plf->lfHeight;
1918 else d = h = 0;
1920 if( d && plf->lfHeight )
1922 UINT16 height = ( plf->lfHeight > 0 ) ? plf->lfHeight
1923 : ((-plf->lfHeight * pfi->df.dfPixHeight) / h);
1924 if( bScale ) pfm->height = height;
1925 else if( (plf->lfQuality != PROOF_QUALITY) && bR6 )
1927 if( d > 0 ) /* do not shrink raster fonts */
1929 pfm->height = pfi->df.dfPixHeight;
1930 penalty += (pfi->df.dfPixHeight - height) * 0x4;
1932 else /* expand only in integer multiples */
1934 pfm->height = height - height%pfi->df.dfPixHeight;
1935 penalty += (height - pfm->height + 1) * height / pfi->df.dfPixHeight;
1938 else /* can't be scaled at all */
1940 if( plf->lfQuality != PROOF_QUALITY) pfm->flags |= FO_SYNTH_HEIGHT;
1941 pfm->height = pfi->df.dfPixHeight;
1942 penalty += (d > 0)? d * 0x8 : -d * 0x10;
1944 } else pfm->height = pfi->df.dfPixHeight;
1946 if((pfm->flags & FO_MATCH_PAF) &&
1947 (plf->lfPitchAndFamily & FF_FAMILY) != (pfi->df.dfPitchAndFamily & FF_FAMILY) )
1948 penalty += 0x10;
1950 if( plf->lfWidth )
1952 if( bR6 && bScale ) h = 0;
1953 else
1955 /* FIXME: not complete */
1957 pfm->flags |= FO_SYNTH_WIDTH;
1958 h = abs(plf->lfWidth - (pfm->height * pfi->df.dfAvgWidth)/pfi->df.dfPixHeight);
1960 penalty += h * ( d ) ? 0x2 : 0x1 ;
1962 else if( !(pfi->fi_flags & FI_NORMAL) ) penalty++;
1964 if( plf->lfWeight != FW_DONTCARE )
1966 penalty += abs(plf->lfWeight - pfi->df.dfWeight) / 40;
1967 if( plf->lfWeight > pfi->df.dfWeight ) pfm->flags |= FO_SYNTH_BOLD;
1968 } else if( pfi->df.dfWeight >= FW_BOLD ) penalty++; /* choose normal by default */
1970 if( plf->lfItalic != pfi->df.dfItalic )
1972 penalty += 0x4;
1973 pfm->flags |= FO_SYNTH_ITALIC;
1976 if( plf->lfUnderline ) pfm->flags |= FO_SYNTH_UNDERLINE;
1977 if( plf->lfStrikeOut ) pfm->flags |= FO_SYNTH_STRIKEOUT;
1979 if( penalty && pfi->lfd_resolution != DefResolution )
1980 penalty++;
1982 TRACE(font," returning %i\n", penalty );
1984 return penalty;
1987 /***********************************************************************
1988 * XFONT_MatchFIList
1990 * Scan a particular font resource for the best match.
1992 static UINT32 XFONT_MatchFIList( fontMatch* pfm )
1994 BOOL32 skipRaster = (pfm->flags & FO_MATCH_NORASTER);
1995 UINT32 current_score, score = (UINT32)(-1);
1996 UINT16 origflags = pfm->flags; /* Preserve FO_MATCH_XYINDEP */
1997 fontMatch fm = *pfm;
1999 for( fm.pfi = pfm->pfr->fi; fm.pfi && score; fm.pfi = fm.pfi->next,
2000 fm.flags = origflags )
2002 if( skipRaster && !(fm.pfi->fi_flags & FI_SCALABLE) )
2003 continue;
2005 current_score = XFONT_Match( &fm );
2006 if( score > current_score )
2008 memcpy( pfm, &fm, sizeof(fontMatch) );
2009 score = current_score;
2012 return score;
2015 /***********************************************************************
2016 * XFONT_CheckFIList
2018 * REMOVE_SUBSETS - attach new fi and purge subsets
2019 * UNMARK_SUBSETS - remove subset flags from all fi entries
2021 static void XFONT_CheckFIList( fontResource* fr, fontInfo* fi, int action)
2023 int i = 0;
2024 fontInfo* pfi, *prev;
2026 for( prev = NULL, pfi = fr->fi; pfi; )
2028 if( action == REMOVE_SUBSETS )
2030 if( pfi->fi_flags & FI_SUBSET )
2032 fontInfo* subset = pfi;
2034 i++;
2035 fr->count--;
2036 if( prev ) prev->next = pfi = pfi->next;
2037 else fr->fi = pfi = pfi->next;
2038 HeapFree( SystemHeap, 0, subset );
2039 continue;
2042 else pfi->fi_flags &= ~FI_SUBSET;
2044 prev = pfi;
2045 pfi = pfi->next;
2048 if( action == REMOVE_SUBSETS ) /* also add the superset */
2050 if( fi->fi_flags & FI_SCALABLE )
2052 fi->next = fr->fi;
2053 fr->fi = fi;
2055 else if( prev ) prev->next = fi; else fr->fi = fi;
2056 fr->count++;
2059 if( i ) TRACE(font,"\t purged %i subsets [%i]\n", i , fr->count);
2062 /***********************************************************************
2063 * XFONT_FindFIList
2065 static fontResource* XFONT_FindFIList( fontResource* pfr, const char* pTypeFace )
2067 while( pfr )
2069 if( !strcasecmp( pfr->lfFaceName, pTypeFace ) ) break;
2070 pfr = pfr->next;
2072 return pfr;
2075 /***********************************************************************
2076 * XFONT_MatchDeviceFont
2078 * Scan font resource tree.
2080 static BOOL32 XFONT_MatchDeviceFont( fontResource* start, fontMatch* pfm )
2082 fontMatch fm = *pfm;
2084 pfm->pfi = NULL;
2085 if( fm.plf->lfFaceName[0] )
2087 fontAlias* fa;
2088 LPSTR str = NULL;
2090 for( fa = aliasTable; fa; fa = fa->next )
2091 if( !strcmp( fa->faAlias, fm.plf->lfFaceName ) )
2093 str = fa->faTypeFace;
2094 break;
2096 fm.pfr = XFONT_FindFIList( start, str ? str : fm.plf->lfFaceName );
2099 if( fm.pfr ) /* match family */
2101 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2103 XFONT_MatchFIList( &fm );
2104 *pfm = fm;
2107 if( !pfm->pfi ) /* match all available fonts */
2109 UINT32 current_score, score = (UINT32)(-1);
2111 fm.flags |= FO_MATCH_PAF;
2112 for( start = fontList; start && score; start = start->next )
2114 fm.pfr = start;
2116 TRACE(font, "%s\n", fm.pfr->lfFaceName );
2118 current_score = XFONT_MatchFIList( &fm );
2119 if( current_score < score )
2121 score = current_score;
2122 *pfm = fm;
2126 return TRUE;
2130 /***********************************************************************
2131 * X Font Cache
2133 static void XFONT_GrowFreeList(int start, int end)
2135 /* add all entries from 'start' up to and including 'end' */
2137 memset( fontCache + start, 0, (end - start + 1) * sizeof(fontObject) );
2139 fontCache[end].lru = fontLF;
2140 fontCache[end].count = -1;
2141 fontLF = start;
2142 while( start < end )
2144 fontCache[start].count = -1;
2145 fontCache[start].lru = start + 1;
2146 start++;
2150 static fontObject* XFONT_LookupCachedFont( LPLOGFONT16 plf, UINT16* checksum )
2152 UINT16 cs = __lfCheckSum( plf );
2153 int i = fontMRU, prev = -1;
2155 *checksum = cs;
2156 while( i >= 0 )
2158 if( fontCache[i].lfchecksum == cs &&
2159 !(fontCache[i].fo_flags & FO_REMOVED) )
2161 /* FIXME: something more intelligent here */
2163 if( !memcmp( plf, &fontCache[i].lf,
2164 sizeof(LOGFONT16) - LF_FACESIZE ) &&
2165 !strncasecmp( plf->lfFaceName, fontCache[i].lf.lfFaceName,
2166 LF_FACESIZE ) )
2168 /* remove temporarily from the lru list */
2170 if( prev >= 0 )
2171 fontCache[prev].lru = fontCache[i].lru;
2172 else
2173 fontMRU = (INT16)fontCache[i].lru;
2174 return (fontCache + i);
2177 prev = i;
2178 i = (INT16)fontCache[i].lru;
2180 return NULL;
2183 static fontObject* XFONT_GetCacheEntry()
2185 int i;
2187 if( fontLF == -1 )
2189 int prev_i, prev_j, j;
2191 TRACE(font,"font cache is full\n");
2193 /* lookup the least recently used font */
2195 for( prev_i = prev_j = j = -1, i = fontMRU; i >= 0; i = (INT16)fontCache[i].lru )
2197 if( fontCache[i].count <= 0 &&
2198 !(fontCache[i].fo_flags & FO_SYSTEM) )
2200 prev_j = prev_i;
2201 j = i;
2203 prev_i = i;
2206 if( j >= 0 ) /* unload font */
2208 /* detach from the lru list */
2210 TRACE(font,"\tfreeing entry %i\n", j );
2212 if( prev_j >= 0 )
2213 fontCache[prev_j].lru = fontCache[j].lru;
2214 else fontMRU = (INT16)fontCache[j].lru;
2216 /* FIXME: lpXForm, lpPixmap */
2217 if(fontCache[j].lpX11Trans)
2218 HeapFree( SystemHeap, 0, fontCache[j].lpX11Trans );
2220 TSXFreeFont( display, fontCache[j].fs );
2222 memset( fontCache + j, 0, sizeof(fontObject) );
2223 return (fontCache + j);
2225 else /* expand cache */
2227 fontObject* newCache;
2229 prev_i = fontCacheSize + FONTCACHE;
2231 TRACE(font,"\tgrowing font cache from %i to %i\n", fontCacheSize, prev_i );
2233 if( (newCache = (fontObject*)HeapReAlloc(SystemHeap, 0,
2234 fontCache, prev_i)) )
2236 i = fontCacheSize;
2237 fontCacheSize = prev_i;
2238 fontCache = newCache;
2239 XFONT_GrowFreeList( i, fontCacheSize - 1);
2241 else return NULL;
2245 /* detach from the free list */
2247 i = fontLF;
2248 fontLF = (INT16)fontCache[i].lru;
2249 fontCache[i].count = 0;
2250 return (fontCache + i);
2253 static int XFONT_ReleaseCacheEntry(fontObject* pfo)
2255 UINT32 u = (UINT32)(pfo - fontCache);
2257 if( u < fontCacheSize ) return (--fontCache[u].count);
2258 return -1;
2261 /**********************************************************************
2262 * XFONT_SetX11Trans
2264 static BOOL32 XFONT_SetX11Trans( fontObject *pfo )
2266 char *fontName;
2267 Atom nameAtom;
2268 int i;
2269 char *cp, *start;
2271 TSXGetFontProperty( pfo->fs, XA_FONT, &nameAtom );
2272 fontName = TSXGetAtomName( display, nameAtom );
2273 for(i = 0, cp = fontName; i < 7; i++) {
2274 cp = strchr(cp, '-');
2275 cp++;
2277 if(*cp != '[') {
2278 TSXFree(fontName);
2279 return FALSE;
2281 start = cp;
2282 while((cp = strchr(cp, '~')))
2283 *cp = '-';
2285 #define PX pfo->lpX11Trans
2287 sscanf(start, "[%f%f%f%f]", &PX->a, &PX->b, &PX->c, &PX->d);
2288 TSXFree(fontName);
2290 TSXGetFontProperty( pfo->fs, RAW_ASCENT, &PX->RAW_ASCENT );
2291 TSXGetFontProperty( pfo->fs, RAW_DESCENT, &PX->RAW_DESCENT );
2293 PX->pixelsize = hypot(PX->a, PX->b);
2294 PX->ascent = PX->pixelsize / 1000.0 * PX->RAW_ASCENT;
2295 PX->descent = PX->pixelsize / 1000.0 * PX->RAW_DESCENT;
2297 TRACE(font, "[%f %f %f %f] RA = %ld RD = %ld\n", pfo->lpX11Trans->a,
2298 pfo->lpX11Trans->b, pfo->lpX11Trans->c, pfo->lpX11Trans->d,
2299 pfo->lpX11Trans->RAW_ASCENT, pfo->lpX11Trans->RAW_DESCENT);
2301 #undef PX
2302 return TRUE;
2305 /***********************************************************************
2306 * X Device Font Objects
2308 static X_PHYSFONT XFONT_RealizeFont( LPLOGFONT16 plf )
2310 UINT16 checksum;
2311 fontObject* pfo = XFONT_LookupCachedFont( plf, &checksum );
2313 if( !pfo )
2315 fontMatch fm = { NULL, NULL, 0, 0, plf};
2316 INT32 i, index;
2318 if( XTextCaps & TC_SF_X_YINDEP ) fm.flags = FO_MATCH_XYINDEP;
2320 /* allocate new font cache entry */
2322 if( (pfo = XFONT_GetCacheEntry()) )
2324 LPSTR lpLFD = HeapAlloc( GetProcessHeap(), 0, MAX_LFD_LENGTH );
2326 if( lpLFD ) /* initialize entry and load font */
2328 UINT32 uRelaxLevel = 0;
2330 TRACE(font,"(%u) '%s' h=%i weight=%i %s\n",
2331 plf->lfCharSet, plf->lfFaceName, plf->lfHeight,
2332 plf->lfWeight, (plf->lfItalic) ? "Italic" : "" );
2334 if(abs(plf->lfHeight) > MAX_FONT_SIZE) {
2335 ERR(font,
2336 "plf->lfHeight = %d, this is probably not right. Setting to 100\n",
2337 plf->lfHeight);
2338 plf->lfHeight = 100;
2341 XFONT_MatchDeviceFont( fontList, &fm );
2343 pfo->fr = fm.pfr;
2344 pfo->fi = fm.pfi;
2345 pfo->fo_flags = fm.flags & ~FO_MATCH_MASK;
2347 memcpy( &pfo->lf, plf, sizeof(LOGFONT16) );
2348 pfo->lfchecksum = checksum;
2352 LFD_ComposeLFD( pfo, fm.height, lpLFD, uRelaxLevel++ );
2353 if( (pfo->fs = TSXLoadQueryFont( display, lpLFD )) ) break;
2354 } while( uRelaxLevel );
2357 if(pfo->lf.lfEscapement != 0) {
2358 pfo->lpX11Trans = HeapAlloc(SystemHeap, 0,
2359 sizeof(XFONTTRANS));
2360 if(!XFONT_SetX11Trans( pfo )) {
2361 HeapFree(SystemHeap, 0, pfo->lpX11Trans);
2362 pfo->lpX11Trans = NULL;
2366 if( XFONT_GetLeading( &pfo->fi->df, pfo->fs, &i, NULL,
2367 pfo->lpX11Trans ) )
2369 if(!pfo->lpX11Trans)
2370 pfo->foAvgCharWidth =
2371 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].width;
2372 else
2373 pfo->foAvgCharWidth =
2374 (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].attributes
2375 * pfo->lpX11Trans->pixelsize / 1000.0;
2376 else
2377 pfo->foAvgCharWidth = (INT16)XFONT_GetAvgCharWidth(
2378 &pfo->fi->df, pfo->fs, pfo->lpX11Trans );
2379 pfo->foMaxCharWidth = (INT16)XFONT_GetMaxCharWidth(pfo);
2380 pfo->foInternalLeading = (INT16)i;
2382 /* FIXME: If we've got a soft font or
2383 * there are FO_SYNTH_... flags for the
2384 * non PROOF_QUALITY request, the engine
2385 * should rasterize characters into mono
2386 * pixmaps and store them in the pfo->lpPixmap
2387 * array (pfo->fs should be updated as well).
2388 * X11DRV_ExtTextOut() must be heavily modified
2389 * to support pixmap blitting and FO_SYNTH_...
2390 * styles.
2393 pfo->lpXForm = NULL;
2394 pfo->lpPixmap = NULL;
2396 HeapFree( GetProcessHeap(), 0, lpLFD );
2398 else /* attach back to the free list */
2400 pfo->count = -1;
2401 pfo->lru = fontLF;
2402 fontLF = (pfo - fontCache);
2403 pfo = NULL;
2407 if( !pfo ) /* couldn't get a new entry, get one of the cached fonts */
2409 UINT32 current_score, score = (UINT32)(-1);
2411 i = index = fontMRU;
2412 fm.flags |= FO_MATCH_PAF;
2415 pfo = fontCache + i;
2416 fm.pfr = pfo->fr; fm.pfi = pfo->fi;
2418 current_score = XFONT_Match( &fm );
2419 if( current_score < score ) index = i;
2421 i = pfo->lru;
2422 } while( i >= 0 );
2423 pfo = fontCache + index;
2424 pfo->count++;
2425 return (X_PHYSFONT)(X_PFONT_MAGIC | index);
2429 /* attach at the head of the lru list */
2431 pfo->count++;
2432 pfo->lru = fontMRU;
2433 fontMRU = (pfo - fontCache);
2435 TRACE(font,"physfont %i\n", fontMRU);
2437 return (X_PHYSFONT)(X_PFONT_MAGIC | fontMRU);
2440 /***********************************************************************
2441 * XFONT_GetFontObject
2443 fontObject* XFONT_GetFontObject( X_PHYSFONT pFont )
2445 if( CHECK_PFONT(pFont) ) return __PFONT(pFont);
2446 return NULL;
2449 /***********************************************************************
2450 * XFONT_GetFontStruct
2452 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
2454 if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
2455 return NULL;
2458 /***********************************************************************
2459 * XFONT_GetFontInfo
2461 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
2463 if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
2464 return NULL;
2469 /* X11DRV Interface ****************************************************
2471 * Exposed via the dc->funcs dispatch table. *
2473 ***********************************************************************/
2474 /***********************************************************************
2475 * X11DRV_FONT_SelectObject
2477 HFONT32 X11DRV_FONT_SelectObject( DC* dc, HFONT32 hfont, FONTOBJ* font )
2479 HFONT32 hPrevFont = 0;
2480 LOGFONT16 lf;
2481 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2483 if( CHECK_PFONT(physDev->font) )
2484 XFONT_ReleaseCacheEntry( __PFONT(physDev->font) );
2486 /* FIXME: do we need to pass anything back from here? */
2487 memcpy(&lf,&font->logfont,sizeof(lf));
2488 lf.lfWidth = font->logfont.lfWidth * dc->vportExtX/dc->wndExtX;
2489 lf.lfHeight = font->logfont.lfHeight* dc->vportExtY/dc->wndExtY;
2491 physDev->font = XFONT_RealizeFont( &lf );
2492 hPrevFont = dc->w.hFont;
2493 dc->w.hFont = hfont;
2495 return hPrevFont;
2499 /***********************************************************************
2501 * X11DRV_EnumDeviceFonts
2503 BOOL32 X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf,
2504 DEVICEFONTENUMPROC proc, LPARAM lp )
2506 ENUMLOGFONTEX16 lf;
2507 NEWTEXTMETRIC16 tm;
2508 fontResource* pfr = fontList;
2509 BOOL32 b, bRet = 0;
2511 if( plf->lfFaceName[0] )
2513 pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
2514 if( pfr )
2516 fontInfo* pfi;
2517 for( pfi = pfr->fi; pfi; pfi = pfi->next )
2518 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2519 XFONT_GetFontMetric( pfi, &lf, &tm ), lp )) )
2520 bRet = b;
2521 else break;
2524 else
2525 for( ; pfr ; pfr = pfr->next )
2526 if(pfr->fi)
2528 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm,
2529 XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
2530 bRet = b;
2531 else break;
2534 return bRet;
2538 /***********************************************************************
2539 * X11DRV_GetTextExtentPoint
2541 BOOL32 X11DRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT32 count,
2542 LPSIZE32 size )
2544 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2545 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2546 if( pfo ) {
2547 if( !pfo->lpX11Trans ) {
2548 int dir, ascent, descent;
2549 XCharStruct info;
2551 TSXTextExtents( pfo->fs, str, count, &dir, &ascent, &descent, &info );
2552 size->cx = abs((info.width + dc->w.breakRem + count *
2553 dc->w.charExtra) * dc->wndExtX / dc->vportExtX);
2554 size->cy = abs((pfo->fs->ascent + pfo->fs->descent) *
2555 dc->wndExtY / dc->vportExtY);
2556 } else {
2558 INT32 i;
2559 float x = 0.0, y = 0.0;
2560 for(i = 0; i < count; i++) {
2561 x += pfo->fs->per_char ?
2562 pfo->fs->per_char[str[i] - pfo->fs->min_char_or_byte2].attributes :
2563 pfo->fs->min_bounds.attributes;
2565 y = pfo->lpX11Trans->RAW_ASCENT + pfo->lpX11Trans->RAW_DESCENT;
2566 TRACE(font, "x = %f y = %f\n", x, y);
2567 x *= pfo->lpX11Trans->pixelsize / 1000.0;
2568 y *= pfo->lpX11Trans->pixelsize / 1000.0;
2569 size->cx = fabsf((x + dc->w.breakRem + count * dc->w.charExtra) *
2570 dc->wndExtX / dc->vportExtX);
2571 size->cy = fabsf(y * dc->wndExtY / dc->vportExtY);
2573 return TRUE;
2575 return FALSE;
2579 /***********************************************************************
2580 * X11DRV_GetTextMetrics
2582 BOOL32 X11DRV_GetTextMetrics(DC *dc, TEXTMETRIC32A *metrics)
2584 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2586 if( CHECK_PFONT(physDev->font) )
2588 fontObject* pfo = __PFONT(physDev->font);
2589 XFONT_GetTextMetric( pfo, metrics );
2591 return TRUE;
2593 return FALSE;
2597 /***********************************************************************
2598 * X11DRV_GetCharWidth
2600 BOOL32 X11DRV_GetCharWidth( DC *dc, UINT32 firstChar, UINT32 lastChar,
2601 LPINT32 buffer )
2603 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2604 fontObject* pfo = XFONT_GetFontObject( physDev->font );
2606 if( pfo )
2608 int i;
2610 if (pfo->fs->per_char == NULL)
2611 for (i = firstChar; i <= lastChar; i++)
2612 if(pfo->lpX11Trans)
2613 *buffer++ = pfo->fs->min_bounds.attributes *
2614 pfo->lpX11Trans->pixelsize / 1000.0;
2615 else
2616 *buffer++ = pfo->fs->min_bounds.width;
2617 else
2619 XCharStruct *cs, *def;
2620 static XCharStruct __null_char = { 0, 0, 0, 0, 0, 0 };
2622 CI_GET_CHAR_INFO(pfo->fs, pfo->fs->default_char, &__null_char,
2623 def);
2625 for (i = firstChar; i <= lastChar; i++)
2627 if (i >= pfo->fs->min_char_or_byte2 &&
2628 i <= pfo->fs->max_char_or_byte2)
2630 cs = &pfo->fs->per_char[(i - pfo->fs->min_char_or_byte2)];
2631 if (CI_NONEXISTCHAR(cs)) cs = def;
2632 } else cs = def;
2633 if(pfo->lpX11Trans)
2634 *buffer++ = MAX(cs->attributes, 0) *
2635 pfo->lpX11Trans->pixelsize / 1000.0;
2636 else
2637 *buffer++ = MAX(cs->width, 0 );
2641 return TRUE;
2643 return FALSE;
2646 /***********************************************************************
2648 * Font Resource API *
2650 ***********************************************************************/
2651 /***********************************************************************
2652 * AddFontResource16 (GDI.119)
2654 * Can be either .FON, or .FNT, or .TTF, or .FOT font file.
2656 * FIXME: Load header and find the best-matching font in the fontList;
2657 * fixup dfPoints if all metrics are identical, otherwise create
2658 * new fontAlias. When soft font support is ready this will
2659 * simply create a new fontResource ('filename' will go into
2660 * the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE
2661 * flag set.
2663 INT16 WINAPI AddFontResource16( LPCSTR filename )
2665 return AddFontResource32A( filename );
2669 /***********************************************************************
2670 * AddFontResource32A (GDI32.2)
2672 INT32 WINAPI AddFontResource32A( LPCSTR str )
2674 FIXME(font, "(%s): stub\n", debugres_a(str));
2675 return 1;
2679 /***********************************************************************
2680 * AddFontResource32W (GDI32.4)
2682 INT32 WINAPI AddFontResource32W( LPCWSTR str )
2684 FIXME(font, "(%s): stub\n", debugres_w(str) );
2685 return 1;
2688 /***********************************************************************
2689 * RemoveFontResource16 (GDI.136)
2691 BOOL16 WINAPI RemoveFontResource16( SEGPTR str )
2693 FIXME(font, "(%s): stub\n", debugres_a(PTR_SEG_TO_LIN(str)));
2694 return TRUE;
2698 /***********************************************************************
2699 * RemoveFontResource32A (GDI32.284)
2701 BOOL32 WINAPI RemoveFontResource32A( LPCSTR str )
2703 FIXME(font, "(%s): stub\n", debugres_a(str));
2704 return TRUE;
2708 /***********************************************************************
2709 * RemoveFontResource32W (GDI32.286)
2711 BOOL32 WINAPI RemoveFontResource32W( LPCWSTR str )
2713 FIXME(font, "(%s): stub\n", debugres_w(str) );
2714 return TRUE;