Fixed error handling in DGA_IDirectDraw2Impl_GetCaps().
[wine] / graphics / x11drv / xfont.c
1 /*
2  * X11 physical font objects
3  *
4  * Copyright 1997 Alex Korobka
5  *
6  * TODO: Mapping algorithm tweaks, FO_SYNTH_... flags (ExtTextOut() will
7  *       have to be changed for that), dynamic font loading (FreeType).
8  */
9
10 #include "config.h"
11
12 #ifndef X_DISPLAY_MISSING
13 #include <X11/Xatom.h>
14 #include "ts_xlib.h"
15 #include "x11font.h"
16 #endif /* !defined(X_DISPLAY_MISSING) */
17
18 #include <ctype.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <math.h>
27 #include <assert.h>
28 #include "winuser.h"
29 #include "heap.h"
30 #include "options.h"
31 #include "font.h"
32 #include "debug.h"
33 #include "ldt.h"
34
35 DEFAULT_DEBUG_CHANNEL(font)
36
37 #ifndef X_DISPLAY_MISSING
38
39 #define X_PFONT_MAGIC           (0xFADE0000)
40 #define X_FMC_MAGIC             (0x0000CAFE)
41
42 #define MAX_FONT_FAMILIES       128
43 #define MAX_LFD_LENGTH          256
44
45 #define MAX_FONT_SIZE           1000    /* Max size in pixels */
46
47 #define REMOVE_SUBSETS          1
48 #define UNMARK_SUBSETS          0
49
50 #define DEF_SCALABLE_HEIGHT     24
51 #define DEF_SCALABLE_DP         240
52
53 #define FF_FAMILY       (FF_MODERN | FF_SWISS | FF_ROMAN | FF_DECORATIVE | FF_SCRIPT)
54
55 typedef struct __fontAlias
56 {
57   LPSTR                 faTypeFace;
58   LPSTR                 faAlias;
59   struct __fontAlias*   next;
60 } fontAlias;
61
62 typedef struct
63 {
64   LPSTR                 fatResource;
65   LPSTR                 fatAlias;
66 } aliasTemplate;
67
68 /* Font alias table - these 2 aliases are always present */
69 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
70
71 static fontAlias __aliasTable[2] = { 
72                         { NULL, "Helv", &__aliasTable[1] },
73                         { NULL, "Tms Rmn", NULL } 
74                         };
75
76 static fontAlias *aliasTable = __aliasTable;
77
78 /* Optional built-in aliases, they are installed only when X
79  * cannot supply us with original MS fonts */
80 /* CHANGING THE FIRST TWO WILL BREAK XFONT_BuildDefaultAliases! */
81
82 static int           faTemplateNum = 4;
83 static aliasTemplate faTemplate[4] = {
84                           { NULL, "MS Sans Serif" },
85                           { NULL, "MS Serif" },
86                           { "-adobe-times-", "Times New Roman" },
87                           { "-adobe-helvetica-", "Arial" }
88                           };
89
90 UINT16                  XTextCaps = TC_OP_CHARACTER | TC_OP_STROKE |
91 TC_CP_STROKE | TC_CR_ANY |
92                                     TC_SA_DOUBLE | TC_SA_INTEGER | TC_SA_CONTIN |
93                                     TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
94
95                         /* X11R6 adds TC_SF_X_YINDEP, maybe more... */
96
97 static const char*      INIWinePrefix = "/.wine";
98 static const char*      INIFontMetrics = "/.cachedmetrics.";
99 static const char*      INIFontSection = "fonts";
100 static const char*      INIAliasSection = "Alias";
101 static const char*      INIIgnoreSection = "Ignore";
102 static const char*      INIDefault = "Default";
103 static const char*      INIDefaultFixed = "DefaultFixed";
104 static const char*      INIResolution = "Resolution";
105 static const char*      INIGlobalMetrics = "FontMetrics";
106 static const char*      INIDefaultSerif = "DefaultSerif";
107 static const char*      INIDefaultSansSerif = "DefaultSansSerif";
108
109 static const char*      LFDSeparator = "*-";
110
111 /* suffix tables, must be less than 254 entries long */
112
113 static LPSTR    suffx_iso[] = { "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", 
114                                   "-9", "-10", "-11", "-12", "-13", "-14", "-15", NULL };
115 static LPSTR    suffx_iso646[] = { "-irv", NULL };
116 static LPSTR    suffx_microsoft[] = { "-cp1252", "-cp1251", "-cp1250", "-cp1253", "-cp1254", "-cp1255",
117                                       "-cp1256", "-cp1257", "-fontspecific", "-symbol", NULL };
118 static LPSTR    suffx_viscii[] = { "-1", NULL };
119 static LPSTR    suffx_ansi[] = { "-0", NULL };
120 static LPSTR    suffx_koi8[] = { "-ru", "-r", NULL };
121 static LPSTR    suffx_null[] = { NULL };
122
123 /* charset mapping tables, have to have the same number of entries as corresponding suffix tables */
124
125 static BYTE     chset_iso8859[] = { ANSI_CHARSET, EE_CHARSET, ISO3_CHARSET, ISO4_CHARSET, RUSSIAN_CHARSET,
126                                     ARABIC_CHARSET, GREEK_CHARSET, HEBREW_CHARSET, TURKISH_CHARSET, BALTIC_CHARSET,
127                                     THAI_CHARSET, SYMBOL_CHARSET, SYMBOL_CHARSET, SYMBOL_CHARSET, ANSI_CHARSET, 
128                                     SYMBOL_CHARSET };
129 static BYTE     chset_iso646[] = { ANSI_CHARSET, SYMBOL_CHARSET };
130 static BYTE     chset_microsoft[] = { ANSI_CHARSET, RUSSIAN_CHARSET, EE_CHARSET, GREEK_CHARSET, TURKISH_CHARSET,
131                                       HEBREW_CHARSET, ARABIC_CHARSET, BALTIC_CHARSET, SYMBOL_CHARSET, SYMBOL_CHARSET, 
132                                       SYMBOL_CHARSET };
133 static BYTE     chset_ansi[] = { ANSI_CHARSET, ANSI_CHARSET };
134 static BYTE     chset_koi8[] = { KOI8_CHARSET, KOI8_CHARSET, KOI8_CHARSET };
135 static BYTE     chset_tcvn[] = { TCVN_CHARSET, TCVN_CHARSET };
136 static BYTE     chset_tis620[] = { THAI_CHARSET, THAI_CHARSET };
137 static BYTE     chset_fontspecific[] = { SYMBOL_CHARSET };
138 static BYTE     chset_viscii[] = { VISCII_CHARSET, VISCII_CHARSET };
139
140 typedef struct __fet
141 {
142   LPSTR         prefix;
143   LPSTR         (*psuffix)[];
144   BYTE          (*pcharset)[];
145   struct __fet* next;
146 } fontEncodingTemplate;
147
148 /* Note: we can attach additional encoding mappings to the end
149  *       of this table at runtime.
150  */
151
152 static fontEncodingTemplate __fETTable[10] = {
153                         { "iso8859", &suffx_iso, &chset_iso8859, &__fETTable[1] },
154                         { "iso646.1991", &suffx_iso646, &chset_iso646,  &__fETTable[2] },
155                         { "microsoft",  &suffx_microsoft, &chset_microsoft, &__fETTable[3] },
156                         { "ansi", &suffx_ansi, &chset_ansi, &__fETTable[4] },
157                         { "ascii", &suffx_ansi, &chset_ansi, &__fETTable[5] },
158                         { "fontspecific", &suffx_null, &chset_fontspecific, &__fETTable[6] },
159                         { "koi8", &suffx_koi8, &chset_koi8, &__fETTable[7] },
160                         { "tcvn", &suffx_ansi, &chset_tcvn, &__fETTable[8] },
161                         { "tis620.2533", &suffx_ansi, &chset_tis620, &__fETTable[9] },
162                         { "viscii1.1", &suffx_viscii, &chset_viscii, NULL }
163                 };
164 static fontEncodingTemplate* fETTable = __fETTable;
165
166 static unsigned         DefResolution = 0;
167
168 static CRITICAL_SECTION crtsc_fonts_X11;
169
170 static fontResource*    fontList = NULL;
171 static fontObject*      fontCache = NULL;               /* array */
172 static int              fontCacheSize = FONTCACHE;
173 static int              fontLF = -1, fontMRU = -1;      /* last free, most recently used */
174
175 #define __PFONT(pFont)     ( fontCache + ((UINT)(pFont) & 0x0000FFFF) )
176 #define CHECK_PFONT(pFont) ( (((UINT)(pFont) & 0xFFFF0000) == X_PFONT_MAGIC) &&\
177                              (((UINT)(pFont) & 0x0000FFFF) < fontCacheSize) )
178
179 static INT XFONT_IsSubset(fontInfo*, fontInfo*);
180 static void  XFONT_CheckFIList(fontResource*, fontInfo*, int subset_action);
181 static void  XFONT_GrowFreeList(int start, int end);
182 static void XFONT_RemoveFontResource(fontResource** ppfr);
183
184
185 static Atom RAW_ASCENT;
186 static Atom RAW_DESCENT;
187
188 /***********************************************************************
189  *           Helper macros from X distribution
190  */
191
192 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
193                              (((cs)->rbearing|(cs)->lbearing| \
194                                (cs)->ascent|(cs)->descent) == 0))
195
196 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
197 { \
198     cs = def; \
199     if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
200         if (fs->per_char == NULL) { \
201             cs = &fs->min_bounds; \
202         } else { \
203             cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
204             if (CI_NONEXISTCHAR(cs)) cs = def; \
205         } \
206     } \
207 }
208
209 #define CI_GET_DEFAULT_INFO(fs,cs) \
210   CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
211
212 /***********************************************************************
213  *           Checksums
214  */
215 static UINT16   __lfCheckSum( LPLOGFONT16 plf )
216 {
217     CHAR        font[LF_FACESIZE];
218     UINT16      checksum = 0;
219     UINT16      i;
220
221 #define ptr ((UINT16*)plf)
222    for( i = 0; i < 9; i++ ) checksum ^= *ptr++;
223 #undef ptr
224    i = 0;
225 #define ptr ((CHAR*)plf)
226    do { font[i++] = tolower(*ptr++); } while (( i < LF_FACESIZE) && (*ptr) && (*ptr!=' '));
227    for( ptr = font, i >>= 1; i > 0; i-- ) 
228 #undef ptr
229 #define ptr ((UINT16*)plf)
230         checksum ^= *ptr++;
231 #undef ptr
232    return checksum;
233 }
234
235 static UINT16   __genericCheckSum( const void *ptr, int size )
236 {
237    unsigned int checksum = 0;
238    const char *p = (const char *)ptr;
239    while (size-- > 0)
240      checksum ^= (checksum << 3) + (checksum >> 29) + *p++;
241
242    return checksum & 0xffff;
243 }
244
245 /*************************************************************************
246  *           LFD parse/compose routines
247  */
248 static char* LFD_Advance(LPSTR lpFont, UINT16 uParmsNo)
249 {
250   int   j = 0;
251   char* lpch = lpFont;
252
253   for( ; j < uParmsNo && *lpch; lpch++ ) if( *lpch == LFDSeparator[1] ) j++;
254   return lpch;
255 }
256
257 static void LFD_GetWeight( fontInfo* fi, LPSTR lpStr, int j)
258 {
259   if( j == 1 && *lpStr == '0' )
260       fi->fi_flags |= FI_POLYWEIGHT;
261   else if( j == 4 )
262        {
263          if( !strncasecmp( "bold", lpStr, 4) )
264            fi->df.dfWeight = FW_BOLD; 
265          else if( !strncasecmp( "demi", lpStr, 4) )
266          {
267            fi->fi_flags |= FI_FW_DEMI;
268            fi->df.dfWeight = FW_DEMIBOLD;
269          }
270          else if( !strncasecmp( "book", lpStr, 4) )
271          {
272            fi->fi_flags |= FI_FW_BOOK;
273            fi->df.dfWeight = FW_REGULAR;
274          }
275        }
276   else if( j == 5 )
277        {
278          if( !strncasecmp( "light", lpStr, 5) )
279            fi->df.dfWeight = FW_LIGHT;
280          else if( !strncasecmp( "black", lpStr, 5) )
281            fi->df.dfWeight = FW_BLACK;
282        }
283   else if( j == 6 && !strncasecmp( "medium", lpStr, 6) )
284       fi->df.dfWeight = FW_REGULAR; 
285   else if( j == 8 && !strncasecmp( "demibold", lpStr, 8) )
286       fi->df.dfWeight = FW_DEMIBOLD; 
287   else
288       fi->df.dfWeight = FW_DONTCARE; /* FIXME: try to get something
289                                       * from the weight property */
290 }
291
292 static int LFD_GetSlant( fontInfo* fi, LPSTR lpStr, int l)
293 {
294     if( l == 1 )
295     {
296         switch( tolower( *lpStr ) )
297         {
298             case '0':  fi->fi_flags |= FI_POLYSLANT;    /* haven't seen this one yet */
299             default:
300             case 'r':  fi->df.dfItalic = 0;
301                        break;
302             case 'o':
303                        fi->fi_flags |= FI_OBLIQUE;
304             case 'i':  fi->df.dfItalic = 1;
305                        break;
306         }
307         return 0;
308     }
309     return 1;
310 }
311
312 /*************************************************************************
313  *           LFD_InitFontInfo
314  *
315  * INIT ONLY
316  *
317  * Fill in some fields in the fontInfo struct.
318  */
319 static int LFD_InitFontInfo( fontInfo* fi, LPSTR lpstr )
320 {
321    LPSTR        lpch;
322    int          i, j, dec_style_check, scalability;
323    UINT16       tmp[3];
324    fontEncodingTemplate* boba;
325
326    memset(fi, 0, sizeof(fontInfo) );
327
328 /* weight name - */
329    lpch = LFD_Advance( lpstr, 1);
330    if( !*lpch ) return FALSE;
331    j = lpch - lpstr - 1;
332    LFD_GetWeight( fi, lpstr, j );
333
334 /* slant - */
335    lpch = LFD_Advance( lpstr = lpch, 1);
336    if( !*lpch ) return FALSE;
337    j = lpch - lpstr - 1;
338    dec_style_check = LFD_GetSlant( fi, lpstr, j );
339
340 /* width name - */
341    lpch = LFD_Advance( lpstr = lpch, 1);
342    if( !*lpch ) return FALSE;
343    if( strncasecmp( "normal", lpstr, 6) )       /* XXX 'narrow', 'condensed', etc... */
344        dec_style_check = TRUE;
345    else
346        fi->fi_flags |= FI_NORMAL;
347
348 /* style - */
349    lpch = LFD_Advance( lpstr = lpch, 1);
350    if( !*lpch ) return FALSE;
351    j = lpch - lpstr - 1;
352    if( j > 3 )  /* find out is there "sans" or "script" */
353    {
354         j = 0;
355         *(lpch - 1) = '\0';
356
357         if( strstr(lpstr, "sans") ) 
358         { 
359             fi->df.dfPitchAndFamily |= FF_SWISS; 
360             j = 1; 
361         }
362         if( strstr(lpstr, "script") ) 
363         { 
364             fi->df.dfPitchAndFamily |= FF_SCRIPT; 
365             j = 1; 
366         }
367         if( !j && dec_style_check ) 
368             fi->df.dfPitchAndFamily |= FF_DECORATIVE;
369         *(lpch - 1) = LFDSeparator[1];
370    }
371
372 /* pixel height, decipoint height, and res_x */
373
374    for( i = scalability = 0; i < 3; i++ )
375    {
376      lpch = LFD_Advance( lpstr = lpch, 1);
377      if( !*lpch ) return FALSE;
378      if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
379
380     *(lpch - 1) = '\0';
381      if( !(tmp[i] = atoi(lpstr)) ) scalability++;
382     *(lpch - 1) = LFDSeparator[1];
383    }
384    if( scalability == 3 )       /* Type1 */
385    {
386      fi->fi_flags |= FI_SCALABLE;
387      fi->lfd_height = DEF_SCALABLE_HEIGHT; fi->lfd_decipoints = DEF_SCALABLE_DP;
388      fi->lfd_resolution = DefResolution;
389    }
390    else if( scalability == 0 )  /* Bitmap */
391    {
392      fi->lfd_height = tmp[0]; fi->lfd_decipoints = tmp[1]; 
393      fi->lfd_resolution = tmp[2];
394    }
395    else return FALSE; /* #$%^!!! X11R6 mutant garbage */
396
397 /* res_y - skip, spacing - */
398    lpstr = LFD_Advance( lpch, 1);
399    switch( *lpstr )
400    {
401      case '\0': return FALSE;
402
403      case 'p': fi->fi_flags |= FI_VARIABLEPITCH;
404                break;
405      case 'c': fi->df.dfPitchAndFamily |= FF_MODERN;
406                fi->fi_flags |= FI_FIXEDEX;
407                /* fall through */
408      case 'm': fi->fi_flags |= FI_FIXEDPITCH;
409                break;
410      default:
411                fi->df.dfPitchAndFamily |= DEFAULT_PITCH | FF_DONTCARE;
412    }
413    lpstr = LFD_Advance(lpstr, 1);
414    if( !*lpstr ) return FALSE;
415
416 /* average width - */
417    lpch = LFD_Advance( lpstr, 1);
418    if( !*lpch ) return FALSE;
419    if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
420   *(lpch - 1) = '\0'; 
421    if( !(fi->lfd_width = atoi(lpstr)) && !scalability ) return FALSE;
422   *(lpch - 1) = LFDSeparator[1];
423
424 /* charset registry, charset encoding - */
425    if( strstr(lpch, "jisx") || 
426        strstr(lpch, "ksc") || 
427        strstr(lpch, "gb2312") ||
428        strstr(lpch, "big5") ||
429        strstr(lpch, "unicode") ) return FALSE;  /* 2-byte stuff */
430
431    fi->df.dfCharSet = ANSI_CHARSET;
432
433    for( i = 0, boba = fETTable; boba; boba = boba->next, i++ )
434    {
435         tmp[0] = strlen( boba->prefix );
436         if( !strncasecmp( lpch, boba->prefix, tmp[0] ) )
437         {
438             if( lpch[tmp[0]] == '-' )
439             {
440                 lpstr = lpch + tmp[0];
441                 for( j = 0; (*(boba->psuffix))[j]; j++ )
442                 {
443                      tmp[1] = strlen( (*(boba->psuffix))[j] );
444                      if( !strncasecmp( lpstr, (*(boba->psuffix))[j], tmp[1] ) )
445                      {
446                          fi->df.dfCharSet = (*(boba->pcharset))[j];
447                          goto done;
448                      }
449                 }
450                 /* Note : LFD_ComposeLFD will produce 'prefix-*' encoding     *
451                  *                      if (*(boba->psuffix))[j] is NULL here */
452             }
453             else
454             {
455                 for( j = 0; (*(boba->psuffix))[j] ; j++ );
456                 fi->df.dfCharSet = (*(boba->pcharset))[j];
457                 j = lpch[tmp[0]] ? 254 : 255;
458             }
459         }
460    }
461 done:
462    if( !boba ) return FALSE;
463
464    /* i - index into fETTable
465     * j - index into suffix array for fETTable[i]
466     *     except:
467     *     254 - weird suffix (i.e. no '-' right after prefix )
468     *     255 - no suffix at all.
469     */
470
471    fi->fi_encoding = 256 * (UINT16)i + (UINT16)j;
472
473    return TRUE;                                 
474 }
475
476
477 /*************************************************************************
478  *           LFD_ComposeLFD
479  *
480  * Note: uRelax is a treatment not a cure. Font mapping algorithm
481  *       should be bulletproof enough to allow us to avoid hacks like
482  *       if( uRelax == 200 ) even despite LFD being so braindead.
483  */
484 static BOOL  LFD_ComposeLFD( fontObject* fo, 
485                                INT height, LPSTR lpLFD, UINT uRelax )
486 {
487    fontEncodingTemplate* boba;
488    int          i, h, w, ch, point = 0;
489    char*        lpch; 
490    char         lpEncoding[64];
491    char         h_string[64], point_string[64];
492
493    *(lpLFD+MAX_LFD_LENGTH-1)=0;
494    lstrcpyA( lpLFD, fo->fr->resource );
495
496 /* add weight */
497    switch( fo->fi->df.dfWeight )
498    {
499         case FW_BOLD:
500                 strcat( lpLFD, "bold" ); break;
501         case FW_REGULAR:
502                 if( fo->fi->fi_flags & FI_FW_BOOK )
503                     strcat( lpLFD, "book" );
504                 else
505                     strcat( lpLFD, "medium" );
506                 break;
507         case FW_DEMIBOLD:
508                 strcat( lpLFD, "demi" );
509                 if( !( fo->fi->fi_flags & FI_FW_DEMI) )
510                      strcat ( lpLFD, "bold" );
511                 break;
512         case FW_BLACK:
513                 strcat( lpLFD, "black" ); break;
514         case FW_LIGHT:
515                 strcat( lpLFD, "light" ); break;
516         default:
517                 strcat( lpLFD, "*" );
518    }
519
520 /* add slant */
521    if( fo->fi->df.dfItalic )
522        if( fo->fi->fi_flags & FI_OBLIQUE )
523            strcat( lpLFD, "-o" );
524        else
525            strcat( lpLFD, "-i" );
526    else 
527        strcat( lpLFD, (uRelax < 2) ? "-r" : "-*" );
528
529 /* add width style and skip serifs */
530    if( fo->fi->fi_flags & FI_NORMAL )
531        strcat( lpLFD, "-normal-*-");
532    else
533        strcat( lpLFD, "-*-*-" );
534
535 /* add pixelheight, pointheight, and resolution 
536  *
537  * FIXME: fill in lpXForm and lpPixmap for rotated fonts
538  */
539    if( fo->fo_flags & FO_SYNTH_HEIGHT ) h = fo->fi->lfd_height;
540    else h = (fo->fi->lfd_height * height) / fo->fi->df.dfPixHeight;
541
542    if( XTextCaps & TC_SF_X_YINDEP ) 
543    {
544         if( fo->lf.lfWidth && !(fo->fo_flags & FO_SYNTH_WIDTH) )
545             point = (fo->fi->lfd_decipoints * fo->lf.lfWidth) / fo->fi->df.dfAvgWidth;
546         else 
547         if( fo->fi->fi_flags & FI_SCALABLE ) /* adjust h/w ratio */
548             point = h * 72 * 10 / fo->fi->lfd_resolution;
549    }
550
551    /* handle rotated fonts */
552    if (fo->lf.lfEscapement) {
553      /* escapement is in tenths of degrees, theta is in radians */
554      double theta = M_PI*fo->lf.lfEscapement/1800.;  
555      double h_matrix[4];
556      double point_matrix[4];
557      char *s;
558      h_matrix[0] = h*cos(theta);
559      h_matrix[1] = h*sin(theta);
560      h_matrix[2] = -h*sin(theta);
561      h_matrix[3] = h*cos(theta);
562      point_matrix[0] = point*cos(theta);
563      point_matrix[1] = point*sin(theta);
564      point_matrix[2] = -point*sin(theta);
565      point_matrix[3] = point*cos(theta);
566      sprintf(h_string, "[%+f%+f%+f%+f]", h_matrix[0], h_matrix[1], h_matrix[2], h_matrix[3]);
567      sprintf(point_string, "[%+f%+f%+f%+f]", point_matrix[0], point_matrix[1], point_matrix[2], point_matrix[3]);
568      while ((s = strchr(h_string, '-'))) *s='~';
569      while ((s = strchr(point_string, '-'))) *s='~';
570    } else {
571      sprintf(h_string, "%d", h);
572      sprintf(point_string, "%d", point);
573    }
574
575
576 /* spacing and width */
577
578    if( fo->fi->fi_flags & FI_FIXEDPITCH ) 
579        w = ( fo->fi->fi_flags & FI_FIXEDEX ) ? 'c' : 'm';
580    else 
581        w = ( fo->fi->fi_flags & FI_VARIABLEPITCH ) ? 'p' : LFDSeparator[0]; 
582
583 /* encoding */
584
585    i = fo->fi->fi_encoding >> 8;
586    for( boba = fETTable; i; i--, boba = boba->next );
587
588    strcpy( lpEncoding, boba->prefix );
589
590    i = fo->fi->fi_encoding & 255;
591    switch( i )
592    {
593         case 254: strcat( lpEncoding, "*" );
594                   break;
595         default:
596                   
597                   if( (*(boba->psuffix))[i] )
598                       strcat( lpEncoding, (*(boba->psuffix))[i] );
599                   else
600                       strcat( lpEncoding, "-*" );
601                   /* fall through */
602
603         case 255: /* no suffix */
604                   break;
605    }
606
607    lpch = lpLFD + lstrlenA(lpLFD);
608    ch = (fo->fi->fi_flags & FI_SCALABLE) ? '0' : LFDSeparator[0];
609
610    switch( uRelax )
611    {
612        /* RealizeFont() will call us repeatedly with increasing uRelax 
613         * until XLoadFont() succeeds. */
614
615        case 0: 
616             if( point )
617             {
618                 sprintf( lpch, "%s-%s-%i-%c-%c-*-%s", h_string, 
619                          point_string, 
620                          fo->fi->lfd_resolution, ch, w, lpEncoding );
621                 break;
622             }
623             /* fall through */
624
625        case 1: 
626        case 2: /* 2 will have replaced an 'r' in slant by '*' */
627             sprintf( lpch, "%s-*-%i-%c-%c-*-%s", h_string, 
628                         fo->fi->lfd_resolution, ch, w, lpEncoding );
629             break;
630
631        case 3:
632             sprintf( lpch, "%s-*-%i-%c-*-*-%s",
633                         h_string, fo->fi->lfd_resolution, ch, lpEncoding );
634             break;
635
636        case 4:
637             sprintf( lpch, "%i-*-%i-%c-*-*-%s", fo->fi->lfd_height,
638                         fo->fi->lfd_resolution, ch, lpEncoding );
639             break;
640
641        case 5:
642             sprintf( lpch, "%i-*-*-*-*-*-%s", fo->fi->lfd_height, lpEncoding );
643             break;
644
645        default:
646             sprintf( lpch, "%i-*-*-*-*-*-*-*", fo->fi->lfd_height);
647             break;
648
649        /* to avoid an infinite loop; those will allways match */
650        case 200:
651             sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1" );
652             break;
653        case 201:
654             sprintf( lpLFD, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" );
655             break;
656    }
657
658    TRACE(font,"\tLFD(uRelax=%d): %s\n", uRelax, lpLFD );
659    assert(*(lpLFD+MAX_LFD_LENGTH-1)==0); /* check if overwrittem */
660    return TRUE;
661 }
662
663
664 /***********************************************************************
665  *              X Font Resources
666  *
667  * font info            - http://www.microsoft.com/kb/articles/q65/1/23.htm
668  * Windows font metrics - http://www.microsoft.com/kb/articles/q32/6/67.htm
669  */
670 static BOOL XFONT_GetLeading( LPIFONTINFO16 pFI, XFontStruct* x_fs, INT*
671        pIL, INT* pEL, XFONTTRANS *XFT )
672 {
673     unsigned long height;
674     unsigned min = (unsigned char)pFI->dfFirstChar;
675     unsigned max = (unsigned char)pFI->dfLastChar;
676     BOOL bHaveCapHeight = (pFI->dfCharSet == ANSI_CHARSET && 'X' >= min && 'X' <= max );
677
678     if( pEL ) *pEL = 0;
679
680     if(XFT) {
681         Atom RAW_CAP_HEIGHT = TSXInternAtom(display, "RAW_CAP_HEIGHT", TRUE);
682         if(TSXGetFontProperty(x_fs, RAW_CAP_HEIGHT, &height))
683             *pIL = XFT->ascent - 
684                             (INT)(XFT->pixelsize / 1000.0 * height);
685         else
686             *pIL = 0;
687         return bHaveCapHeight && x_fs->per_char;
688     }
689        
690     if( TSXGetFontProperty(x_fs, XA_CAP_HEIGHT, &height) == FALSE )
691     {
692         if( x_fs->per_char )
693             if( bHaveCapHeight )
694                     height = x_fs->per_char['X' - min].ascent;
695             else
696                 if (x_fs->ascent >= x_fs->max_bounds.ascent)
697                     height = x_fs->max_bounds.ascent;
698                 else
699                 {
700                     height = x_fs->ascent;
701                     if( pEL )
702                         *pEL = x_fs->max_bounds.ascent - height;
703                 }
704         else 
705             height = x_fs->min_bounds.ascent;
706     }
707
708    *pIL = x_fs->ascent - height;
709     return (bHaveCapHeight && x_fs->per_char);
710 }
711
712 static INT XFONT_GetAvgCharWidth( LPIFONTINFO16 pFI, XFontStruct* x_fs,
713                                     XFONTTRANS *XFT)
714 {
715     unsigned min = (unsigned char)pFI->dfFirstChar;
716     unsigned max = (unsigned char)pFI->dfLastChar;
717
718     if( x_fs->per_char )
719     {
720         int  width, chars, j;
721         for( j = 0, width = 0, chars = 0, max -= min; j <= max; j++ )
722             if( !CI_NONEXISTCHAR(x_fs->per_char + j) )
723             {
724                 if(!XFT)
725                     width += x_fs->per_char[j].width;
726                 else
727                     width += x_fs->per_char[j].attributes * 
728                       XFT->pixelsize / 1000.0;
729                 chars++;
730             }
731         return (width / chars);
732     }
733     /* uniform width */
734     return x_fs->min_bounds.width;
735 }
736
737 static INT XFONT_GetMaxCharWidth(fontObject *pfo)
738 {
739     unsigned min = (unsigned char)pfo->fs->min_char_or_byte2;
740     unsigned max = (unsigned char)pfo->fs->max_char_or_byte2;
741
742     if(!pfo->lpX11Trans)
743         return abs(pfo->fs->max_bounds.width);
744
745     if( pfo->fs->per_char )
746     {
747         int  maxwidth, j;
748         for( j = 0, maxwidth = 0, max -= min; j <= max; j++ )
749             if( !CI_NONEXISTCHAR(pfo->fs->per_char + j) )
750                 if(maxwidth < pfo->fs->per_char[j].attributes)
751                     maxwidth = pfo->fs->per_char[j].attributes;
752
753         maxwidth *= pfo->lpX11Trans->pixelsize / 1000.0;
754         return maxwidth;
755     }
756     return pfo->foAvgCharWidth;
757 }
758
759 /***********************************************************************
760  *              XFONT_SetFontMetric
761  *
762  * INIT ONLY
763  *
764  * Initializes IFONTINFO16. dfHorizRes and dfVertRes must be already set.
765  */
766 static void XFONT_SetFontMetric(fontInfo* fi, fontResource* fr, XFontStruct* xfs)
767 {
768     unsigned     min, max;
769     INT  el, il;
770
771     fi->df.dfFirstChar = (BYTE)(min = xfs->min_char_or_byte2);
772     fi->df.dfLastChar = (BYTE)(max = xfs->max_char_or_byte2);
773
774     fi->df.dfDefaultChar = (BYTE)xfs->default_char;
775     fi->df.dfBreakChar = (BYTE)(( ' ' < min || ' ' > max) ? xfs->default_char: ' ');
776
777     fi->df.dfPixHeight = (INT16)((fi->df.dfAscent = (INT16)xfs->ascent) + xfs->descent);
778     fi->df.dfPixWidth = (xfs->per_char) ? 0 : xfs->min_bounds.width;
779     fi->df.dfMaxWidth = (INT16)abs(xfs->max_bounds.width);
780
781     if( XFONT_GetLeading( &fi->df, xfs, &il, &el, NULL ) )
782         fi->df.dfAvgWidth = (INT16)xfs->per_char['X' - min].width;
783     else
784         fi->df.dfAvgWidth = (INT16)XFONT_GetAvgCharWidth( &fi->df, xfs, NULL);
785
786     fi->df.dfInternalLeading = (INT16)il;
787     fi->df.dfExternalLeading = (INT16)el;
788
789     fi->df.dfPoints = (INT16)(((INT)(fi->df.dfPixHeight - 
790                fi->df.dfInternalLeading) * 72 + (fi->df.dfVertRes >> 1)) / fi->df.dfVertRes);
791
792     if( xfs->min_bounds.width != xfs->max_bounds.width )
793         fi->df.dfPitchAndFamily |= TMPF_FIXED_PITCH; /* au contraire! */
794     if( fi->fi_flags & FI_SCALABLE ) 
795     {
796         fi->df.dfType = DEVICE_FONTTYPE;
797         fi->df.dfPitchAndFamily |= TMPF_DEVICE;
798     } 
799     else if( fi->fi_flags & FI_TRUETYPE )
800         fi->df.dfType = TRUETYPE_FONTTYPE;
801     else
802         fi->df.dfType = RASTER_FONTTYPE;
803
804     fi->df.dfFace = fr->lfFaceName;
805 }
806
807 /***********************************************************************
808  *              XFONT_GetTextMetric
809  *
810  * GetTextMetrics() back end.
811  */
812 static void XFONT_GetTextMetric( fontObject* pfo, LPTEXTMETRICA pTM )
813 {
814     LPIFONTINFO16 pdf = &pfo->fi->df;
815
816     if( ! pfo->lpX11Trans ) {
817       pTM->tmAscent = pfo->fs->ascent;
818       pTM->tmDescent = pfo->fs->descent;
819     } else {
820       pTM->tmAscent = pfo->lpX11Trans->ascent;
821       pTM->tmDescent = pfo->lpX11Trans->descent;
822     }
823     pTM->tmHeight = pTM->tmAscent + pTM->tmDescent;
824
825     pTM->tmAveCharWidth = pfo->foAvgCharWidth;
826     pTM->tmMaxCharWidth = pfo->foMaxCharWidth;
827
828     pTM->tmInternalLeading = pfo->foInternalLeading;
829     pTM->tmExternalLeading = pdf->dfExternalLeading;
830
831     pTM->tmStruckOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT )
832                         ? 1 : pdf->dfStrikeOut;
833     pTM->tmUnderlined = (pfo->fo_flags & FO_SYNTH_UNDERLINE )
834                         ? 1 : pdf->dfUnderline;
835
836     pTM->tmOverhang = 0;
837     if( pfo->fo_flags & FO_SYNTH_ITALIC ) 
838     {
839         pTM->tmOverhang += pTM->tmHeight/3;
840         pTM->tmItalic = 1;
841     } else 
842         pTM->tmItalic = pdf->dfItalic;
843
844     pTM->tmWeight = pdf->dfWeight;
845     if( pfo->fo_flags & FO_SYNTH_BOLD ) 
846     {
847         pTM->tmOverhang++; 
848         pTM->tmWeight += 100;
849     } 
850
851     *(INT*)&pTM->tmFirstChar = *(INT*)&pdf->dfFirstChar;
852
853     pTM->tmCharSet = pdf->dfCharSet;
854     pTM->tmPitchAndFamily = pdf->dfPitchAndFamily;
855
856     pTM->tmDigitizedAspectX = pdf->dfHorizRes;
857     pTM->tmDigitizedAspectY = pdf->dfVertRes;
858 }
859
860 /***********************************************************************
861  *              XFONT_GetFontMetric
862  *
863  * Retrieve font metric info (enumeration).
864  */
865 static UINT XFONT_GetFontMetric( fontInfo* pfi, LPENUMLOGFONTEX16 pLF,
866                                                   LPNEWTEXTMETRIC16 pTM )
867 {
868     memset( pLF, 0, sizeof(*pLF) );
869     memset( pTM, 0, sizeof(*pTM) );
870
871 #define plf ((LPLOGFONT16)pLF)
872     plf->lfHeight    = pTM->tmHeight       = pfi->df.dfPixHeight;
873     plf->lfWidth     = pTM->tmAveCharWidth = pfi->df.dfAvgWidth;
874     plf->lfWeight    = pTM->tmWeight       = pfi->df.dfWeight;
875     plf->lfItalic    = pTM->tmItalic       = pfi->df.dfItalic;
876     plf->lfUnderline = pTM->tmUnderlined   = pfi->df.dfUnderline;
877     plf->lfStrikeOut = pTM->tmStruckOut    = pfi->df.dfStrikeOut;
878     plf->lfCharSet   = pTM->tmCharSet      = pfi->df.dfCharSet;
879
880     /* convert pitch values */
881
882     pTM->tmPitchAndFamily = pfi->df.dfPitchAndFamily;
883     plf->lfPitchAndFamily = (pfi->df.dfPitchAndFamily & 0xF1) + 1;
884
885     lstrcpynA( plf->lfFaceName, pfi->df.dfFace, LF_FACESIZE );
886 #undef plf
887
888     pTM->tmAscent = pfi->df.dfAscent;
889     pTM->tmDescent = pTM->tmHeight - pTM->tmAscent;
890     pTM->tmInternalLeading = pfi->df.dfInternalLeading;
891     pTM->tmMaxCharWidth = pfi->df.dfMaxWidth;
892     pTM->tmDigitizedAspectX = pfi->df.dfHorizRes;
893     pTM->tmDigitizedAspectY = pfi->df.dfVertRes;
894
895     *(INT*)&pTM->tmFirstChar = *(INT*)&pfi->df.dfFirstChar;
896
897     /* return font type */
898
899     return pfi->df.dfType;
900 }
901
902
903 /***********************************************************************
904  *           XFONT_FixupFlags
905  *
906  * INIT ONLY
907  * 
908  * dfPitchAndFamily flags for some common typefaces.
909  */
910 static BYTE XFONT_FixupFlags( LPCSTR lfFaceName )
911 {
912    switch( lfFaceName[0] )
913    {
914         case 'h':
915         case 'H': if(!strcasecmp(lfFaceName, "Helvetica") )
916                     return FF_SWISS;
917                   break;
918         case 'c':
919         case 'C': if(!strcasecmp(lfFaceName, "Courier") ||
920                      !strcasecmp(lfFaceName, "Charter") )
921                     return FF_ROMAN;
922                   break;
923         case 'p':
924         case 'P': if( !strcasecmp(lfFaceName,"Palatino") )
925                     return FF_ROMAN;
926                   break;
927         case 't':
928         case 'T': if(!strncasecmp(lfFaceName, "Times", 5) )
929                     return FF_ROMAN;
930                   break;
931         case 'u':
932         case 'U': if(!strcasecmp(lfFaceName, "Utopia") )
933                     return FF_ROMAN;
934                   break;
935         case 'z':
936         case 'Z': if(!strcasecmp(lfFaceName, "Zapf Dingbats") )
937                     return FF_DECORATIVE;
938    }
939    return 0;
940 }
941
942
943 /***********************************************************************
944  *           XFONT_CheckResourceName
945  *
946  * INIT ONLY
947  */
948 static BOOL XFONT_CheckResourceName( LPSTR resource, LPCSTR name, INT n )
949 {
950     resource = LFD_Advance( resource, 2 );
951     if( resource )
952         return (!strncasecmp( resource, name, n ));
953     return FALSE;
954 }
955
956
957 /***********************************************************************
958  *           XFONT_WindowsNames
959  *
960  * INIT ONLY
961  *
962  * Build generic Windows aliases for X font names.
963  *
964  * -misc-fixed- -> "Fixed"
965  * -sony-fixed- -> "Sony Fixed", etc...
966  */
967 static void XFONT_WindowsNames( char* buffer )
968 {
969     fontResource* fr, *pfr;
970     char*       lpstr, *lpch;
971     int         i, up;
972     BYTE        bFamilyStyle;
973     const char* relocTable[3];
974     
975     relocTable[0] = INIDefaultFixed;
976     relocTable[1] = INIDefault;
977     relocTable[2] = NULL;
978
979     for( fr = fontList; fr ; fr = fr->next )
980     {
981         if( fr->fr_flags & FR_NAMESET ) continue;     /* skip already assigned */
982
983         lpstr = LFD_Advance(fr->resource, 2);
984         i = LFD_Advance( lpstr, 1 ) - lpstr;
985
986         for( pfr = fontList; pfr != fr ; pfr = pfr->next )
987             if( pfr->fr_flags & FR_NAMESET )
988                 if( XFONT_CheckResourceName( pfr->resource, lpstr, i ) )
989                     break;
990
991         if( pfr != fr )  /* prepend vendor name */
992             lpstr = fr->resource + 1;
993
994         for( i = 0, up = 1, lpch = fr->lfFaceName; *lpstr && i < 32;
995                                                 lpch++, lpstr++, i++ )
996         {
997             if( *lpstr == LFDSeparator[1] || *lpstr == ' ' ) 
998             { 
999                 *lpch = ' '; 
1000                 up = 1; continue; 
1001             }
1002             else if( isalpha(*lpstr) && up )
1003             { 
1004                 *lpch = toupper(*lpstr); 
1005                 up = 0; continue; 
1006             }
1007             *lpch = *lpstr;
1008         }
1009         while (*(lpch - 1) == ' ') *(--lpch) = '\0';
1010
1011         if( (bFamilyStyle = XFONT_FixupFlags( fr->lfFaceName )) )
1012         {
1013             fontInfo* fi;
1014             for( fi = fr->fi ; fi ; fi = fi->next )
1015                 fi->df.dfPitchAndFamily |= bFamilyStyle;
1016         }
1017
1018         TRACE(font,"typeface \'%s\'\n", fr->lfFaceName);
1019
1020         fr->fr_flags |= FR_NAMESET;
1021     }
1022
1023     for( up = 0; relocTable[up]; up++ )
1024         if( PROFILE_GetWineIniString( INIFontSection, relocTable[up], "", buffer, 128 ) )
1025         {
1026             while( *buffer && isspace(*buffer) ) buffer++;
1027             for( fr = NULL, pfr = fontList; pfr; pfr = pfr->next )
1028             {
1029                 i = strlen( pfr->resource );
1030                 if( !strncasecmp( pfr->resource, buffer, i) )
1031                 {
1032                     if( fr )
1033                     {
1034                         fr->next = pfr->next;
1035                         pfr->next = fontList;
1036                         fontList = pfr;
1037                     }
1038                     break;
1039                 }
1040                 fr = pfr;
1041             }
1042         }
1043 }
1044
1045 /***********************************************************************
1046  *           XFONT_CreateAlias
1047  */
1048 static fontAlias* XFONT_CreateAlias( LPCSTR lpTypeFace, LPCSTR lpAlias )
1049 {
1050     int j;
1051     fontAlias* pfa = aliasTable;
1052
1053     while( 1 ) 
1054     {
1055         /* check if we already got one */
1056         if( !strcasecmp( pfa->faTypeFace, lpAlias ) )
1057         {
1058             TRACE(font,"\tredundant alias '%s' -> '%s'\n", 
1059                   lpAlias, lpTypeFace );
1060             return NULL;
1061         } 
1062         if( pfa->next ) pfa = pfa->next;
1063         else break;
1064     }
1065
1066     j = lstrlenA(lpTypeFace) + 1;
1067     pfa->next = HeapAlloc( SystemHeap, 0, sizeof(fontAlias) +
1068                                           j + lstrlenA(lpAlias) + 1 );
1069     if((pfa = pfa->next))
1070     {
1071         pfa->next = NULL;
1072         pfa->faTypeFace = (LPSTR)(pfa + 1);
1073         lstrcpyA( pfa->faTypeFace, lpTypeFace );
1074         pfa->faAlias = pfa->faTypeFace + j;
1075         lstrcpyA( pfa->faAlias, lpAlias );
1076
1077         TRACE(font, "\tadded alias '%s' for %s\n", lpAlias, lpTypeFace );
1078
1079         return pfa;
1080     }
1081     return NULL;
1082 }
1083
1084 /***********************************************************************
1085  *           XFONT_LoadAliases
1086  *
1087  * Read user-defined aliases from wine.conf. Format is as follows
1088  *
1089  * Alias# = [Windows font name],[LFD font name], <substitute original name>
1090  *
1091  * Example:
1092  *   Alias0 = Arial, -adobe-helvetica- 
1093  *   Alias1 = Times New Roman, -bitstream-courier-, 1
1094  *   ...
1095  *
1096  * Note that from 081797 and on we have built-in alias templates that take
1097  * care of the necessary Windows typefaces.
1098  */
1099 static void XFONT_LoadAliases( char** buffer, int *buf_size )
1100 {
1101     char* lpResource, *lpAlias;
1102     char  subsection[32];
1103     int   i = 0, j = 0;
1104     BOOL bHaveAlias = TRUE, bSubst = FALSE;
1105
1106     if( *buf_size < 128 )
1107     {
1108         *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
1109         *buf_size = 256;
1110     }
1111     do
1112     {
1113         if( j < faTemplateNum )
1114         {
1115             /* built-in templates first */
1116
1117             lpResource = faTemplate[j].fatResource;
1118             lpAlias = faTemplate[j].fatAlias;
1119             j++;
1120         }
1121         else
1122         {
1123             /* then WINE.CONF */
1124
1125             wsprintfA( subsection, "%s%i", INIAliasSection, i++ );
1126
1127             if( (bHaveAlias = PROFILE_GetWineIniString( INIFontSection, 
1128                                         subsection, "", *buffer, 128 )) )
1129             {
1130                 lpAlias = *buffer;
1131                 while( isspace(*lpAlias) ) lpAlias++;
1132                 lpResource = PROFILE_GetStringItem( lpAlias );
1133                 bSubst = (PROFILE_GetStringItem( lpResource )) ? TRUE : FALSE;
1134             }
1135         }
1136
1137         if( bHaveAlias )
1138         {
1139             int length;
1140
1141             length = strlen( lpAlias );
1142             if( lpResource && length )
1143             {
1144                 fontResource* fr, *frMatch = NULL;
1145
1146                 for (fr = fontList; fr ; fr = fr->next)
1147                 {
1148                     if( !strcasecmp( fr->resource, lpResource ) ) frMatch = fr;
1149                     if( XFONT_CheckResourceName( fr->resource, lpAlias, length ) )
1150                     {
1151                         /* alias is not needed since the real font is present */
1152                         frMatch = NULL; break;
1153                     }
1154                 }
1155
1156                 if( frMatch )
1157                 {
1158                     if( bSubst )
1159                     {
1160                         fontAlias *pfa, *prev = NULL;
1161
1162                         for(pfa = aliasTable; pfa; pfa = pfa->next)
1163                         {
1164         /* Remove lpAlias from aliasTable - we should free the old entry */
1165                             if(!strcmp(lpAlias, pfa->faAlias))
1166                             {
1167                                 if(prev)
1168                                     prev->next = pfa->next;
1169                                 else
1170                                     aliasTable = pfa->next;
1171                              }
1172
1173         /* Update any references to the substituted font in aliasTable */
1174                             if(!strcmp(frMatch->lfFaceName,
1175                                                         pfa->faTypeFace))
1176                                 pfa->faTypeFace = HEAP_strdupA( SystemHeap, 0,
1177                                                          lpAlias );
1178                             prev = pfa;
1179                         }
1180                                                 
1181                         TRACE(font, "\tsubstituted '%s' with %s\n",
1182                                                 frMatch->lfFaceName, lpAlias );
1183
1184                         lstrcpynA( frMatch->lfFaceName, lpAlias, LF_FACESIZE );
1185                         frMatch->fr_flags |= FR_NAMESET;
1186                     }
1187                     else
1188                     {
1189                         /* create new entry in the alias table */
1190                         XFONT_CreateAlias( frMatch->lfFaceName, lpAlias );
1191                     }
1192                 }
1193             }
1194             else ERR(font, " malformed font alias '%s'\n", *buffer );
1195         }
1196         else break;
1197     } while(TRUE);
1198 }
1199
1200 /***********************************************************************
1201  *           XFONT_LoadPenalties
1202  *
1203  * Removes specified fonts from the font table to prevent Wine from
1204  * using it.
1205  *
1206  * Ignore# = [LFD font name]
1207  *
1208  * Example:
1209  *   Ignore0 = -misc-nil-
1210  *   Ignore1 = -sun-open look glyph-
1211  *   ...
1212  *
1213  */
1214 static void XFONT_LoadPenalties( char** buffer, int *buf_size )
1215 {
1216     int i = 0;
1217     char  subsection[32];
1218
1219     if( *buf_size < 128 )
1220     {
1221         *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
1222         *buf_size = 256;
1223         *buffer = '\0';
1224     }
1225     do
1226     {
1227         wsprintfA( subsection, "%s%i", INIIgnoreSection, i++ );
1228
1229         if( PROFILE_GetWineIniString( INIFontSection,
1230                                 subsection, "", *buffer, 255 ) )
1231         {
1232             fontResource** ppfr;
1233             int length = strlen( *buffer );
1234
1235             for( ppfr = &fontList; *ppfr ; ppfr = &((*ppfr)->next))
1236             {
1237                 if( !strncasecmp( (*ppfr)->resource, *buffer, length ) )
1238                 {
1239                     TRACE(font, "Ignoring '%s'\n", (*ppfr)->resource );
1240
1241                     XFONT_RemoveFontResource( ppfr );
1242                 }
1243             }
1244         }
1245         else 
1246             break;
1247     } while(TRUE);
1248 }
1249
1250
1251 /***********************************************************************
1252  *           XFONT_UserMetricsCache
1253  * 
1254  * Returns expanded name for the ~/.wine/.cachedmetrics file.
1255  * Now it also appends the current value of the $DISPLAY varaible.
1256  */
1257 static char* XFONT_UserMetricsCache( char* buffer, int* buf_size )
1258 {
1259     char* pchDisplay, *home;
1260
1261     pchDisplay = getenv( "DISPLAY" );
1262     if( !pchDisplay ) pchDisplay = "0";
1263
1264     if ((home = getenv( "HOME" )) != NULL)
1265     {
1266         int i = strlen( home ) + strlen( INIWinePrefix ) + 
1267                 strlen( INIFontMetrics ) + strlen( pchDisplay ) + 2;
1268         if( i > *buf_size ) 
1269             buffer = (char*) HeapReAlloc( SystemHeap, 0, buffer, *buf_size = i );
1270         strcpy( buffer, home );
1271         strcat( buffer, INIWinePrefix );
1272         strcat( buffer, INIFontMetrics );
1273         strcat( buffer, pchDisplay );
1274     } else buffer[0] = '\0';
1275     return buffer;
1276 }
1277
1278
1279 /***********************************************************************
1280  *           XFONT_ReadCachedMetrics
1281  *
1282  * INIT ONLY
1283  */
1284 static BOOL XFONT_ReadCachedMetrics( int fd, int res, unsigned x_checksum, int x_count )
1285 {
1286     if( fd >= 0 )
1287     {
1288         unsigned u;
1289         int i, j;
1290
1291         /* read checksums */
1292         read( fd, &u, sizeof(unsigned) );
1293         read( fd, &i, sizeof(int) );
1294
1295         if( u == x_checksum && i == x_count )
1296         {
1297             off_t length, offset = 3 * sizeof(int);
1298
1299             /* read total size */
1300             read( fd, &i, sizeof(int) );
1301             length = lseek( fd, 0, SEEK_END );
1302
1303             if( length == (i + offset) )
1304             {
1305                 lseek( fd, offset, SEEK_SET );
1306                 fontList = (fontResource*)HeapAlloc( SystemHeap, 0, i);
1307                 if( fontList )
1308                 {
1309                     fontResource*       pfr = fontList;
1310                     fontInfo*           pfi = NULL;
1311
1312                     TRACE(font,"Reading cached font metrics:\n");
1313
1314                     read( fd, fontList, i); /* read all metrics at once */
1315                     while( offset < length )
1316                     {
1317                         offset += sizeof(fontResource) + sizeof(fontInfo);
1318                         pfr->fi = pfi = (fontInfo*)(pfr + 1);
1319                         j = 1;
1320                         while( TRUE )
1321                         {
1322                            if( offset > length ||
1323                               (int)(pfi->next) != j++ ) goto fail;
1324
1325                            pfi->df.dfFace = pfr->lfFaceName;
1326                            pfi->df.dfHorizRes = pfi->df.dfVertRes = res;
1327                            pfi->df.dfPoints = (INT16)(((INT)(pfi->df.dfPixHeight -
1328                                 pfi->df.dfInternalLeading) * 72 + (res >> 1)) / res );
1329                            pfi->next = pfi + 1;
1330
1331                            if( j > pfr->fi_count ) break;
1332
1333                            pfi = pfi->next;
1334                            offset += sizeof(fontInfo);
1335                         }
1336                         pfi->next = NULL;
1337                         if( pfr->next )
1338                         {
1339                             pfr->next = (fontResource*)(pfi + 1);
1340                             pfr = pfr->next;
1341                         } 
1342                         else break;
1343                     }
1344                     if( pfr->next == NULL &&
1345                         *(int*)(pfi + 1) == X_FMC_MAGIC )
1346                     {
1347                         /* read LFD stubs */
1348                         char* lpch = (char*)((int*)(pfi + 1) + 1);
1349                         offset += sizeof(int);
1350                         for( pfr = fontList; pfr; pfr = pfr->next )
1351                         {
1352                             TRACE(font,"\t%s, %i instances\n", lpch, pfr->fi_count );
1353                             pfr->resource = lpch;
1354                             while( TRUE )
1355                             { 
1356                                 if( ++offset > length ) goto fail;
1357                                 if( !*lpch++ ) break;
1358                             }
1359                         }
1360                         close( fd );
1361                         return TRUE;
1362                     }
1363                 }
1364             }
1365         }
1366 fail:
1367         if( fontList ) HeapFree( SystemHeap, 0, fontList );
1368         fontList = NULL;
1369         close( fd );
1370     }
1371     return FALSE;
1372 }
1373
1374 /***********************************************************************
1375  *           XFONT_WriteCachedMetrics
1376  *
1377  * INIT ONLY
1378  */
1379 static BOOL XFONT_WriteCachedMetrics( int fd, unsigned x_checksum, int x_count, int n_ff )
1380 {
1381     fontResource* pfr;
1382     fontInfo* pfi;
1383
1384     if( fd >= 0 )
1385     {
1386         int  i, j, k;
1387
1388         /* font metrics file:
1389          *
1390          * +0000 x_checksum
1391          * +0004 x_count
1392          * +0008 total size to load
1393          * +000C prepackaged font metrics
1394          * ...
1395          * +...x        X_FMC_MAGIC
1396          * +...x + 4    LFD stubs
1397          */
1398
1399         write( fd, &x_checksum, sizeof(unsigned) );
1400         write( fd, &x_count, sizeof(int) );
1401
1402         for( j = i = 0, pfr = fontList; pfr; pfr = pfr->next ) 
1403         {
1404             i += strlen( pfr->resource ) + 1;
1405             j += pfr->fi_count;
1406         }
1407         i += n_ff * sizeof(fontResource) + j * sizeof(fontInfo) + sizeof(int);
1408         write( fd, &i, sizeof(int) );
1409
1410         TRACE(font,"Writing font cache:\n");
1411
1412         for( pfr = fontList; pfr; pfr = pfr->next )
1413         {
1414             fontInfo fi;
1415
1416             TRACE(font,"\t%s, %i instances\n", pfr->resource, pfr->fi_count );
1417
1418             i = write( fd, pfr, sizeof(fontResource) );
1419             if( i == sizeof(fontResource) ) 
1420             {
1421                 for( k = 1, pfi = pfr->fi; pfi; pfi = pfi->next )
1422                 {
1423                     memcpy( &fi, pfi, sizeof(fi) );
1424
1425                     fi.df.dfFace = NULL;
1426                     fi.next = (fontInfo*)k;     /* loader checks this */
1427
1428                     j = write( fd, &fi, sizeof(fi) );
1429                     k++;
1430                 }
1431                 if( j == sizeof(fontInfo) ) continue;
1432             }
1433             break;
1434         }
1435         if( i == sizeof(fontResource) && j == sizeof(fontInfo) )
1436         {
1437             i = j = X_FMC_MAGIC;
1438             write( fd, &i, sizeof(int) );
1439             for( pfr = fontList; pfr && i == j; pfr = pfr->next )
1440             {
1441                 i = strlen( pfr->resource ) + 1;
1442                 j = write( fd, pfr->resource, i );
1443             }
1444         }
1445         close( fd );
1446         return ( i == j );
1447     }
1448     return TRUE;
1449 }
1450
1451 /***********************************************************************
1452  *           XFONT_CheckIniSection
1453  *
1454  * INIT ONLY
1455  *
1456  *   Examines wine.conf for old/invalid font entries and recommend changes to
1457  *   the user.
1458  *
1459  *   Revision history
1460  *        05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
1461  *             Original implementation.
1462  */
1463 static void XFONT_CheckIniCallback(char const *, char const *, void *);
1464
1465 static char const  *fontmsgprologue =
1466 "Wine warning:\n"
1467 "   The following entries in the [fonts] section of the wine.conf file are\n"
1468 "   obsolete or invalid:\n";
1469
1470 static char const  *fontmsgepilogue =
1471 "   These entries should be eliminated or updated.\n"
1472 "   See the documentation/fonts file for more information.\n";
1473
1474 static int XFONT_CheckIniSection()
1475 {
1476     int  found = 0;
1477
1478     PROFILE_EnumerateWineIniSection("Fonts", &XFONT_CheckIniCallback,
1479                     (void *)&found);
1480     if(found)
1481     MSG(fontmsgepilogue);
1482
1483     return 1;
1484 }
1485
1486 static void  XFONT_CheckIniCallback(
1487     char const  *key,
1488     char const  *value,
1489     void  *found)
1490 {
1491     /* Ignore any keys that start with potential comment characters "'", '#',
1492        or ';'. */
1493     if(key[0] == '\'' || key[0] == '#' || key[0] == ';' || key[0] == '\0')
1494     return;
1495
1496     /* Make sure this is a valid key */
1497     if((strncasecmp(key, INIAliasSection, 5) == 0) ||
1498        (strncasecmp(key, INIIgnoreSection, 6) == 0) ||
1499        (strcasecmp( key, INIDefault) == 0) ||
1500        (strcasecmp( key, INIDefaultFixed) == 0) ||
1501        (strcasecmp( key, INIGlobalMetrics) == 0) ||
1502        (strcasecmp( key, INIResolution) == 0) ||
1503        (strcasecmp( key, INIDefaultSerif) == 0) ||
1504        (strcasecmp( key, INIDefaultSansSerif) ==0) )
1505     {
1506         /* Valid key; make sure the value doesn't contain a wildcard */
1507         if(strchr(value, '*')) {
1508             if(*(int *)found == 0) {
1509                 MSG(fontmsgprologue);
1510                 ++*(int *)found;
1511             }
1512
1513             MSG("     %s=%s [no wildcards allowed]\n", key, value);
1514         }
1515     }
1516     else {
1517         /* Not a valid key */
1518         if(*(int *)found == 0) {
1519             MSG(fontmsgprologue);
1520             ++*(int *)found;
1521     }
1522
1523         MSG("     %s=%s [obsolete]\n", key, value);
1524     }
1525
1526     return;
1527 }
1528
1529 /***********************************************************************
1530  *           XFONT_GetPointResolution()
1531  *
1532  * INIT ONLY
1533  *
1534  * Here we initialize DefResolution which is used in the
1535  * XFONT_Match() penalty function. We also load the point
1536  * resolution value (higher values result in larger fonts).
1537  */
1538 static int XFONT_GetPointResolution( DeviceCaps* pDevCaps )
1539 {
1540     int i, j, point_resolution, num = 3; 
1541     int allowed_xfont_resolutions[3] = { 72, 75, 100 };
1542     int best = 0, best_diff = 65536;
1543
1544     DefResolution = point_resolution = PROFILE_GetWineIniInt( INIFontSection, INIResolution, 0 );
1545     if( !DefResolution ) DefResolution = point_resolution = pDevCaps->logPixelsY;
1546     else pDevCaps->logPixelsX = pDevCaps->logPixelsY = DefResolution;
1547
1548     for( i = best = 0; i < num; i++ )
1549     {
1550         j = abs( DefResolution - allowed_xfont_resolutions[i] );
1551         if( j < best_diff )
1552         {
1553             best = i;
1554                 best_diff = j;
1555         }
1556     }
1557     DefResolution = allowed_xfont_resolutions[best];
1558     return point_resolution;
1559 }
1560
1561 /***********************************************************************
1562  *           XFONT_BuildDefaultAliases
1563  *
1564  * INIT ONLY 
1565  *
1566  * Alias "Helv", and "Tms Rmn" to the DefaultSansSerif and DefaultSerif
1567  * fonts respectively.  Create font alias templates for "MS Sans Serif"
1568  * and "MS Serif", also pointing to DefaultSansSerif and DefaultSerif.
1569  */
1570 static int XFONT_BuildDefaultAliases( char** buffer, int* buf_size )
1571 {
1572
1573   aliasTemplate fatDefaultSerif = { "-bitstream-charter-", "Charter" };
1574   aliasTemplate fatDefaultSansSerif = { "-adobe-helvetica-", "Helvetica" };
1575
1576   fontResource* fr;
1577
1578   /* Make sure our buffer is big enough; update calling function's
1579         buf_size if we change it. */
1580
1581   if( *buf_size < 128 )
1582   {
1583     *buffer = HeapReAlloc( SystemHeap, 0, *buffer, 256 );
1584     *buf_size = 256;
1585   }
1586
1587   /* Get the X11 name of the default serif font from the Wine INI file.
1588         (-bitstream-charter- is the default.) */
1589
1590   PROFILE_GetWineIniString( INIFontSection, INIDefaultSerif,
1591                                 fatDefaultSerif.fatResource, *buffer, 128 );
1592
1593   /* Find the Windows typeface which corresponds to the X11 font. */
1594
1595   for( fr = fontList; fr; fr = fr->next )
1596     if( !strcasecmp( fr->resource, *buffer ) ) break;
1597
1598   /* Update the Alias Table entry for "Tms Rmn" with the default serif font's
1599         typeface.  Update the Alias Template for "MS Serif" with the default
1600         serif font's X11 name.  Note that this method leaves us dependant on
1601         the order of the Alias Table and the Alias Templates.  Also, we don't
1602         check for or handle a situation in which -bitstream-charter- is not
1603         available. */
1604
1605   if( fr )
1606   {
1607     TRACE(font, "Using \'%s\' as default serif font\n", fr->lfFaceName);
1608     aliasTable[1].faTypeFace = fr->lfFaceName;
1609     faTemplate[1].fatResource = fr->resource;
1610   }
1611   else
1612   {
1613     WARN(font, "No typeface found for \'%s\'; using \'%s\'\n", *buffer,
1614                                                 fatDefaultSerif.fatAlias);
1615     aliasTable[1].faTypeFace = fatDefaultSerif.fatAlias;        /* Charter */
1616     faTemplate[1].fatResource = fatDefaultSerif.fatResource;
1617   }
1618
1619   /* Get the X11 name of the default sans serif font from the Wine INI file.
1620         (-adobe-helvetica- is the default.) */
1621
1622   PROFILE_GetWineIniString (INIFontSection, INIDefaultSansSerif,
1623                         fatDefaultSansSerif.fatResource, *buffer, 128 );
1624
1625   /* Find the Windows typeface which corresponds to the X11 font. */
1626
1627   for( fr = fontList; fr; fr = fr->next )
1628     if ( !strcasecmp( fr->resource, *buffer ) ) break;
1629
1630   /* Update the Alias Table entry for "Helv" with the default sans serif font's
1631         typeface.  Update the Alias Template for "MS Sans Serif" with the
1632         default sans serif font's X11 name.  Note that this method leaves us
1633         dependant on the order of the Alias Table and the Alias Templates.
1634         Also, we don't check for or handle a situation in which
1635         -adobe-helvetica- is not available. */
1636
1637   if( fr )
1638   {
1639     TRACE(font, "Using \'%s\' as default sans serif font\n", fr->lfFaceName);
1640     aliasTable[0].faTypeFace = fr->lfFaceName;
1641     faTemplate[0].fatResource = fr->resource;
1642   }
1643   else
1644   {
1645     WARN(font, "No typeface found for \'%s\'; using \'%s\'\n", *buffer,
1646                                                 fatDefaultSansSerif.fatAlias);
1647     aliasTable[0].faTypeFace = fatDefaultSansSerif.fatAlias;    /* Helvetica */
1648     faTemplate[0].fatResource = fatDefaultSansSerif.fatResource;
1649   }
1650
1651   return 0;
1652 }
1653
1654 /***********************************************************************
1655  *           X11DRV_FONT_Init
1656  *
1657  * Initialize font resource list and allocate font cache.
1658  */
1659 BOOL X11DRV_FONT_Init( DeviceCaps* pDevCaps )
1660 {
1661   XFontStruct*  x_fs;
1662   fontResource* fr, *pfr;
1663   fontInfo*     fi, *pfi;
1664   unsigned      x_checksum;
1665   int           i, j, res, x_count, fd = -1, buf_size = 0;
1666   char*         lpstr, *lpch, *lpmetrics, *buffer;
1667   char**        x_pattern;
1668
1669   XFONT_CheckIniSection();
1670
1671   res = XFONT_GetPointResolution( pDevCaps );
1672       
1673   x_pattern = TSXListFonts(display, "*", MAX_FONT_FAMILIES * 16, &x_count );
1674
1675   TRACE(font,"Font Mapper: initializing %i fonts [LPY=%i, XDR=%i, DR=%i]\n", 
1676                                     x_count, pDevCaps->logPixelsY, DefResolution, res);
1677   for( i = x_checksum = 0; i < x_count; i++ )
1678   {
1679 #if 0
1680      printf("%i\t: %s\n", i, x_pattern[i] );
1681 #endif
1682
1683      j = strlen( x_pattern[i] );
1684      if( j ) x_checksum ^= __genericCheckSum( x_pattern[i], j );
1685   }
1686   x_checksum |= X_PFONT_MAGIC;
1687
1688   buf_size = 128;
1689   buffer = HeapAlloc( SystemHeap, 0, buf_size );
1690   lpmetrics = NULL;
1691
1692   /* deal with systemwide font metrics cache */
1693
1694   if( PROFILE_GetWineIniString( INIFontSection, INIGlobalMetrics, "", buffer, 128 ) )
1695       fd = open( buffer, O_RDONLY );
1696
1697   if( XFONT_ReadCachedMetrics(fd, res, x_checksum, x_count) == FALSE )
1698   {
1699       /* try per-user */
1700       buffer = XFONT_UserMetricsCache( buffer, &buf_size );
1701       if( buffer[0] )
1702       {
1703           fd = open( buffer, O_RDONLY );
1704           if( XFONT_ReadCachedMetrics(fd, res, x_checksum, x_count) == FALSE )
1705               lpmetrics = HEAP_strdupA( SystemHeap, 0, buffer ); /* update later on */
1706       }
1707   }
1708
1709   fi = NULL;
1710   if( fontList == NULL )        /* build metrics from scratch */
1711   {
1712      int n_ff;
1713      char* typeface;
1714
1715      for( i = n_ff = 0; i < x_count; i++ )
1716      {
1717         typeface = lpch = x_pattern[i];
1718
1719         lpch = LFD_Advance(typeface, 3); /* extra '-' in the beginning */
1720         if( !*lpch ) continue;
1721
1722         lpstr = lpch; 
1723         j = lpch - typeface;    /* resource name length */
1724
1725         /* find a family to insert into */
1726
1727         for( pfr = NULL, fr = fontList; fr; fr = fr->next )
1728         {
1729            if( !strncasecmp(fr->resource, typeface, j) && 
1730                strlen(fr->resource) == j ) break;
1731            pfr = fr;
1732         }  
1733
1734         if( !fi ) fi = (fontInfo*) HeapAlloc(SystemHeap, 0, sizeof(fontInfo));
1735
1736         if( !fr ) /* add new family */
1737         {
1738            if( n_ff >= MAX_FONT_FAMILIES ) break;
1739            if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1740
1741            n_ff++;
1742            fr = (fontResource*) HeapAlloc(SystemHeap, 0, sizeof(fontResource)); 
1743            memset(fr, 0, sizeof(fontResource));
1744            fr->resource = (char*) HeapAlloc(SystemHeap, 0, j + 1 );
1745            lstrcpynA( fr->resource, typeface, j + 1 );
1746
1747            TRACE(font,"    family: %s\n", fr->resource );
1748
1749            if( pfr ) pfr->next = fr;
1750            else fontList = fr;
1751         }
1752         else if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1753
1754         /* check if we already have something better than "fi" */
1755
1756         for( pfi = fr->fi, j = 0; pfi && j <= 0; pfi = pfi->next ) 
1757            if( (j = XFONT_IsSubset( pfi, fi )) < 0 ) 
1758                pfi->fi_flags |= FI_SUBSET; /* superseded by "fi" */
1759         if( j > 0 ) continue;
1760
1761         /* add new font instance "fi" to the "fr" font resource */
1762
1763         if( fi->fi_flags & FI_SCALABLE )
1764         {
1765             /* set scalable font height to 24 to get an origin for extrapolation */
1766
1767            j = strlen(typeface);  j += 0x10;
1768            if( j > buf_size ) 
1769                buffer = (char*)HeapReAlloc( SystemHeap, 0, buffer, buf_size = j );
1770
1771            lpch = LFD_Advance(typeface, 7);
1772            memcpy( buffer, typeface, (j = lpch - typeface) );
1773            lpch = LFD_Advance(lpch, 4);
1774            sprintf( buffer + j, "%d-%d-%d-*-%c-*-", fi->lfd_height,
1775                             fi->lfd_decipoints, fi->lfd_resolution,
1776                                         (*lpch == '-')?'*':*lpch );
1777            lpch = LFD_Advance(lpch, 2);
1778            strcat( lpstr = buffer, lpch);
1779         }
1780         else lpstr = typeface;
1781
1782         if( (x_fs = TSXLoadQueryFont(display, lpstr)) )
1783         {
1784            fi->df.dfHorizRes = fi->df.dfVertRes = res;
1785
1786            XFONT_SetFontMetric( fi, fr, x_fs );
1787            TSXFreeFont( display, x_fs );
1788
1789            TRACE(font,"\t[% 2ipt] '%s'\n", fi->df.dfPoints, typeface );
1790
1791            XFONT_CheckFIList( fr, fi, REMOVE_SUBSETS );
1792            fi = NULL;   /* preventing reuse */
1793         }
1794         else
1795         {
1796            ERR(font, "failed to load %s\n", lpstr );
1797
1798            XFONT_CheckFIList( fr, fi, UNMARK_SUBSETS );
1799         }
1800      }
1801
1802      if( lpmetrics )     /* update cached metrics */
1803      {
1804          fd = open( lpmetrics, O_CREAT | O_TRUNC | O_RDWR, 0644 ); /* -rw-r--r-- */
1805          if( XFONT_WriteCachedMetrics( fd, x_checksum, x_count, n_ff ) == FALSE )
1806              if( fd ) remove( lpmetrics );      /* couldn't write entire file */
1807          HeapFree( SystemHeap, 0, lpmetrics );
1808      }
1809   }
1810
1811   if( fi ) HeapFree(SystemHeap, 0, fi);
1812   TSXFreeFontNames(x_pattern);
1813
1814   /* check if we're dealing with X11 R6 server */
1815
1816   strcpy(buffer, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
1817   if( (x_fs = TSXLoadQueryFont(display, buffer)) )
1818   {
1819        XTextCaps |= TC_SF_X_YINDEP;
1820        TSXFreeFont(display, x_fs);
1821   }
1822
1823   XFONT_WindowsNames( buffer );
1824   XFONT_BuildDefaultAliases( &buffer, &buf_size );
1825   XFONT_LoadAliases( &buffer, &buf_size );
1826   XFONT_LoadPenalties( &buffer, &buf_size );
1827   HeapFree(SystemHeap, 0, buffer);
1828
1829   InitializeCriticalSection( &crtsc_fonts_X11 );
1830   MakeCriticalSectionGlobal( &crtsc_fonts_X11 );
1831
1832   /* fontList initialization is over, allocate X font cache */
1833
1834   fontCache = (fontObject*) HeapAlloc(SystemHeap, 0, fontCacheSize * sizeof(fontObject));
1835   XFONT_GrowFreeList(0, fontCacheSize - 1);
1836
1837   TRACE(font,"done!\n");
1838
1839   /* update text caps parameter */
1840
1841   pDevCaps->textCaps = XTextCaps;
1842
1843   RAW_ASCENT = TSXInternAtom(display, "RAW_ASCENT", TRUE);
1844   RAW_DESCENT = TSXInternAtom(display, "RAW_DESCENT", TRUE);
1845   
1846   return TRUE;
1847 }
1848
1849
1850 /***********************************************************************
1851  *           XFONT_RemoveFontResource
1852  *
1853  * Caller should check if the font resource is in use. If it is it should
1854  * set FR_REMOVED flag to delay removal until the resource is not in use
1855  * anymore.
1856  */
1857 void XFONT_RemoveFontResource( fontResource** ppfr )
1858 {
1859     fontInfo* pfi;
1860     fontResource* pfr = *ppfr;
1861
1862     *ppfr = pfr->next;
1863     while( pfr->fi )
1864     {
1865         pfi = pfr->fi->next;
1866         HeapFree( SystemHeap, 0, pfr->fi );
1867         pfr->fi = pfi;
1868     }
1869     HeapFree( SystemHeap, 0, pfr );
1870 }
1871
1872 /***********************************************************************
1873  *           X Font Matching
1874  *
1875  * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1876  */
1877 static INT XFONT_IsSubset(fontInfo* match, fontInfo* fi)
1878 {
1879   INT           m;
1880
1881   /* 0 - keep both, 1 - keep match, -1 - keep fi */
1882
1883   m = (BYTE*)&fi->df.dfPixWidth - (BYTE*)&fi->df.dfItalic;
1884   if( memcmp(&match->df.dfItalic, &fi->df.dfItalic, m )) return 0;
1885
1886   if( (!((fi->fi_flags & FI_SCALABLE) + (match->fi_flags & FI_SCALABLE))
1887        && fi->lfd_height != match->lfd_height) ||
1888       (!((fi->fi_flags & FI_POLYWEIGHT) + (match->fi_flags & FI_POLYWEIGHT))
1889        && fi->df.dfWeight != match->df.dfWeight) ) return 0;
1890
1891   m = (int)(match->fi_flags & (FI_POLYWEIGHT | FI_SCALABLE)) -
1892       (int)(fi->fi_flags & (FI_SCALABLE | FI_POLYWEIGHT));
1893
1894   if( m == (FI_POLYWEIGHT - FI_SCALABLE) ||
1895       m == (FI_SCALABLE - FI_POLYWEIGHT) ) return 0;    /* keep both */
1896   else if( m >= 0 ) return 1;   /* 'match' is better */
1897
1898   return -1;                    /* 'fi' is better */
1899 }
1900
1901 /***********************************************************************
1902  *            XFONT_Match
1903  *
1904  * Compute the matching score between the logical font and the device font.
1905  *
1906  * contributions from highest to lowest:
1907  *      charset
1908  *      fixed pitch
1909  *      height
1910  *      family flags (only when the facename is not present)
1911  *      width
1912  *      weight, italics, underlines, strikeouts
1913  *
1914  * NOTE: you can experiment with different penalty weights to see what happens.
1915  * http://premium.microsoft.com/msdn/library/techart/f365/f36b/f37b/d38b/sa8bf.htm
1916  */
1917 static UINT XFONT_Match( fontMatch* pfm )
1918 {
1919    fontInfo*    pfi = pfm->pfi;         /* device font to match */
1920    LPLOGFONT16  plf = pfm->plf;         /* wanted logical font */
1921    UINT       penalty = 0;
1922    BOOL       bR6 = pfm->flags & FO_MATCH_XYINDEP;    /* from TextCaps */
1923    BOOL       bScale = pfi->fi_flags & FI_SCALABLE;
1924    INT        d, h;
1925
1926    TRACE(font,"\t[ %-2ipt h=%-3i w=%-3i %s%s]\n", pfi->df.dfPoints,
1927                  pfi->df.dfPixHeight, pfi->df.dfAvgWidth,
1928                 (pfi->df.dfWeight > 400) ? "Bold " : "Normal ",
1929                 (pfi->df.dfItalic) ? "Italic" : "" );
1930
1931    pfm->flags = 0;
1932
1933    if( plf->lfCharSet == DEFAULT_CHARSET )
1934    {
1935        if( (pfi->df.dfCharSet!= ANSI_CHARSET) && (pfi->df.dfCharSet!=DEFAULT_CHARSET) ) 
1936             penalty += 0x200;
1937    }
1938    else if (plf->lfCharSet != pfi->df.dfCharSet) penalty += 0x200;
1939
1940    /* FIXME: Hack to demote symbols and nil fonts.  Should take into
1941              account if a program ever actually asked for this type of
1942              font */
1943    if ( (strcmp(pfm->pfr->lfFaceName,"Symbol")==0) || (strcmp(pfm->pfr->lfFaceName,"Nil")==0) ) 
1944      penalty += 0x200; /* very stiff penality */
1945
1946    /* TMPF_FIXED_PITCH means exactly the opposite */
1947
1948    if( plf->lfPitchAndFamily & FIXED_PITCH ) 
1949    {
1950       if( pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH ) penalty += 0x100;
1951    }
1952    else if( !(pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH) ) penalty += 0x2;
1953
1954    if( plf->lfHeight > 0 )
1955        d = (h = pfi->df.dfPixHeight) - plf->lfHeight;
1956    else if( plf->lfHeight < -1 )
1957        d = (h = pfi->df.dfPoints) + plf->lfHeight;
1958    else d = h = 0;      
1959
1960    if( d && h && plf->lfHeight )
1961    {
1962        UINT16   height = ( plf->lfHeight > 0 ) ? plf->lfHeight
1963                          : ((-plf->lfHeight * pfi->df.dfPixHeight) / h);
1964        if( bScale ) pfm->height = height;
1965        else if( (plf->lfQuality != PROOF_QUALITY) && bR6 )
1966        {
1967            if( d > 0 )  /* do not shrink raster fonts */
1968            {
1969                pfm->height = pfi->df.dfPixHeight;
1970                penalty += (pfi->df.dfPixHeight - height) * 0x4;
1971            }
1972            else         /* expand only in integer multiples */
1973            {
1974                pfm->height = height - height%pfi->df.dfPixHeight;
1975                penalty += (height - pfm->height + 1) * height / pfi->df.dfPixHeight;
1976            }
1977        }
1978        else /* can't be scaled at all */
1979        {
1980            if( plf->lfQuality != PROOF_QUALITY) pfm->flags |= FO_SYNTH_HEIGHT;
1981            pfm->height = pfi->df.dfPixHeight;
1982            penalty += (d > 0)? d * 0x8 : -d * 0x10;
1983        }
1984    }
1985    else pfm->height = pfi->df.dfPixHeight;
1986
1987    if((pfm->flags & FO_MATCH_PAF) &&
1988       (plf->lfPitchAndFamily & FF_FAMILY) != (pfi->df.dfPitchAndFamily & FF_FAMILY) )
1989        penalty += 0x10;
1990
1991    if( plf->lfWidth )
1992    {
1993        if( bR6 && bScale ) h = 0; 
1994        else
1995        {
1996            /* FIXME: not complete */
1997
1998            pfm->flags |= FO_SYNTH_WIDTH;
1999            h = abs(plf->lfWidth - (pfm->height * pfi->df.dfAvgWidth)/pfi->df.dfPixHeight);
2000        }
2001        penalty += h * ( d ) ? 0x2 : 0x1 ;
2002    }
2003    else if( !(pfi->fi_flags & FI_NORMAL) ) penalty++;
2004
2005    if( plf->lfWeight != FW_DONTCARE )
2006    {
2007        penalty += abs(plf->lfWeight - pfi->df.dfWeight) / 40;
2008        if( plf->lfWeight > pfi->df.dfWeight ) pfm->flags |= FO_SYNTH_BOLD;
2009    } else if( pfi->df.dfWeight >= FW_BOLD ) penalty++;  /* choose normal by default */
2010
2011    if( plf->lfItalic != pfi->df.dfItalic )
2012    {
2013        penalty += 0x4;
2014        pfm->flags |= FO_SYNTH_ITALIC;
2015    }
2016
2017    if( plf->lfUnderline ) pfm->flags |= FO_SYNTH_UNDERLINE;
2018    if( plf->lfStrikeOut ) pfm->flags |= FO_SYNTH_STRIKEOUT;
2019
2020    if( penalty && pfi->lfd_resolution != DefResolution ) 
2021        penalty++;
2022
2023    TRACE(font,"  returning %i\n", penalty );
2024
2025    return penalty;
2026 }
2027
2028 /***********************************************************************
2029  *            XFONT_MatchFIList
2030  *
2031  * Scan a particular font resource for the best match.
2032  */
2033 static UINT XFONT_MatchFIList( fontMatch* pfm )
2034 {
2035   BOOL        skipRaster = (pfm->flags & FO_MATCH_NORASTER);
2036   UINT        current_score, score = (UINT)(-1);
2037   UINT16        origflags = pfm->flags; /* Preserve FO_MATCH_XYINDEP */
2038   fontMatch     fm = *pfm;
2039
2040   for( fm.pfi = pfm->pfr->fi; fm.pfi && score; fm.pfi = fm.pfi->next,
2041       fm.flags = origflags )
2042   {
2043      if( skipRaster && !(fm.pfi->fi_flags & FI_SCALABLE) )
2044          continue;
2045
2046      current_score = XFONT_Match( &fm );
2047      if( score > current_score )
2048      {
2049         memcpy( pfm, &fm, sizeof(fontMatch) );
2050         score = current_score;
2051      }
2052   }
2053   return score;
2054 }
2055
2056 /***********************************************************************
2057  *            XFONT_CheckFIList
2058  *
2059  * REMOVE_SUBSETS - attach new fi and purge subsets
2060  * UNMARK_SUBSETS - remove subset flags from all fi entries
2061  */
2062 static void XFONT_CheckFIList( fontResource* fr, fontInfo* fi, int action)
2063 {
2064   int           i = 0;
2065   fontInfo*     pfi, *prev;
2066
2067   for( prev = NULL, pfi = fr->fi; pfi; )
2068   {
2069     if( action == REMOVE_SUBSETS )
2070     {
2071         if( pfi->fi_flags & FI_SUBSET )
2072         {
2073             fontInfo* subset = pfi;
2074
2075             i++;
2076             fr->fi_count--;
2077             if( prev ) prev->next = pfi = pfi->next;
2078             else fr->fi = pfi = pfi->next;
2079             HeapFree( SystemHeap, 0, subset );
2080             continue;
2081         }
2082     }
2083     else pfi->fi_flags &= ~FI_SUBSET;
2084
2085     prev = pfi; 
2086     pfi = pfi->next;
2087   }
2088
2089   if( action == REMOVE_SUBSETS )        /* also add the superset */
2090   {
2091     if( fi->fi_flags & FI_SCALABLE )
2092     {
2093         fi->next = fr->fi;
2094         fr->fi = fi;
2095     }
2096     else if( prev ) prev->next = fi; else fr->fi = fi;
2097     fr->fi_count++;
2098   }
2099
2100   if( i ) TRACE(font,"\t    purged %i subsets [%i]\n", i , fr->fi_count);
2101 }
2102
2103 /***********************************************************************
2104  *            XFONT_FindFIList
2105  */
2106 static fontResource* XFONT_FindFIList( fontResource* pfr, const char* pTypeFace )
2107 {
2108   while( pfr )
2109   {
2110     if( !strcasecmp( pfr->lfFaceName, pTypeFace ) ) break;
2111     pfr = pfr->next;
2112   }
2113   return pfr;
2114 }
2115
2116 /***********************************************************************
2117  *          XFONT_MatchDeviceFont
2118  *
2119  * Scan font resource tree.
2120  */
2121 static BOOL XFONT_MatchDeviceFont( fontResource* start, fontMatch* pfm )
2122 {
2123     fontResource**      ppfr;
2124     fontMatch           fm = *pfm;
2125
2126     pfm->pfi = NULL;
2127     if( fm.plf->lfFaceName[0] ) 
2128     {
2129         fontAlias* fa;
2130         LPSTR str = NULL;
2131
2132         for( fa = aliasTable; fa; fa = fa->next )
2133              if( !strcmp( fa->faAlias, fm.plf->lfFaceName ) ) 
2134              {
2135                 str = fa->faTypeFace;
2136                 break;
2137              }
2138         fm.pfr = XFONT_FindFIList( start, str ? str : fm.plf->lfFaceName );
2139     }
2140
2141     if( fm.pfr ) /* match family */
2142     {
2143         TRACE(font, "%s\n", fm.pfr->lfFaceName );
2144
2145         if( fm.pfr->fr_flags & FR_REMOVED )
2146             fm.pfr = 0;
2147         else
2148         {
2149             XFONT_MatchFIList( &fm );
2150            *pfm = fm;
2151         }
2152     }
2153
2154     if( !pfm->pfi )      /* match all available fonts */
2155     {
2156         UINT          current_score, score = (UINT)(-1);
2157
2158         fm.flags |= FO_MATCH_PAF;
2159         for( ppfr = &fontList; *ppfr && score; ppfr = &(*ppfr)->next )
2160         {
2161             if( (*ppfr)->fr_flags & FR_REMOVED )
2162             {
2163                 if( (*ppfr)->fo_count == 0 )
2164                     XFONT_RemoveFontResource( ppfr );
2165                 continue;
2166             }
2167
2168             fm.pfr = *ppfr;
2169
2170             TRACE(font, "%s\n", fm.pfr->lfFaceName );
2171
2172             current_score = XFONT_MatchFIList( &fm );
2173             if( current_score < score )
2174             {
2175                 score = current_score;
2176                 *pfm = fm;
2177             }
2178         }
2179     }
2180     return TRUE;
2181 }
2182
2183
2184 /***********************************************************************
2185  *           X Font Cache
2186  */
2187 static void XFONT_GrowFreeList(int start, int end)
2188 {
2189    /* add all entries from 'start' up to and including 'end' */
2190
2191    memset( fontCache + start, 0, (end - start + 1) * sizeof(fontObject) );
2192
2193    fontCache[end].lru = fontLF;
2194    fontCache[end].count = -1;
2195    fontLF = start;
2196    while( start < end )
2197    {
2198         fontCache[start].count = -1;
2199         fontCache[start].lru = start + 1;
2200         start++;
2201    } 
2202 }
2203
2204 static fontObject* XFONT_LookupCachedFont( LPLOGFONT16 plf, UINT16* checksum )
2205 {
2206     UINT16      cs = __lfCheckSum( plf );
2207     int         i = fontMRU, prev = -1;
2208    
2209    *checksum = cs;
2210     while( i >= 0 )
2211     {
2212         if( fontCache[i].lfchecksum == cs &&
2213           !(fontCache[i].fo_flags & FO_REMOVED) )
2214         {
2215             /* FIXME: something more intelligent here */
2216
2217             if( !memcmp( plf, &fontCache[i].lf,
2218                          sizeof(LOGFONT16) - LF_FACESIZE ) &&
2219                 !strncasecmp( plf->lfFaceName, fontCache[i].lf.lfFaceName, 
2220                                                             LF_FACESIZE ) )
2221             {
2222                 /* remove temporarily from the lru list */
2223
2224                 if( prev >= 0 )
2225                     fontCache[prev].lru = fontCache[i].lru;
2226                 else 
2227                     fontMRU = (INT16)fontCache[i].lru;
2228                 return (fontCache + i);
2229             }
2230         }
2231         prev = i;
2232         i = (INT16)fontCache[i].lru;
2233     }
2234     return NULL;
2235 }
2236
2237 static fontObject* XFONT_GetCacheEntry()
2238 {
2239     int         i;
2240
2241     if( fontLF == -1 )
2242     {
2243         int     prev_i, prev_j, j;
2244
2245         TRACE(font,"font cache is full\n");
2246
2247         /* lookup the least recently used font */
2248
2249         for( prev_i = prev_j = j = -1, i = fontMRU; i >= 0; i = (INT16)fontCache[i].lru )
2250         {
2251             if( fontCache[i].count <= 0 &&
2252               !(fontCache[i].fo_flags & FO_SYSTEM) )
2253             {
2254                 prev_j = prev_i;
2255                 j = i;
2256             }
2257             prev_i = i;
2258         }
2259
2260         if( j >= 0 )    /* unload font */
2261         {
2262             /* detach from the lru list */
2263
2264             TRACE(font,"\tfreeing entry %i\n", j );
2265
2266             fontCache[j].fr->fo_count--;
2267
2268             if( prev_j >= 0 )
2269                 fontCache[prev_j].lru = fontCache[j].lru;
2270             else fontMRU = (INT16)fontCache[j].lru;
2271
2272             /* FIXME: lpXForm, lpPixmap */
2273             if(fontCache[j].lpX11Trans)
2274                 HeapFree( SystemHeap, 0, fontCache[j].lpX11Trans );
2275
2276             TSXFreeFont( display, fontCache[j].fs );
2277
2278             memset( fontCache + j, 0, sizeof(fontObject) );
2279             return (fontCache + j);
2280         }
2281         else            /* expand cache */
2282         {
2283             fontObject* newCache;
2284
2285             prev_i = fontCacheSize + FONTCACHE;
2286
2287             TRACE(font,"\tgrowing font cache from %i to %i\n", fontCacheSize, prev_i );
2288
2289             if( (newCache = (fontObject*)HeapReAlloc(SystemHeap, 0,  
2290                                                      fontCache, prev_i)) )
2291             {
2292                 i = fontCacheSize;
2293                 fontCacheSize  = prev_i;
2294                 fontCache = newCache;
2295                 XFONT_GrowFreeList( i, fontCacheSize - 1);
2296             } 
2297             else return NULL;
2298         }
2299     }
2300
2301     /* detach from the free list */
2302
2303     i = fontLF;
2304     fontLF = (INT16)fontCache[i].lru;
2305     fontCache[i].count = 0;
2306     return (fontCache + i);
2307 }
2308
2309 static int XFONT_ReleaseCacheEntry(fontObject* pfo)
2310 {
2311     UINT        u = (UINT)(pfo - fontCache);
2312
2313     if( u < fontCacheSize ) return (--fontCache[u].count);
2314     return -1;
2315 }
2316
2317 /**********************************************************************
2318  *      XFONT_SetX11Trans
2319  */
2320 static BOOL XFONT_SetX11Trans( fontObject *pfo )
2321 {
2322   char *fontName;
2323   Atom nameAtom;
2324   char *cp, *start;
2325
2326   TSXGetFontProperty( pfo->fs, XA_FONT, &nameAtom );
2327   fontName = TSXGetAtomName( display, nameAtom );
2328   cp = LFD_Advance( fontName, 7 );
2329   if(*cp != '[') {
2330     TSXFree(fontName);
2331     return FALSE;
2332   }
2333   start = cp;
2334   while((cp = strchr(cp, '~')))
2335     *cp = '-';
2336
2337 #define PX pfo->lpX11Trans
2338
2339   sscanf(start, "[%f%f%f%f]", &PX->a, &PX->b, &PX->c, &PX->d);
2340   TSXFree(fontName);
2341
2342   TSXGetFontProperty( pfo->fs, RAW_ASCENT, &PX->RAW_ASCENT );
2343   TSXGetFontProperty( pfo->fs, RAW_DESCENT, &PX->RAW_DESCENT );
2344
2345   PX->pixelsize = hypot(PX->a, PX->b);
2346   PX->ascent = PX->pixelsize / 1000.0 * PX->RAW_ASCENT;
2347   PX->descent = PX->pixelsize / 1000.0 * PX->RAW_DESCENT;
2348
2349   TRACE(font, "[%f %f %f %f] RA = %ld RD = %ld\n", pfo->lpX11Trans->a, 
2350         pfo->lpX11Trans->b, pfo->lpX11Trans->c, pfo->lpX11Trans->d,
2351         pfo->lpX11Trans->RAW_ASCENT, pfo->lpX11Trans->RAW_DESCENT);
2352
2353 #undef PX
2354   return TRUE;
2355 }
2356
2357 /***********************************************************************
2358  *           X Device Font Objects
2359  */
2360 static X_PHYSFONT XFONT_RealizeFont( LPLOGFONT16 plf )
2361 {
2362     UINT16      checksum;
2363     fontObject* pfo = XFONT_LookupCachedFont( plf, &checksum );
2364
2365     if( !pfo )
2366     {
2367         fontMatch       fm;
2368         INT             i, index;
2369
2370         fm.pfr = NULL;
2371         fm.pfi = NULL;
2372         fm.height = 0;
2373         fm.flags = 0;
2374         fm.plf = plf;
2375
2376         if( XTextCaps & TC_SF_X_YINDEP ) fm.flags = FO_MATCH_XYINDEP;
2377
2378         /* allocate new font cache entry */
2379
2380         if( (pfo = XFONT_GetCacheEntry()) )
2381         {
2382             LPSTR       lpLFD = HeapAlloc( GetProcessHeap(), 0, MAX_LFD_LENGTH );
2383             
2384             if( lpLFD ) /* initialize entry and load font */
2385             {
2386                 UINT    uRelaxLevel = 0;
2387
2388                 TRACE(font,"(%u) '%s' h=%i weight=%i %s\n",
2389                              plf->lfCharSet, plf->lfFaceName, plf->lfHeight, 
2390                              plf->lfWeight, (plf->lfItalic) ? "Italic" : "" );
2391
2392                 if(abs(plf->lfHeight) > MAX_FONT_SIZE) {
2393                     ERR(font,
2394           "plf->lfHeight = %d, this is probably not right. Setting to 12\n", 
2395                         plf->lfHeight);
2396                     plf->lfHeight = 12;
2397                 }
2398
2399                 XFONT_MatchDeviceFont( fontList, &fm );
2400
2401                 pfo->fr = fm.pfr;
2402                 pfo->fi = fm.pfi;
2403                 pfo->fr->fo_count++;
2404                 pfo->fo_flags = fm.flags & ~FO_MATCH_MASK;
2405
2406                 memcpy( &pfo->lf, plf, sizeof(LOGFONT16) );
2407                 pfo->lfchecksum = checksum;
2408
2409                 do
2410                 {
2411                     LFD_ComposeLFD( pfo, fm.height, lpLFD, uRelaxLevel++ );
2412                     if( (pfo->fs = TSXLoadQueryFont( display, lpLFD )) ) break;
2413                 } while( uRelaxLevel );
2414
2415                 
2416                 if(pfo->lf.lfEscapement != 0) {
2417                     pfo->lpX11Trans = HeapAlloc(SystemHeap, 0,
2418                                                 sizeof(XFONTTRANS));
2419                     if(!XFONT_SetX11Trans( pfo )) {
2420                         HeapFree(SystemHeap, 0, pfo->lpX11Trans);
2421                         pfo->lpX11Trans = NULL;
2422                     }
2423                 }
2424
2425                 if( XFONT_GetLeading( &pfo->fi->df, pfo->fs, &i, NULL, 
2426                                       pfo->lpX11Trans ) )
2427
2428                     if(!pfo->lpX11Trans)
2429                         pfo->foAvgCharWidth =
2430               (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].width;
2431                     else
2432                         pfo->foAvgCharWidth = 
2433          (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].attributes
2434                           * pfo->lpX11Trans->pixelsize / 1000.0;
2435                 else
2436                     pfo->foAvgCharWidth = (INT16)XFONT_GetAvgCharWidth(
2437                                      &pfo->fi->df, pfo->fs, pfo->lpX11Trans );
2438                 pfo->foMaxCharWidth = (INT16)XFONT_GetMaxCharWidth(pfo);
2439                 pfo->foInternalLeading = (INT16)i;
2440
2441                 /* FIXME: If we've got a soft font or
2442                  * there are FO_SYNTH_... flags for the
2443                  * non PROOF_QUALITY request, the engine
2444                  * should rasterize characters into mono
2445                  * pixmaps and store them in the pfo->lpPixmap
2446                  * array (pfo->fs should be updated as well).
2447                  * array (pfo->fs should be updated as well).
2448                  * X11DRV_ExtTextOut() must be heavily modified 
2449                  * to support pixmap blitting and FO_SYNTH_...
2450                  * styles.
2451                  */
2452
2453                 pfo->lpPixmap = NULL;
2454
2455                 HeapFree( GetProcessHeap(), 0, lpLFD );
2456             } 
2457             else /* attach back to the free list */
2458             {
2459                 pfo->count = -1;
2460                 pfo->lru = fontLF;
2461                 fontLF = (pfo - fontCache);
2462                 pfo = NULL;
2463             }
2464         }
2465
2466         if( !pfo ) /* couldn't get a new entry, get one of the cached fonts */
2467         {
2468             UINT                current_score, score = (UINT)(-1);
2469
2470             i = index = fontMRU; 
2471             fm.flags |= FO_MATCH_PAF;
2472             do
2473             {
2474                 pfo = fontCache + i;
2475                 fm.pfr = pfo->fr; fm.pfi = pfo->fi;
2476
2477                 current_score = XFONT_Match( &fm );
2478                 if( current_score < score ) index = i;
2479
2480                 i =  pfo->lru;
2481             } while( i >= 0 );
2482             pfo = fontCache + index;
2483             pfo->count++;
2484             return (X_PHYSFONT)(X_PFONT_MAGIC | index);
2485         }
2486     }
2487  
2488     /* attach at the head of the lru list */
2489
2490     pfo->count++;
2491     pfo->lru = fontMRU;
2492     fontMRU = (pfo - fontCache);
2493
2494     TRACE(font,"physfont %i\n", fontMRU);
2495
2496     return (X_PHYSFONT)(X_PFONT_MAGIC | fontMRU);
2497 }
2498
2499 /***********************************************************************
2500  *           XFONT_GetFontObject
2501  */
2502 fontObject* XFONT_GetFontObject( X_PHYSFONT pFont )
2503 {
2504     if( CHECK_PFONT(pFont) ) return __PFONT(pFont);
2505     return NULL;
2506 }
2507
2508 /***********************************************************************
2509  *           XFONT_GetFontStruct
2510  */
2511 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
2512 {
2513     if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
2514     return NULL;
2515 }
2516
2517 /***********************************************************************
2518  *           XFONT_GetFontInfo
2519  */
2520 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
2521 {
2522     if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
2523     return NULL;
2524 }
2525
2526
2527
2528 /* X11DRV Interface ****************************************************
2529  *                                                                     *
2530  * Exposed via the dc->funcs dispatch table.                           *
2531  *                                                                     *
2532  ***********************************************************************/
2533 /***********************************************************************
2534  *           X11DRV_FONT_SelectObject
2535  */
2536 HFONT X11DRV_FONT_SelectObject( DC* dc, HFONT hfont, FONTOBJ* font )
2537 {
2538     HFONT hPrevFont = 0;
2539     LOGFONT16 lf;
2540     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2541
2542     EnterCriticalSection( &crtsc_fonts_X11 );
2543
2544     if( CHECK_PFONT(physDev->font) ) 
2545         XFONT_ReleaseCacheEntry( __PFONT(physDev->font) );
2546
2547     /* FIXME: do we need to pass anything back from here? */
2548     memcpy(&lf,&font->logfont,sizeof(lf));
2549     lf.lfWidth  = font->logfont.lfWidth * dc->vportExtX/dc->wndExtX;
2550     lf.lfHeight = font->logfont.lfHeight* dc->vportExtY/dc->wndExtY;
2551
2552     physDev->font = XFONT_RealizeFont( &lf );
2553     hPrevFont = dc->w.hFont;
2554     dc->w.hFont = hfont;
2555
2556     LeaveCriticalSection( &crtsc_fonts_X11 );
2557
2558     return hPrevFont;
2559 }
2560
2561
2562 /***********************************************************************
2563  *
2564  *           X11DRV_EnumDeviceFonts
2565  */
2566 BOOL    X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf, 
2567                                         DEVICEFONTENUMPROC proc, LPARAM lp )
2568 {
2569     ENUMLOGFONTEX16     lf;
2570     NEWTEXTMETRIC16     tm;
2571     fontResource*       pfr = fontList;
2572     BOOL                b, bRet = 0;
2573
2574     if( plf->lfFaceName[0] )
2575     {
2576         /* enum all entries in this resource */
2577         pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
2578         if( pfr )
2579         {
2580             fontInfo*   pfi;
2581             for( pfi = pfr->fi; pfi; pfi = pfi->next )
2582             {
2583                 /* Note: XFONT_GetFontMetric() will have to
2584                    release the crit section, font list will
2585                    have to be retraversed on return */
2586
2587                 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm, 
2588                         XFONT_GetFontMetric( pfi, &lf, &tm ), lp )) )
2589                      bRet = b;
2590                 else break;
2591             }
2592         }
2593     }
2594     else /* enum first entry in each resource */
2595         for( ; pfr ; pfr = pfr->next )
2596         {
2597             if(pfr->fi)
2598             {
2599                 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm, 
2600                         XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
2601                      bRet = b;
2602                 else break;
2603             }
2604         }
2605     return bRet;
2606 }
2607
2608
2609 /***********************************************************************
2610  *           X11DRV_GetTextExtentPoint
2611  */
2612 BOOL X11DRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT count,
2613                                   LPSIZE size )
2614 {
2615     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2616     fontObject* pfo = XFONT_GetFontObject( physDev->font );
2617     if( pfo ) {
2618         if( !pfo->lpX11Trans ) {
2619             int dir, ascent, descent;
2620             XCharStruct info;
2621
2622             TSXTextExtents( pfo->fs, str, count, &dir, &ascent, &descent, &info );
2623             size->cx = abs((info.width + dc->w.breakRem + count * 
2624                             dc->w.charExtra) * dc->wndExtX / dc->vportExtX);
2625             size->cy = abs((pfo->fs->ascent + pfo->fs->descent) * 
2626                            dc->wndExtY / dc->vportExtY);
2627         } else {
2628
2629             INT i;
2630             float x = 0.0, y = 0.0;
2631             for(i = 0; i < count; i++) {
2632                 x += pfo->fs->per_char ? 
2633            pfo->fs->per_char[str[i] - pfo->fs->min_char_or_byte2].attributes : 
2634            pfo->fs->min_bounds.attributes;
2635             }
2636             y = pfo->lpX11Trans->RAW_ASCENT + pfo->lpX11Trans->RAW_DESCENT;
2637             TRACE(font, "x = %f y = %f\n", x, y);
2638             x *= pfo->lpX11Trans->pixelsize / 1000.0;
2639             y *= pfo->lpX11Trans->pixelsize / 1000.0; 
2640             size->cx = fabs((x + dc->w.breakRem + count * dc->w.charExtra) *
2641                              dc->wndExtX / dc->vportExtX);
2642             size->cy = fabs(y * dc->wndExtY / dc->vportExtY);
2643         }
2644         return TRUE;
2645     }
2646     return FALSE;
2647 }
2648
2649
2650 /***********************************************************************
2651  *           X11DRV_GetTextMetrics
2652  */
2653 BOOL X11DRV_GetTextMetrics(DC *dc, TEXTMETRICA *metrics)
2654 {
2655     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2656
2657     if( CHECK_PFONT(physDev->font) )
2658     {
2659         fontObject* pfo = __PFONT(physDev->font);
2660         XFONT_GetTextMetric( pfo, metrics );
2661
2662         return TRUE;
2663     }
2664     return FALSE;
2665 }
2666
2667
2668 /***********************************************************************
2669  *           X11DRV_GetCharWidth
2670  */
2671 BOOL X11DRV_GetCharWidth( DC *dc, UINT firstChar, UINT lastChar,
2672                             LPINT buffer )
2673 {
2674     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2675     fontObject* pfo = XFONT_GetFontObject( physDev->font );
2676
2677     if( pfo )
2678     {
2679         int i;
2680
2681         if (pfo->fs->per_char == NULL)
2682             for (i = firstChar; i <= lastChar; i++)
2683                 if(pfo->lpX11Trans)
2684                     *buffer++ = pfo->fs->min_bounds.attributes *
2685                       pfo->lpX11Trans->pixelsize / 1000.0;
2686                 else
2687                     *buffer++ = pfo->fs->min_bounds.width;
2688         else
2689         {
2690             XCharStruct *cs, *def;
2691             static XCharStruct  __null_char = { 0, 0, 0, 0, 0, 0 };
2692
2693             CI_GET_CHAR_INFO(pfo->fs, pfo->fs->default_char, &__null_char,
2694                              def);
2695
2696             for (i = firstChar; i <= lastChar; i++)
2697             {
2698                 if (i >= pfo->fs->min_char_or_byte2 && 
2699                     i <= pfo->fs->max_char_or_byte2)
2700                 {
2701                     cs = &pfo->fs->per_char[(i - pfo->fs->min_char_or_byte2)]; 
2702                     if (CI_NONEXISTCHAR(cs)) cs = def; 
2703                 } else cs = def;
2704                 if(pfo->lpX11Trans)
2705                     *buffer++ = MAX(cs->attributes, 0) *
2706                       pfo->lpX11Trans->pixelsize / 1000.0;
2707                 else
2708                     *buffer++ = MAX(cs->width, 0 );
2709             }
2710         }
2711
2712         return TRUE;
2713     }
2714     return FALSE;
2715 }
2716
2717 #endif /* !defined(X_DISPLAY_MISSING) */
2718
2719 /***********************************************************************
2720  *                                                                     *
2721  *           Font Resource API                                         *
2722  *                                                                     *
2723  ***********************************************************************/
2724 /***********************************************************************
2725  *           AddFontResource16    (GDI.119)
2726  *
2727  *  Can be either .FON, or .FNT, or .TTF, or .FOT font file.
2728  *
2729  *  FIXME: Load header and find the best-matching font in the fontList;
2730  *         fixup dfPoints if all metrics are identical, otherwise create
2731  *         new fontAlias. When soft font support is ready this will
2732  *         simply create a new fontResource ('filename' will go into
2733  *         the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE 
2734  *         flag set. 
2735  */
2736 INT16 WINAPI AddFontResource16( LPCSTR filename )
2737 {
2738     return AddFontResourceA( filename );
2739 }
2740
2741
2742 /***********************************************************************
2743  *           AddFontResource32A    (GDI32.2)
2744  */
2745 INT WINAPI AddFontResourceA( LPCSTR str )
2746 {
2747     FIXME(font, "(%s): stub\n", debugres_a(str));
2748     return 1;
2749 }
2750
2751
2752 /***********************************************************************
2753  *           AddFontResource32W    (GDI32.4)
2754  */
2755 INT WINAPI AddFontResourceW( LPCWSTR str )
2756 {
2757     FIXME(font, "(%s): stub\n", debugres_w(str) );
2758     return 1;
2759 }
2760
2761 /***********************************************************************
2762  *           RemoveFontResource16    (GDI.136)
2763  */
2764 BOOL16 WINAPI RemoveFontResource16( SEGPTR str )
2765 {
2766     FIXME(font, "(%s): stub\n", debugres_a(PTR_SEG_TO_LIN(str)));
2767     return TRUE;
2768 }
2769
2770
2771 /***********************************************************************
2772  *           RemoveFontResource32A    (GDI32.284)
2773  */
2774 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
2775 {
2776 /*  This is how it should look like */
2777 /*
2778     fontResource** ppfr;
2779     BOOL32 retVal = FALSE;
2780
2781     EnterCriticalSection( &crtsc_fonts_X11 );
2782     for( ppfr = &fontList; *ppfr; ppfr = &(*ppfr)->next )
2783          if( !strcasecmp( (*ppfr)->lfFaceName, str ) )
2784          {
2785              if(((*ppfr)->fr_flags & (FR_SOFTFONT | FR_SOFTRESOURCE)) &&
2786                  (*ppfr)->hOwnerProcess == GetCurrentProcess() )
2787              {
2788                  if( (*ppfr)->fo_count )
2789                      (*ppfr)->fr_flags |= FR_REMOVED;
2790                  else
2791                      XFONT_RemoveFontResource( ppfr );
2792              }
2793              retVal = TRUE;
2794          }
2795     LeaveCriticalSection( &crtsc_fontList );
2796     return retVal;
2797  */
2798     FIXME(font, "(%s): stub\n", debugres_a(str));
2799     return TRUE;
2800 }
2801
2802
2803 /***********************************************************************
2804  *           RemoveFontResource32W    (GDI32.286)
2805  */
2806 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
2807 {
2808     FIXME(font, "(%s): stub\n", debugres_w(str) );
2809     return TRUE;
2810 }
2811