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