Release 970616
[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 <ctype.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <pwd.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <X11/Xlib.h>
20 #include <X11/Xatom.h>
21 #include "heap.h"
22 #include "options.h"
23 #include "x11font.h"
24 #include "font.h"
25 #include "stddebug.h"
26 #include "debug.h"
27
28 #define DEBUG_FONT_INIT         1
29
30 #define X_PFONT_MAGIC           (0xFADE0000)
31 #define X_FMC_MAGIC             (0x0000CAFE)
32
33 #define MAX_FONT_FAMILIES       64
34 #define MAX_LFD_LENGTH          128
35
36 #define REMOVE_SUBSETS          1
37 #define UNMARK_SUBSETS          0
38
39 #define DEF_SCALABLE_HEIGHT     24
40 #define DEF_SCALABLE_DP         240
41
42 #define FF_FAMILY       (FF_MODERN | FF_SWISS | FF_ROMAN | FF_DECORATIVE | FF_SCRIPT)
43
44 typedef struct __fontAlias
45 {
46   LPSTR                 faTypeFace;
47   LPSTR                 faAlias;
48   struct __fontAlias*   next;
49 } fontAlias;
50
51 static fontAlias aliasTable[2] = { 
52                         { "Helvetica", "Helv", &aliasTable[1] },
53                         { "Times", "Tms Rmn", NULL } 
54                         };
55
56 UINT16                  XTextCaps = TC_OP_CHARACTER | TC_OP_STROKE | TC_CP_STROKE |
57                                     TC_SA_DOUBLE | TC_SA_INTEGER | TC_SA_CONTIN |
58                                     TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
59
60                         /* X11R6 adds TC_SF_X_YINDEP, maybe more... */
61
62 static const char*      INIWinePrefix = "/.wine";
63 static const char*      INIFontMetrics = "/.cachedmetrics";
64 static const char*      INIFontSection = "fonts";
65 static const char*      INISubSection = "Alias";
66 static const char*      INIDefault = "Default";
67
68 static const char*      LFDSeparator = "*-";
69 static const char*      iso8859Encoding = "iso8859-";
70 static const char*      iso646Encoding = "iso646.1991-";
71 static const char*      ansiEncoding = "ansi-";
72 static fontResource*    fontList = NULL;        
73 static unsigned         DefResolution = 0;
74
75 static fontObject*      fontCache = NULL;               /* array */
76 static int              fontCacheSize = FONTCACHE;
77 static int              fontLF = -1, fontMRU = -1;      /* last free, most recently used */
78
79 #define __PFONT(pFont)     ( fontCache + ((UINT32)(pFont) & 0x0000FFFF) )
80 #define CHECK_PFONT(pFont) ( (((UINT32)(pFont) & 0xFFFF0000) == X_PFONT_MAGIC) &&\
81                              (((UINT32)(pFont) & 0x0000FFFF) < fontCacheSize) )
82
83 static INT32 XFONT_IsSubset(fontInfo*, fontInfo*);
84 static void  XFONT_CheckFIList(fontResource*, fontInfo*, int subset_action);
85 static void  XFONT_GrowFreeList(int start, int end);
86
87 /***********************************************************************
88  *           Helper macros from X distribution
89  */
90
91 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
92                              (((cs)->rbearing|(cs)->lbearing| \
93                                (cs)->ascent|(cs)->descent) == 0))
94
95 #define CI_GET_CHAR_INFO(fs,col,def,cs) \
96 { \
97     cs = def; \
98     if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
99         if (fs->per_char == NULL) { \
100             cs = &fs->min_bounds; \
101         } else { \
102             cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
103             if (CI_NONEXISTCHAR(cs)) cs = def; \
104         } \
105     } \
106 }
107
108 #define CI_GET_DEFAULT_INFO(fs,cs) \
109   CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs)
110
111 /***********************************************************************
112  *           Checksums
113  */
114 static UINT16   __lfCheckSum( LPLOGFONT16 plf )
115 {
116     CHAR        font[LF_FACESIZE];
117     UINT16      checksum = 0;
118     UINT16      i;
119
120 #define ptr ((UINT16*)plf)
121    for( i = 0; i < 9; i++ ) checksum ^= *ptr++;
122 #undef ptr
123    i = 0;
124 #define ptr ((CHAR*)plf)
125    do { font[i++] = tolower(*ptr); } while (*ptr++);
126    for( ptr = font, i >>= 1; i > 0; i-- ) 
127 #undef ptr
128 #define ptr ((UINT16*)plf)
129         checksum ^= *ptr++;
130 #undef ptr
131    return checksum;
132 }
133
134 static UINT16   __genericCheckSum( UINT16* ptr, int size )
135 {
136    UINT16       checksum = 0;
137    unsigned     i;
138
139    for( i = 0, size >>= 1; i < size; i++ ) checksum ^= *ptr++;
140    return checksum;
141 }
142
143 /*************************************************************************
144  *           LFD parse/compose routines
145  */
146 static char* LFD_Advance(LPSTR lpFont, UINT16 uParmsNo)
147 {
148   int   j = 0;
149   char* lpch = lpFont;
150
151   for( ; j < uParmsNo && *lpch; lpch++ ) if( *lpch == LFDSeparator[1] ) j++;
152   return lpch;
153 }
154
155 static void LFD_GetWeight( fontInfo* fi, LPSTR lpStr, int j)
156 {
157   if( j == 1 && *lpStr == '0' )
158       fi->fi_flags |= FI_POLYWEIGHT;
159   else if( j == 4 )
160        {
161          if( !lstrncmpi32A( "bold", lpStr, 4) )
162            fi->df.dfWeight = FW_BOLD; 
163          else if( !lstrncmpi32A( "demi", lpStr, 4) )
164          {
165            fi->fi_flags |= FI_FW_DEMI;
166            fi->df.dfWeight = FW_DEMIBOLD;
167          }
168          else if( !lstrncmpi32A( "book", lpStr, 4) )
169          {
170            fi->fi_flags |= FI_FW_BOOK;
171            fi->df.dfWeight = FW_REGULAR;
172          }
173        }
174   else if( j == 5 )
175        {
176          if( !lstrncmpi32A( "light", lpStr, 5) )
177            fi->df.dfWeight = FW_LIGHT;
178          else if( !lstrncmpi32A( "black", lpStr, 5) )
179            fi->df.dfWeight = FW_BLACK;
180        }
181   else if( j == 6 && !lstrncmpi32A( "medium", lpStr, 6) )
182       fi->df.dfWeight = FW_REGULAR; 
183   else if( j == 8 && !lstrncmpi32A( "demibold", lpStr, 8) )
184       fi->df.dfWeight = FW_DEMIBOLD; 
185   else
186       fi->df.dfWeight = FW_DONTCARE; /* FIXME: try to get something
187                                       * from the weight property */
188 }
189
190 static int LFD_GetSlant( fontInfo* fi, LPSTR lpStr, int l)
191 {
192     if( l == 1 )
193     {
194         switch( tolower( *lpStr ) )
195         {
196             case '0':  fi->fi_flags |= FI_POLYSLANT;    /* haven't seen this one yet */
197             default:
198             case 'r':  fi->df.dfItalic = 0;
199                        break;
200             case 'o':
201                        fi->fi_flags |= FI_OBLIQUE;
202             case 'i':  fi->df.dfItalic = 1;
203                        break;
204         }
205         return 0;
206     }
207     return 1;
208 }
209
210 /*************************************************************************
211  *           LFD_InitFontInfo
212  *
213  * Fill in some fields in the fontInfo struct.
214  */
215 static int LFD_InitFontInfo( fontInfo* fi, LPSTR lpstr )
216 {
217    LPSTR        lpch;
218    int          i, j, dec_style_check, scalability;
219    UINT16       tmp[3];
220
221    memset(fi, 0, sizeof(fontInfo) );
222
223 /* weight name - */
224    lpch = LFD_Advance( lpstr, 1);
225    if( !*lpch ) return FALSE;
226    j = lpch - lpstr - 1;
227    LFD_GetWeight( fi, lpstr, j );
228
229 /* slant - */
230    lpch = LFD_Advance( lpstr = lpch, 1);
231    if( !*lpch ) return FALSE;
232    j = lpch - lpstr - 1;
233    dec_style_check = LFD_GetSlant( fi, lpstr, j );
234
235 /* width name - */
236    lpch = LFD_Advance( lpstr = lpch, 1);
237    if( !*lpch ) return FALSE;
238    if( lstrncmpi32A( "normal", lpstr, 6) )      /* XXX 'narrow', 'condensed', etc... */
239        dec_style_check = TRUE;
240    else
241        fi->fi_flags |= FI_NORMAL;
242
243 /* style - */
244    lpch = LFD_Advance( lpstr = lpch, 1);
245    if( !*lpch ) return FALSE;
246    j = lpch - lpstr - 1;
247    if( j > 3 )  /* find out is there "sans" or "script" */
248    {
249         j = 0;
250         *(lpch - 1) = '\0';
251
252         if( strstr(lpstr, "sans") ) 
253         { 
254             fi->df.dfPitchAndFamily |= FF_SWISS; 
255             j = 1; 
256         }
257         if( strstr(lpstr, "script") ) 
258         { 
259             fi->df.dfPitchAndFamily |= FF_SCRIPT; 
260             j = 1; 
261         }
262         if( !j && dec_style_check ) 
263             fi->df.dfPitchAndFamily |= FF_DECORATIVE;
264         *(lpch - 1) = LFDSeparator[1];
265    }
266
267 /* pixel height, decipoint height, and res_x */
268
269    for( i = scalability = 0; i < 3; i++ )
270    {
271      lpch = LFD_Advance( lpstr = lpch, 1);
272      if( !*lpch ) return FALSE;
273      if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
274
275     *(lpch - 1) = '\0';
276      if( !(tmp[i] = atoi(lpstr)) ) scalability++;
277     *(lpch - 1) = LFDSeparator[1];
278    }
279    if( scalability == 3 )       /* Type1 */
280    {
281      fi->fi_flags |= FI_SCALABLE;
282      fi->lfd_height = DEF_SCALABLE_HEIGHT; fi->lfd_decipoints = DEF_SCALABLE_DP;
283      fi->lfd_resolution = DefResolution;
284    }
285    else if( scalability == 0 )  /* Bitmap */
286    {
287      fi->lfd_height = tmp[0]; fi->lfd_decipoints = tmp[1]; 
288      fi->lfd_resolution = tmp[2];
289    }
290    else return FALSE; /* #$%^!!! X11R6 mutant garbage */
291
292 /* res_y - skip, spacing - */
293    lpstr = LFD_Advance( lpch, 1);
294    switch( *lpstr )
295    {
296      case '\0': return FALSE;
297
298      case 'p': fi->fi_flags |= FI_VARIABLEPITCH;
299                break;
300      case 'c': fi->df.dfPitchAndFamily |= FF_MODERN;
301                fi->fi_flags |= FI_FIXEDEX;
302                /* fall through */
303      case 'm': fi->fi_flags |= FI_FIXEDPITCH;
304                break;
305      default:
306                fi->df.dfPitchAndFamily |= DEFAULT_PITCH | FF_DONTCARE;
307    }
308    lpstr = LFD_Advance(lpstr, 1);
309    if( !*lpstr ) return FALSE;
310
311 /* average width - */
312    lpch = LFD_Advance( lpstr, 1);
313    if( !*lpch ) return FALSE;
314    if( lpch - lpstr == 1 || lpch - lpstr > 4 ) return FALSE; /* ridiculous */
315   *(lpch - 1) = '\0'; 
316    if( !(fi->lfd_width = atoi(lpstr)) && !scalability ) return FALSE;
317   *(lpch - 1) = LFDSeparator[1];
318
319 /* charset registry, charset encoding - */
320    if( strstr(lpch, "jisx") || strstr(lpch, "ksc") ) return FALSE;      /* 2-byte stuff */
321
322    if( strstr(lpch, iso8859Encoding) )
323    {
324      fi->fi_flags |= FI_ENC_ISO8859;
325      fi->df.dfCharSet = ANSI_CHARSET;
326    }
327    else if( strstr(lpch, iso646Encoding) )
328    {
329      fi->fi_flags |= FI_ENC_ISO646;
330      fi->df.dfCharSet = ANSI_CHARSET;
331    }
332    else if( strstr(lpch, ansiEncoding) )        /* font2bdf produces -ansi-0 LFD */
333    {
334      fi->fi_flags |= FI_ENC_ANSI;
335      fi->df.dfCharSet = ANSI_CHARSET;
336    }
337    else if( strstr(lpch, "fontspecific") )
338      fi->df.dfCharSet = SYMBOL_CHARSET;
339    else
340      fi->df.dfCharSet = OEM_CHARSET;            /* FIXME: -cp126-.. from fnt2bdf */
341    
342    return TRUE;                                 
343 }
344
345 /*************************************************************************
346  *           LFD_ComposeLFD
347  */
348 static BOOL32  LFD_ComposeLFD( fontObject* fo, 
349                                INT32 height, LPSTR lpLFD, UINT32 uRelax )
350 {
351    int          h, w, ch, point = 0;
352    char*        lpch; 
353    const char*  lpEncoding = NULL;
354
355    lstrcpy32A( lpLFD, fo->fr->resource );
356
357 /* add weight */
358    switch( fo->fi->df.dfWeight )
359    {
360         case FW_BOLD:
361                 strcat( lpLFD, "bold" ); break;
362         case FW_REGULAR:
363                 if( fo->fi->fi_flags & FI_FW_BOOK )
364                     strcat( lpLFD, "book" );
365                 else
366                     strcat( lpLFD, "medium" );
367                 break;
368         case FW_DEMIBOLD:
369                 strcat( lpLFD, "demi" );
370                 if( !( fo->fi->fi_flags & FI_FW_DEMI) )
371                      strcat ( lpLFD, "bold" );
372                 break;
373         case FW_BLACK:
374                 strcat( lpLFD, "black" ); break;
375         case FW_LIGHT:
376                 strcat( lpLFD, "light" ); break;
377         default:
378                 strcat( lpLFD, "*" );
379    }
380
381 /* add slant */
382    if( fo->fi->df.dfItalic )
383        if( fo->fi->fi_flags & FI_OBLIQUE )
384            strcat( lpLFD, "-o" );
385        else
386            strcat( lpLFD, "-i" );
387    else 
388        strcat( lpLFD, (uRelax < 4) ? "-r" : "-*" );
389
390 /* add width style and skip serifs */
391    if( fo->fi->fi_flags & FI_NORMAL )
392        strcat( lpLFD, "-normal-*-");
393    else
394        strcat( lpLFD, "-*-*-" );
395
396 /* add pixelheight, pointheight, and resolution 
397  *
398  * FIXME: fill in lpXForm and lpPixmap for rotated fonts
399  */
400    if( fo->fo_flags & FO_SYNTH_HEIGHT ) h = fo->fi->lfd_height;
401    else h = (fo->fi->lfd_height * height) / fo->fi->df.dfPixHeight;
402
403    if( fo->lf.lfWidth && (XTextCaps & TC_SF_X_YINDEP) 
404                       && !(fo->fo_flags & FO_SYNTH_WIDTH) )
405        point = (fo->fi->lfd_decipoints * fo->lf.lfWidth) / fo->fi->df.dfAvgWidth;
406
407 /* spacing and width */
408
409    if( fo->fi->fi_flags & FI_FIXEDPITCH ) 
410        w = ( fo->fi->fi_flags & FI_FIXEDEX ) ? 'c' : 'm';
411    else 
412        w = ( fo->fi->fi_flags & FI_VARIABLEPITCH ) ? 'p' : LFDSeparator[0]; 
413
414 /* encoding, not quite there yet */
415
416    if( fo->fi->df.dfCharSet == ANSI_CHARSET )
417    {
418         if( fo->fi->fi_flags & FI_ENC_ISO8859 )
419              lpEncoding = iso8859Encoding;
420         else if( fo->fi->fi_flags & FI_ENC_ISO646 )
421              lpEncoding = iso646Encoding;
422         else lpEncoding = ansiEncoding;
423    } else    lpEncoding = LFDSeparator;
424
425    lpch = lpLFD + lstrlen32A(lpLFD);
426    ch = (fo->fi->fi_flags & FI_SCALABLE) ? '0' : LFDSeparator[0];
427
428    switch( uRelax )
429    {
430        /* RealizeFont() will call us repeatedly with increasing uRelax 
431         * until XLoadFont() succeeds. */
432
433        case 0: 
434             if( point )
435             {
436                 sprintf( lpch, "%i-%i-%i-%c-%c-*-%s*", h, point, 
437                          fo->fi->lfd_resolution, ch, w, lpEncoding );
438                 break;
439             }
440             /* fall through */
441
442        case 1: 
443             sprintf( lpch, "%i-*-%i-%c-%c-*-%s*", h, 
444                         fo->fi->lfd_resolution, ch, w, lpEncoding );
445             break;
446
447        case 2:
448             sprintf( lpch, "%i-*-%i-%c-*-*-%s*",
449                         h, fo->fi->lfd_resolution, ch, lpEncoding );
450             break;
451
452        case 3:
453             sprintf( lpch, "%i-*-%i-%c-*-*-%s*", fo->fi->lfd_height,
454                         fo->fi->lfd_resolution, ch, lpEncoding );
455             break;
456
457        default:
458             sprintf( lpch, "%i-*-*-*-*-*-%s*", fo->fi->lfd_height, lpEncoding );
459    }
460
461    dprintf_font(stddeb,"\tLFD: %s\n", lpLFD );
462    return TRUE;
463 }
464
465
466 /***********************************************************************
467  *              X Font Resources
468  *
469  * font info            - http://www.microsoft.com/kb/articles/q65/1/23.htm
470  * Windows font metrics - http://www.microsoft.com/kb/articles/q32/6/67.htm
471  */
472 static BOOL32 XFONT_GetLeading( LPIFONTINFO16 pFI, XFontStruct* x_fs, INT32* pIL, INT32* pEL )
473 {
474     unsigned long height;
475     unsigned min = (unsigned char)pFI->dfFirstChar;
476     unsigned max = (unsigned char)pFI->dfLastChar;
477     BOOL32 bHaveCapHeight = (pFI->dfCharSet == ANSI_CHARSET && 'X' >= min && 'X' <= max );
478
479     if( pEL ) *pEL = 0;
480     if( XGetFontProperty(x_fs, XA_CAP_HEIGHT, &height) == False )
481     {
482         if( x_fs->per_char )
483             if( bHaveCapHeight )
484                 height = x_fs->per_char['X' - min].ascent;
485             else
486                 if (x_fs->ascent >= x_fs->max_bounds.ascent)
487                     height = x_fs->max_bounds.ascent;
488                 else
489                 {
490                     height = x_fs->ascent;
491                     if( pEL )
492                         *pEL = x_fs->max_bounds.ascent - height;
493                 }
494         else 
495             height = x_fs->min_bounds.ascent;
496     }
497
498    *pIL = x_fs->ascent - height;
499     return (bHaveCapHeight && x_fs->per_char);
500 }
501
502 static INT32 XFONT_GetAvgCharWidth( LPIFONTINFO16 pFI, XFontStruct* x_fs)
503 {
504     unsigned min = (unsigned char)pFI->dfFirstChar;
505     unsigned max = (unsigned char)pFI->dfLastChar;
506
507     if( x_fs->per_char )
508     {
509         int  width, chars, j;
510         for( j = 0, width = 0, chars = 0, max -= min; j <= max; j++ )
511             if( !CI_NONEXISTCHAR(x_fs->per_char + j) )
512             {
513                 width += x_fs->per_char[j].width;
514                 chars++;
515             }
516         return (width / chars);
517     }
518     /* uniform width */
519     return x_fs->min_bounds.width;
520 }
521
522 /***********************************************************************
523  *              XFONT_SetFontMetric
524  *
525  * Initializes IFONTINFO16. dfHorizRes and dfVertRes must be already set.
526  */
527 static void XFONT_SetFontMetric(fontInfo* fi, fontResource* fr, XFontStruct* xfs)
528 {
529     unsigned     min, max;
530     INT32        el, il;
531
532     fi->df.dfFirstChar = (BYTE)(min = xfs->min_char_or_byte2);
533     fi->df.dfLastChar = (BYTE)(max = xfs->max_char_or_byte2);
534
535     fi->df.dfDefaultChar = (BYTE)xfs->default_char;
536     fi->df.dfBreakChar = (BYTE)(( ' ' < min || ' ' > max) ? xfs->default_char: ' ');
537
538     fi->df.dfPixHeight = (INT16)((fi->df.dfAscent = (INT16)xfs->ascent) + xfs->descent);
539     fi->df.dfPixWidth = (xfs->per_char) ? 0 : xfs->min_bounds.width;
540     fi->df.dfMaxWidth = (INT16)abs(xfs->max_bounds.width);
541
542     if( XFONT_GetLeading( &fi->df, xfs, &il, &el ) )
543         fi->df.dfAvgWidth = (INT16)xfs->per_char['X' - min].width;
544     else
545         fi->df.dfAvgWidth = (INT16)XFONT_GetAvgCharWidth( &fi->df, xfs);
546
547     fi->df.dfInternalLeading = (INT16)il;
548     fi->df.dfExternalLeading = (INT16)el;
549
550     fi->df.dfPoints = (INT16)(((INT32)(fi->df.dfPixHeight - 
551                                        fi->df.dfInternalLeading) * 72) / fi->df.dfVertRes);
552
553     if( xfs->min_bounds.width != xfs->max_bounds.width )
554         fi->df.dfPitchAndFamily |= TMPF_FIXED_PITCH; /* au contraire! */
555     if( fi->fi_flags & FI_SCALABLE ) 
556     {
557         fi->df.dfType = DEVICE_FONTTYPE;
558         fi->df.dfPitchAndFamily |= TMPF_DEVICE;
559     } 
560     else if( fi->fi_flags & FI_TRUETYPE )
561         fi->df.dfType = TRUETYPE_FONTTYPE;
562     else
563         fi->df.dfType = RASTER_FONTTYPE;
564
565     fi->df.dfFace = fr->lfFaceName;
566 }
567
568 /***********************************************************************
569  *              XFONT_GetTextMetric
570  */
571 static void XFONT_GetTextMetric( fontObject* pfo, LPTEXTMETRIC32A pTM )
572 {
573     LPIFONTINFO16 pdf = &pfo->fi->df;
574
575     pTM->tmAscent = pfo->fs->ascent;
576     pTM->tmDescent = pfo->fs->descent;
577     pTM->tmHeight = pTM->tmAscent + pTM->tmDescent;
578
579     pTM->tmAveCharWidth = pfo->foAvgCharWidth;
580     pTM->tmMaxCharWidth = abs(pfo->fs->max_bounds.width);
581
582     pTM->tmInternalLeading = pfo->foInternalLeading;
583     pTM->tmExternalLeading = pdf->dfExternalLeading;
584
585     pTM->tmStruckOut = (pfo->fo_flags & FO_SYNTH_STRIKEOUT )
586                         ? 1 : pdf->dfStrikeOut;
587     pTM->tmUnderlined = (pfo->fo_flags & FO_SYNTH_UNDERLINE )
588                         ? 1 : pdf->dfUnderline;
589
590     pTM->tmOverhang = 0;
591     if( pfo->fo_flags & FO_SYNTH_ITALIC ) 
592     {
593         pTM->tmOverhang += pTM->tmHeight/3;
594         pTM->tmItalic = 1;
595     } else 
596         pTM->tmItalic = pdf->dfItalic;
597
598     pTM->tmWeight = pdf->dfWeight;
599     if( pfo->fo_flags & FO_SYNTH_BOLD ) 
600     {
601         pTM->tmOverhang++; 
602         pTM->tmWeight += 100;
603     } 
604
605     *(INT32*)&pTM->tmFirstChar = *(INT32*)&pdf->dfFirstChar;
606
607     pTM->tmCharSet = pdf->dfCharSet;
608     pTM->tmPitchAndFamily = pdf->dfPitchAndFamily;
609     pTM->tmDigitizedAspectX = pdf->dfHorizRes;
610     pTM->tmDigitizedAspectY = pdf->dfVertRes;
611 }
612
613 /***********************************************************************
614  *              XFONT_GetFontMetric
615  *
616  * Retrieve font metric info (enumeration).
617  */
618 static UINT32 XFONT_GetFontMetric( fontInfo* pfi, LPENUMLOGFONTEX16 pLF,
619                                                   LPNEWTEXTMETRIC16 pTM )
620 {
621     memset( pLF, 0, sizeof(*pLF) );
622     memset( pTM, 0, sizeof(*pTM) );
623
624 #define plf ((LPLOGFONT16)pLF)
625     plf->lfHeight    = pTM->tmHeight       = pfi->df.dfPixHeight;
626     plf->lfWidth     = pTM->tmAveCharWidth = pfi->df.dfAvgWidth;
627     plf->lfWeight    = pTM->tmWeight       = pfi->df.dfWeight;
628     plf->lfItalic    = pTM->tmItalic       = pfi->df.dfItalic;
629     plf->lfUnderline = pTM->tmUnderlined   = pfi->df.dfUnderline;
630     plf->lfStrikeOut = pTM->tmStruckOut    = pfi->df.dfStrikeOut;
631     plf->lfCharSet   = pTM->tmCharSet      = pfi->df.dfCharSet;
632
633     /* convert pitch values */
634
635     pTM->tmPitchAndFamily = pfi->df.dfPitchAndFamily;
636     plf->lfPitchAndFamily = (pfi->df.dfPitchAndFamily & 0xF1) + 1;
637
638     lstrcpyn32A( plf->lfFaceName, pfi->df.dfFace, LF_FACESIZE );
639 #undef plf
640
641     pTM->tmAscent = pfi->df.dfAscent;
642     pTM->tmDescent = pTM->tmHeight - pTM->tmAscent;
643     pTM->tmInternalLeading = pfi->df.dfInternalLeading;
644     pTM->tmMaxCharWidth = pfi->df.dfMaxWidth;
645     pTM->tmDigitizedAspectX = pfi->df.dfHorizRes;
646     pTM->tmDigitizedAspectY = pfi->df.dfVertRes;
647
648     *(INT32*)&pTM->tmFirstChar = *(INT32*)&pfi->df.dfFirstChar;
649
650     /* return font type */
651
652     return pfi->df.dfType;
653 }
654
655
656 /***********************************************************************
657  *           XFONT_FixupFlags
658  * 
659  * dfPitchAndFamily flags for some common typefaces.
660  */
661 static BYTE XFONT_FixupFlags( LPCSTR lfFaceName )
662 {
663    switch( lfFaceName[0] )
664    {
665         case 'h':
666         case 'H': if(!lstrcmpi32A(lfFaceName, "Helvetica") )
667                     return FF_SWISS;
668                   break;
669         case 'c':
670         case 'C': if(!lstrcmpi32A(lfFaceName, "Courier") )
671                     return FF_ROMAN;
672                   break;
673         case 'p':
674         case 'P': if( !lstrcmpi32A(lfFaceName,"Palatino") )
675                     return FF_ROMAN;
676                   break;
677         case 't':
678         case 'T': if(!lstrncmpi32A(lfFaceName, "Times", 5) )
679                     return FF_ROMAN;
680                   break;
681         case 'u':
682         case 'U': if(!lstrcmpi32A(lfFaceName, "Utopia") )
683                     return FF_ROMAN;
684                   break;
685         case 'z':
686         case 'Z': if(!lstrcmpi32A(lfFaceName, "Zapf Dingbats") )
687                     return FF_DECORATIVE;
688    }
689    return 0;
690 }
691
692
693 /***********************************************************************
694  *           XFONT_WindowsNames
695  *
696  * Build generic Windows aliases for X font names.
697  *
698  * -misc-fixed- -> "Fixed"
699  * -sony-fixed- -> "Sony Fixed", etc...
700  */
701 static void XFONT_WindowsNames( char* buffer )
702 {
703     fontResource* fr, *pfr;
704     char*       lpstr, *lpch;
705     int         i, up;
706     BYTE        bFamilyStyle;
707
708     for( fr = fontList; fr ; fr = fr->next )
709     {
710         if( fr->fr_flags & FR_NAMESET ) continue;     /* skip already assigned */
711
712         lpstr = LFD_Advance(fr->resource, 2);
713         i = lpstr - LFD_Advance( lpstr, 1 );
714
715         for( pfr = fontList; pfr != fr ; pfr = pfr->next )
716             if( pfr->fr_flags & FR_NAMESET )
717             {
718                 lpch = LFD_Advance(pfr->resource, 2);
719
720                 /* check if already have the same face name */
721
722                 if( !lstrncmp32A(lpch, lpstr, i) ) break;
723             }
724         if( pfr != fr )  /* prepend vendor name */
725             lpstr = fr->resource + 1;
726
727         for( i = 0, up = 1, lpch = fr->lfFaceName; *lpstr && i < 32;
728                                                 lpch++, lpstr++, i++ )
729         {
730             if( *lpstr == LFDSeparator[1] || *lpstr == ' ' ) 
731             { 
732                 *lpch = ' '; 
733                 up = 1; continue; 
734             }
735             else if( isalpha(*lpstr) && up )
736             { 
737                 *lpch = toupper(*lpstr); 
738                 up = 0; continue; 
739             }
740             *lpch = *lpstr;
741         }
742         while (*(lpch - 1) == ' ') *(--lpch) = '\0';
743
744         if( (bFamilyStyle = XFONT_FixupFlags( fr->lfFaceName )) )
745         {
746             fontInfo* fi;
747             for( fi = fr->fi ; fi ; fi = fi->next )
748                 fi->df.dfPitchAndFamily |= bFamilyStyle;
749         }
750
751 #ifdef DEBUG_FONT_INIT
752         dprintf_font(stddeb,"typeface \'%s\'\n", fr->lfFaceName);
753 #endif
754         fr->fr_flags |= FR_NAMESET;
755     }
756
757     if( PROFILE_GetWineIniString( INIFontSection, INIDefault, "", buffer, 128 ) )
758     {
759         while( *buffer && isspace(*buffer) ) buffer++;
760         for( fr = NULL, pfr = fontList; pfr; pfr = pfr->next )
761         {
762              i = lstrlen32A( pfr->resource );
763              if( !lstrncmpi32A( pfr->resource, buffer, i) )
764              {
765                  if( fr )
766                  {
767                      fr->next = pfr->next;
768                      pfr->next = fontList;
769                      fontList = pfr;
770                  }
771                  break;
772              }
773              fr = pfr;
774         }
775     }
776 }
777
778 /***********************************************************************
779  *           XFONT_CreateAlias
780  */
781 static fontAlias* XFONT_CreateAlias( LPCSTR lpTypeFace, LPCSTR lpAlias )
782 {
783     fontAlias* pfa = aliasTable;
784     int j = lstrlen32A(lpTypeFace) + 1;
785
786     while( pfa->next ) pfa = pfa->next;
787     pfa->next = HeapAlloc( SystemHeap, 0, sizeof(fontAlias) +
788                                           j + lstrlen32A(lpAlias) + 1 );
789     if((pfa = pfa->next))
790     {
791         pfa->next = NULL;
792         pfa->faTypeFace = (LPSTR)(pfa + 1);
793         lstrcpy32A( pfa->faTypeFace, lpTypeFace );
794         pfa->faAlias = pfa->faTypeFace + j;
795         lstrcpy32A( pfa->faAlias, lpAlias );
796
797 #ifdef DEBUG_FONT_INIT
798         dprintf_font(stddeb, "\tadded alias '%s' for %s\n", lpAlias, lpTypeFace );
799 #endif
800         return pfa;
801     }
802     return NULL;
803 }
804
805 /***********************************************************************
806  *           XFONT_LoadAliases
807  *
808  * Read user-defined aliases from wine.conf. Format is as follows
809  *
810  * Alias# = [Windows font name],[LFD font name], <substitute original name>
811  *
812  * Example:
813  *   Alias0 = Arial, -adobe-helvetica- 
814  *   Alias1 = Times New Roman, -bitstream-courier-, 1
815  *   ...
816  */
817 static void XFONT_LoadAliases( char** buffer, int buf_size )
818 {
819     char  subsection[32];
820     int   i = 0;
821
822     if( buf_size < 128 )
823         *buffer = HeapReAlloc(SystemHeap, 0, *buffer, 256 );
824     do
825     {
826         wsprintf32A( subsection, "%s%i", INISubSection, i++ );
827
828         if( PROFILE_GetWineIniString( INIFontSection, subsection, "", *buffer, 128 ) )
829         {
830             char* lpchX, *lpchW = *buffer;
831
832             while( isspace(*lpchW) ) lpchW++;
833             lpchX = PROFILE_GetStringItem( lpchW );
834
835             if( lpchX )
836             {
837                 fontResource* fr;
838
839                 for (fr = fontList; fr ; fr = fr->next)
840                 {
841                     int j;
842
843                     j = lstrlen32A( fr->resource );
844
845                     if( !lstrncmpi32A( fr->resource, lpchX, j) )
846                     {
847                         char* lpch = PROFILE_GetStringItem( lpchX );
848
849                         if( lpch )
850                         {
851 #ifdef DEBUG_FONT_INIT
852                             dprintf_font(stddeb, "\tsubstituted '%s' with %s\n",
853                                                         fr->lfFaceName, lpchW );
854 #endif
855                             lstrcpyn32A( fr->lfFaceName, lpchW, LF_FACESIZE );
856                             fr->fr_flags |= FR_NAMESET;
857                         }
858                         else
859                         {
860                             /* create new entry in the alias table */
861                             XFONT_CreateAlias(fr->lfFaceName, lpchW);
862                         }
863                         break;
864                     }
865                 }
866             }
867             else fprintf(stderr, "XFONT_Init: malformed font alias '%s'\n", *buffer );
868         }
869         else break;
870     } while(TRUE);
871 }
872
873 /***********************************************************************
874  *           XFONT_UserMetricsCache
875  * 
876  * Returns expanded name for the ~/.wine/.cachedmetrics file.
877  */
878 static char* XFONT_UserMetricsCache( char* buffer, int* buf_size )
879 {
880     struct passwd* pwd;
881
882     pwd = getpwuid(getuid());
883     if( pwd && pwd->pw_dir )
884     {
885         int i = lstrlen32A( pwd->pw_dir ) + lstrlen32A( INIWinePrefix ) + lstrlen32A( INIFontMetrics ) + 2;
886         if( i > *buf_size ) buffer = (char*) HeapReAlloc( SystemHeap, 0, buffer, *buf_size = i );
887         lstrcpy32A( buffer, pwd->pw_dir );
888         strcat( buffer, INIWinePrefix );
889         strcat( buffer, INIFontMetrics );
890     } else buffer[0] = '\0';
891     return buffer;
892 }
893
894
895 /***********************************************************************
896  *           XFONT_ReadCachedMetrics
897  */
898 static BOOL32 XFONT_ReadCachedMetrics( int fd, unsigned x_checksum, int x_count )
899 {
900     if( fd >= 0 )
901     {
902         unsigned u;
903         int i, j;
904
905         /* read checksums */
906         read( fd, &u, sizeof(unsigned) );
907         read( fd, &i, sizeof(int) );
908
909         if( u == x_checksum && i == x_count )
910         {
911             off_t length, offset = 3 * sizeof(int);
912
913             /* read total size */
914             read( fd, &i, sizeof(int) );
915             length = lseek( fd, 0, SEEK_END );
916
917             if( length == (i + offset) )
918             {
919                 lseek( fd, offset, SEEK_SET );
920                 fontList = (fontResource*)HeapAlloc( SystemHeap, 0, i);
921                 if( fontList )
922                 {
923                     fontResource*       pfr = fontList;
924                     fontInfo*           pfi = NULL;
925
926                     dprintf_font(stddeb,"Reading cached font metrics:\n");
927
928                     read( fd, fontList, i); /* read all metrics at once */
929                     while( offset < length )
930                     {
931                         offset += sizeof(fontResource) + sizeof(fontInfo);
932                         pfr->fi = pfi = (fontInfo*)(pfr + 1);
933                         j = 1;
934                         while( TRUE )
935                         {
936                            if( offset > length ||
937                               (int)(pfi->next) != j++ ) goto fail;
938
939                            pfi->df.dfFace = pfr->lfFaceName;
940                            pfi->next = pfi + 1;
941
942                            if( j > pfr->count ) break;
943
944                            pfi = pfi->next;
945                            offset += sizeof(fontInfo);
946                         }
947                         pfi->next = NULL;
948                         if( pfr->next )
949                         {
950                             pfr->next = (fontResource*)(pfi + 1);
951                             pfr = pfr->next;
952                         } 
953                         else break;
954                     }
955                     if( pfr->next == NULL &&
956                         *(int*)(pfi + 1) == X_FMC_MAGIC )
957                     {
958                         /* read LFD stubs */
959                         char* lpch = (char*)((int*)(pfi + 1) + 1);
960                         offset += sizeof(int);
961                         for( pfr = fontList; pfr; pfr = pfr->next )
962                         {
963                             dprintf_font(stddeb,"\t%s, %i instances\n", lpch, pfr->count );
964                             pfr->resource = lpch;
965                             while( TRUE )
966                             { 
967                                 if( ++offset > length ) goto fail;
968                                 if( !*lpch++ ) break;
969                             }
970                         }
971                         close( fd );
972                         return TRUE;
973                     }
974                 }
975             }
976         }
977 fail:
978         if( fontList ) HeapFree( SystemHeap, 0, fontList );
979         fontList = NULL;
980         close( fd );
981     }
982     return FALSE;
983 }
984
985 /***********************************************************************
986  *           XFONT_WriteCachedMetrics
987  */
988 static BOOL32 XFONT_WriteCachedMetrics( int fd, unsigned x_checksum, int x_count, int n_ff )
989 {
990     fontResource* pfr;
991     fontInfo* pfi;
992
993     if( fd >= 0 )
994     {
995         int  i, j, k;
996
997         /* font metrics file:
998          *
999          * +0000 x_checksum
1000          * +0004 x_count
1001          * +0008 total size to load
1002          * +000C prepackaged font metrics
1003          * ...
1004          * +...x        X_FMC_MAGIC
1005          * +...x + 4    LFD stubs
1006          */
1007
1008         write( fd, &x_checksum, sizeof(unsigned) );
1009         write( fd, &x_count, sizeof(int) );
1010
1011         for( j = i = 0, pfr = fontList; pfr; pfr = pfr->next ) 
1012         {
1013             i += lstrlen32A( pfr->resource ) + 1;
1014             j += pfr->count;
1015         }
1016         i += n_ff * sizeof(fontResource) + j * sizeof(fontInfo) + sizeof(int);
1017         write( fd, &i, sizeof(int) );
1018
1019         dprintf_font(stddeb,"Writing font cache:\n");
1020
1021         for( pfr = fontList; pfr; pfr = pfr->next )
1022         {
1023             fontInfo fi;
1024
1025             dprintf_font(stddeb,"\t%s, %i instances\n", pfr->resource, pfr->count );
1026
1027             i = write( fd, pfr, sizeof(fontResource) );
1028             if( i == sizeof(fontResource) ) 
1029             {
1030                 for( k = 1, pfi = pfr->fi; pfi; pfi = pfi->next )
1031                 {
1032                     memcpy( &fi, pfi, sizeof(fi) );
1033
1034                     fi.df.dfFace = NULL;
1035                     fi.next = (fontInfo*)k;     /* loader checks this */
1036
1037                     j = write( fd, &fi, sizeof(fi) );
1038                     k++;
1039                 }
1040                 if( j == sizeof(fontInfo) ) continue;
1041             }
1042             break;
1043         }
1044         if( i == sizeof(fontResource) && j == sizeof(fontInfo) )
1045         {
1046             i = j = X_FMC_MAGIC;
1047             write( fd, &i, sizeof(int) );
1048             for( pfr = fontList; pfr && i == j; pfr = pfr->next )
1049             {
1050                 i = lstrlen32A( pfr->resource ) + 1;
1051                 j = write( fd, pfr->resource, i );
1052             }
1053         }
1054         close( fd );
1055         return ( i == j );
1056     }
1057     return TRUE;
1058 }
1059
1060 /***********************************************************************
1061  *           X11DRV_FONT_Init
1062  *
1063  * Initialize font resource list and allocate font cache.
1064  */
1065 BOOL32 X11DRV_FONT_Init( DeviceCaps* pDevCaps )
1066 {
1067   XFontStruct*  x_fs;
1068   fontResource* fr, *pfr;
1069   fontInfo*     fi, *pfi;
1070   unsigned      x_checksum;
1071   int           i, j, k, x_count, fd = -1, buf_size = 0;
1072   char*         lpstr, *lpch, *lpmetrics, *buffer;
1073   char**        x_pattern;
1074
1075   DefResolution = PROFILE_GetWineIniInt( INIFontSection, "Resolution", 0 );
1076   if( !DefResolution ) DefResolution = pDevCaps->logPixelsY;
1077
1078   i = abs(DefResolution - 72);
1079   j = abs(DefResolution - 75);
1080   k = abs(DefResolution - 100);
1081
1082   if( i < j ) DefResolution = ( i < k ) ? 72 : 100;
1083   else DefResolution = ( j < k ) ? 75 : 100;
1084       
1085   x_pattern = XListFonts(display, "*", MAX_FONT_FAMILIES * 16, &x_count );
1086
1087   dprintf_font(stddeb,"Font Mapper: initializing %i fonts [LPY=%i, DR=%i]\n", 
1088                                     x_count, pDevCaps->logPixelsY, DefResolution);
1089   for( i = x_checksum = 0; i < x_count; i++ )
1090   {
1091 #if 0
1092      printf("%i\t: %s\n", i, x_pattern[i] );
1093 #endif
1094
1095      j = lstrlen32A( x_pattern[i] );
1096      if( j ) x_checksum ^= __genericCheckSum( (UINT16*)(x_pattern[i]), j );
1097   }
1098   x_checksum |= X_PFONT_MAGIC;
1099
1100   buf_size = 128;
1101   buffer = HeapAlloc( SystemHeap, 0, buf_size );
1102   lpmetrics = NULL;
1103
1104   /* deal with systemwide font metrics cache */
1105
1106   if( PROFILE_GetWineIniString( INIFontSection, "FontMetrics", "", buffer, 128 ) )
1107       fd = open( buffer, O_RDONLY );
1108
1109   if( XFONT_ReadCachedMetrics(fd, x_checksum, x_count) == FALSE )
1110   {
1111       /* try per-user */
1112       buffer = XFONT_UserMetricsCache( buffer, &buf_size );
1113       if( buffer[0] )
1114       {
1115           fd = open( buffer, O_RDONLY );
1116           if( XFONT_ReadCachedMetrics(fd, x_checksum, x_count) == FALSE )
1117               lpmetrics = HEAP_strdupA( SystemHeap, 0, buffer ); /* update later on */
1118       }
1119   }
1120
1121   fi = NULL;
1122   if( fontList == NULL )        /* build metrics from scratch */
1123   {
1124      int n_ff;
1125      char* typeface;
1126
1127      for( i = n_ff = 0; i < x_count; i++ )
1128      {
1129         typeface = lpch = x_pattern[i];
1130
1131         lpch = LFD_Advance(typeface, 3); /* extra '-' in the beginning */
1132         if( !*lpch ) continue;
1133
1134         lpstr = lpch; 
1135         j = lpch - typeface;    /* resource name length */
1136
1137         /* find a family to insert into */
1138
1139         for( pfr = NULL, fr = fontList; fr; fr = fr->next )
1140         {
1141            if( !lstrncmpi32A(fr->resource, typeface, j) && 
1142                lstrlen32A(fr->resource) == j ) break;
1143            pfr = fr;
1144         }  
1145
1146         if( !fi ) fi = (fontInfo*) HeapAlloc(SystemHeap, 0, sizeof(fontInfo));
1147
1148         if( !fr ) /* add new family */
1149         {
1150            if( n_ff++ > MAX_FONT_FAMILIES ) break;
1151
1152            if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1153
1154            fr = (fontResource*) HeapAlloc(SystemHeap, 0, sizeof(fontResource)); 
1155            memset(fr, 0, sizeof(fontResource));
1156            fr->resource = (char*) HeapAlloc(SystemHeap, 0, j + 1 );
1157            lstrcpyn32A( fr->resource, typeface, j + 1 );
1158
1159 #ifdef DEBUG_FONT_INIT
1160            dprintf_font(stddeb,"    family: %s\n", fr->resource );
1161 #endif
1162
1163            if( pfr ) pfr->next = fr;
1164            else fontList = fr;
1165         }
1166         else if( !LFD_InitFontInfo( fi, lpstr) ) continue;
1167
1168         /* check if we already have something better than "fi" */
1169
1170         for( pfi = fr->fi, j = 0; pfi && j <= 0; pfi = pfi->next ) 
1171            if( (j = XFONT_IsSubset( pfi, fi )) < 0 ) 
1172                pfi->fi_flags |= FI_SUBSET; /* superseded by "fi" */
1173         if( j > 0 ) continue;
1174
1175         /* add new font instance "fi" to the "fr" font resource */
1176
1177         if( fi->fi_flags & FI_SCALABLE )
1178         {
1179             /* set scalable font height to 24 to get an origin for extrapolation */
1180
1181            j = lstrlen32A(typeface);  j += 0x10;
1182            if( j > buf_size ) 
1183                buffer = (char*)HeapReAlloc( SystemHeap, 0, buffer, buf_size = j );
1184
1185            lpch = LFD_Advance(typeface, 7);
1186            memcpy( buffer, typeface, (j = lpch - typeface) );
1187            lpch = LFD_Advance(lpch, 4);
1188            sprintf( buffer + j, "%d-%d-%d-*-%c-*-", fi->lfd_height,
1189                             fi->lfd_decipoints, fi->lfd_resolution,
1190                                         (*lpch == '-')?'*':*lpch );
1191            lpch = LFD_Advance(lpch, 2);
1192            strcat( lpstr = buffer, lpch);
1193         }
1194         else lpstr = typeface;
1195
1196         if( (x_fs = XLoadQueryFont(display, lpstr)) )
1197         {
1198            fi->df.dfHorizRes = pDevCaps->logPixelsX;
1199            fi->df.dfVertRes = pDevCaps->logPixelsY;
1200
1201            XFONT_SetFontMetric( fi, fr, x_fs );
1202            XFreeFont( display, x_fs );
1203
1204 #ifdef DEBUG_FONT_INIT
1205            dprintf_font(stddeb,"\t[% 2ipt] '%s'\n", fi->df.dfPoints, typeface );
1206 #endif
1207            XFONT_CheckFIList( fr, fi, REMOVE_SUBSETS );
1208            fi = NULL;   /* preventing reuse */
1209         }
1210         else
1211         {
1212            fprintf(stderr, "FONT_Init: failed to load %s\n", lpstr );
1213
1214            XFONT_CheckFIList( fr, fi, UNMARK_SUBSETS );
1215         }
1216      }
1217
1218      if( lpmetrics )     /* update cached metrics */
1219      {
1220          fd = open( lpmetrics, O_CREAT | O_TRUNC | O_RDWR, 0644 ); /* -rw-r--r-- */
1221          if( XFONT_WriteCachedMetrics( fd, x_checksum, x_count, n_ff ) == FALSE )
1222              if( fd ) remove( lpmetrics );      /* couldn't write entire file */
1223          HeapFree( SystemHeap, 0, lpmetrics );
1224      }
1225   }
1226
1227   if( fi ) HeapFree(SystemHeap, 0, fi);
1228   XFreeFontNames(x_pattern);
1229
1230   /* check if we're dealing with X11 R6 server */
1231
1232   lstrcpy32A(buffer, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
1233   if( (x_fs = XLoadQueryFont(display, buffer)) )
1234   {
1235        XTextCaps |= TC_SF_X_YINDEP;
1236        XFreeFont(display, x_fs);
1237   }
1238
1239   XFONT_WindowsNames( buffer );
1240   XFONT_LoadAliases( &buffer, buf_size );
1241   HeapFree(SystemHeap, 0, buffer);
1242
1243
1244   /* fontList initialization is over, allocate X font cache */
1245
1246   fontCache = (fontObject*) HeapAlloc(SystemHeap, 0, fontCacheSize * sizeof(fontObject));
1247   XFONT_GrowFreeList(0, fontCacheSize - 1);
1248
1249 #ifdef DEBUG_FONT_INIT
1250         dprintf_font(stddeb,"done!\n");
1251 #endif
1252
1253   /* update text caps parameter */
1254
1255   pDevCaps->textCaps = XTextCaps;
1256   return TRUE;
1257 }
1258
1259
1260 /***********************************************************************
1261  *           X Font Matching
1262  *
1263  * Compare two fonts (only parameters set by the XFONT_InitFontInfo()).
1264  */
1265 static INT32 XFONT_IsSubset(fontInfo* match, fontInfo* fi)
1266 {
1267   INT32           m;
1268
1269   /* 0 - keep both, 1 - keep match, -1 - keep fi */
1270
1271   m = (BYTE*)&fi->df.dfPixWidth - (BYTE*)&fi->df.dfItalic;
1272   if( memcmp(&match->df.dfItalic, &fi->df.dfItalic, m )) return 0;
1273
1274   if( (!((fi->fi_flags & FI_SCALABLE) + (match->fi_flags & FI_SCALABLE))
1275        && fi->lfd_height != match->lfd_height) ||
1276       (!((fi->fi_flags & FI_POLYWEIGHT) + (match->fi_flags & FI_POLYWEIGHT))
1277        && fi->df.dfWeight != match->df.dfWeight) ) return 0;
1278
1279   m = (int)(match->fi_flags & (FI_POLYWEIGHT | FI_SCALABLE)) -
1280       (int)(fi->fi_flags & (FI_SCALABLE | FI_POLYWEIGHT));
1281
1282   if( m == (FI_POLYWEIGHT - FI_SCALABLE) ||
1283       m == (FI_SCALABLE - FI_POLYWEIGHT) ) return 0;    /* keep both */
1284   else if( m >= 0 ) return 1;   /* 'match' is better */
1285
1286   return -1;                    /* 'fi' is better */
1287 }
1288
1289 /***********************************************************************
1290  *            XFONT_Match
1291  *
1292  * Compute the matching score between the logical font and the device font.
1293  *
1294  * contributions from highest to lowest:
1295  *      charset
1296  *      fixed pitch
1297  *      height
1298  *      family flags (only when the facename is not present)
1299  *      width
1300  *      weight, italics, underlines, strikeouts
1301  *
1302  * NOTE: you can experiment with different penalty weights to see what happens.
1303  * http://premium.microsoft.com/msdn/library/techart/f30/f34/f40/d4d/sa8bf.htm
1304  */
1305 static UINT32 XFONT_Match( fontMatch* pfm )
1306 {
1307    fontInfo*    pfi = pfm->pfi;         /* device font to match */
1308    LPLOGFONT16  plf = pfm->plf;         /* wanted logical font */
1309    UINT32       penalty = 0;
1310    BOOL32       bR6 = pfm->flags & FO_MATCH_XYINDEP;    /* from TextCaps */
1311    BOOL32       bScale = pfi->fi_flags & FI_SCALABLE;
1312    INT32        d, h;
1313
1314    dprintf_font( stddeb,"\t[ %-2ipt h=%-3i w=%-3i %s%s]", pfi->df.dfPoints,
1315                  pfi->df.dfPixHeight, pfi->df.dfAvgWidth,
1316                 (pfi->df.dfWeight > 400) ? "Bold " : "Normal ",
1317                 (pfi->df.dfItalic) ? "Italic" : "" );
1318
1319    pfm->flags = 0;
1320
1321    if( plf->lfCharSet != DEFAULT_CHARSET &&
1322        plf->lfCharSet != pfi->df.dfCharSet ) penalty += 0x200;
1323
1324    /* TMPF_FIXED_PITCH means exactly the opposite */
1325
1326    if( plf->lfPitchAndFamily & FIXED_PITCH ) 
1327    {
1328       if( pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH ) penalty += 0x100;
1329    }
1330    else if( !(pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH) ) penalty += 0x2;
1331
1332    if( plf->lfHeight > 0 )
1333        d = (h = pfi->df.dfPixHeight) - plf->lfHeight;
1334    else if( plf->lfHeight < -1 )
1335        d = (h = pfi->df.dfPoints) + plf->lfHeight;
1336    else d = h = 0;      
1337
1338    if( d && plf->lfHeight )
1339    {
1340        UINT16   height = ( plf->lfHeight > 0 ) ? plf->lfHeight
1341                          : ((-plf->lfHeight * pfi->df.dfPixHeight) / h);
1342        if( bScale ) pfm->height = height;
1343        else if( (plf->lfQuality != PROOF_QUALITY) && bR6 )
1344        {
1345            if( d > 0 )  /* do not shrink raster fonts */
1346            {
1347                pfm->height = pfi->df.dfPixHeight;
1348                penalty += (pfi->df.dfPixHeight - height) * 0x4;
1349            }
1350            else         /* expand only in integer multiples */
1351            {
1352                pfm->height = height - height%pfi->df.dfPixHeight;
1353                penalty += (height - pfm->height) * pfm->height / height;
1354            }
1355        }
1356        else /* can't be scaled at all */
1357        {
1358            if( plf->lfQuality != PROOF_QUALITY) pfm->flags |= FO_SYNTH_HEIGHT;
1359            pfm->height = pfi->df.dfPixHeight;
1360            penalty += (d > 0)? d * 0x8 : -d * 0x10;
1361        }
1362    } else pfm->height = pfi->df.dfPixHeight;
1363
1364    if((pfm->flags & FO_MATCH_PAF) &&
1365       (plf->lfPitchAndFamily & FF_FAMILY) != (pfi->df.dfPitchAndFamily & FF_FAMILY) )
1366        penalty += 0x10;
1367
1368    if( plf->lfWidth )
1369    {
1370        if( bR6 && bScale ) h = 0; 
1371        else
1372        {
1373            /* FIXME: not complete */
1374
1375            pfm->flags |= FO_SYNTH_WIDTH;
1376            h = abs(plf->lfWidth - (pfm->height * pfi->df.dfAvgWidth)/pfi->df.dfPixHeight);
1377        }
1378        penalty += h * ( d ) ? 0x2 : 0x1 ;
1379    }
1380    else if( !(pfi->fi_flags & FI_NORMAL) ) penalty++;
1381
1382    if( pfi->lfd_resolution != DefResolution ) penalty++;
1383
1384    if( plf->lfWeight != FW_DONTCARE )
1385    {
1386        penalty += abs(plf->lfWeight - pfi->df.dfWeight) / 40;
1387        if( plf->lfWeight > pfi->df.dfWeight ) pfm->flags |= FO_SYNTH_BOLD;
1388    } else if( pfi->df.dfWeight >= FW_BOLD ) penalty++;  /* choose normal by default */
1389
1390    if( plf->lfItalic != pfi->df.dfItalic )
1391    {
1392        penalty += 0x4;
1393        pfm->flags |= FO_SYNTH_ITALIC;
1394    }
1395
1396    if( plf->lfUnderline ) pfm->flags |= FO_SYNTH_UNDERLINE;
1397    if( plf->lfStrikeOut ) pfm->flags |= FO_SYNTH_STRIKEOUT;
1398
1399    dprintf_font(stddeb,"-> %i\n", penalty );
1400
1401    return penalty;
1402 }
1403
1404 /***********************************************************************
1405  *            XFONT_MatchFIList
1406  *
1407  * Scan a particular font resource for the best match.
1408  */
1409 static UINT32 XFONT_MatchFIList( fontMatch* pfm )
1410 {
1411   BOOL32        skipRaster = (pfm->flags & FO_MATCH_NORASTER);
1412   UINT32        current_score, score = (UINT32)(-1);
1413   fontMatch     fm = *pfm;
1414
1415   for( fm.pfi = pfm->pfr->fi; fm.pfi && score; fm.pfi = fm.pfi->next )
1416   {
1417      if( skipRaster && !(fm.pfi->fi_flags & FI_SCALABLE) )
1418          continue;
1419
1420      current_score = XFONT_Match( &fm );
1421      if( score > current_score )
1422      {
1423         memcpy( pfm, &fm, sizeof(fontMatch) );
1424         score = current_score;
1425      }
1426   }
1427   return score;
1428 }
1429
1430 /***********************************************************************
1431  *            XFONT_CheckAliasTable
1432  */
1433 static LPSTR XFONT_CheckAliasTable( LPSTR lpAlias )
1434 {
1435     fontAlias* fa;
1436
1437     for( fa = aliasTable; fa; fa = fa->next )
1438         if( !lstrcmpi32A( fa->faAlias, lpAlias ) ) return fa->faTypeFace;
1439     return NULL;
1440 }
1441
1442 /***********************************************************************
1443  *            XFONT_CheckFIList
1444  *
1445  * REMOVE_SUBSETS - attach new fi and purge subsets
1446  * UNMARK_SUBSETS - remove subset flags from all fi entries
1447  */
1448 static void XFONT_CheckFIList( fontResource* fr, fontInfo* fi, int action)
1449 {
1450   int           i = 0;
1451   fontInfo*     pfi, *prev;
1452
1453   for( prev = NULL, pfi = fr->fi; pfi; )
1454   {
1455     if( action == REMOVE_SUBSETS )
1456     {
1457         if( pfi->fi_flags & FI_SUBSET )
1458         {
1459             fontInfo* subset = pfi;
1460
1461             i++;
1462             fr->count--;
1463             if( prev ) prev->next = pfi = pfi->next;
1464             else fr->fi = pfi = pfi->next;
1465             HeapFree( SystemHeap, 0, subset );
1466             continue;
1467         }
1468     }
1469     else pfi->fi_flags &= ~FI_SUBSET;
1470
1471     prev = pfi; 
1472     pfi = pfi->next;
1473   }
1474
1475   if( action == REMOVE_SUBSETS )        /* also add the superset */
1476   {
1477     if( fi->fi_flags & FI_SCALABLE )
1478     {
1479         fi->next = fr->fi;
1480         fr->fi = fi;
1481     }
1482     else if( prev ) prev->next = fi; else fr->fi = fi;
1483     fr->count++;
1484   }
1485
1486 #ifdef DEBUG_FONT_INIT
1487   if( i ) dprintf_font(stddeb,"\t    purged %i subsets [%i]\n", i , fr->count);
1488 #endif
1489 }
1490
1491 /***********************************************************************
1492  *            XFONT_FindFIList
1493  */
1494 static fontResource* XFONT_FindFIList( fontResource* pfr, const char* pTypeFace )
1495 {
1496   while( pfr )
1497   {
1498     if( !lstrcmpi32A( pfr->lfFaceName, pTypeFace ) ) break;
1499     pfr = pfr->next;
1500   }
1501   return pfr;
1502 }
1503
1504 /***********************************************************************
1505  *          XFONT_MatchDeviceFont
1506  *
1507  * Scan font resource tree.
1508  */
1509 static BOOL32 XFONT_MatchDeviceFont( fontResource* start, fontMatch* pfm )
1510 {
1511     fontMatch           fm = *pfm;
1512
1513     pfm->pfi = NULL;
1514     if( fm.plf->lfFaceName[0] )
1515     {
1516         LPSTR str = XFONT_CheckAliasTable( fm.plf->lfFaceName );
1517         fm.pfr = XFONT_FindFIList( start, str ? str : fm.plf->lfFaceName );
1518     }
1519
1520     if( fm.pfr )        /* match family */
1521     {
1522         dprintf_font(stddeb, "%s\n", fm.pfr->lfFaceName );
1523
1524         XFONT_MatchFIList( &fm );
1525         *pfm = fm;
1526     }
1527
1528     if( !pfm->pfi )      /* match all available fonts */
1529     {
1530         UINT32          current_score, score = (UINT32)(-1);
1531
1532         fm.flags |= FO_MATCH_PAF;
1533         for( start = fontList; start && score; start = start->next )
1534         {
1535             fm.pfr = start;
1536             dprintf_font(stddeb, "%s\n", fm.pfr->lfFaceName );
1537
1538             current_score = XFONT_MatchFIList( &fm );
1539             if( current_score < score )
1540             {
1541                 score = current_score;
1542                 *pfm = fm;
1543             }
1544         }
1545     }
1546     return TRUE;
1547 }
1548
1549
1550 /***********************************************************************
1551  *           X Font Cache
1552  */
1553 static void XFONT_GrowFreeList(int start, int end)
1554 {
1555    /* add all entries from 'start' up to and including 'end' */
1556
1557    memset( fontCache + start, 0, (end - start + 1) * sizeof(fontObject) );
1558
1559    fontCache[end].lru = fontLF;
1560    fontCache[end].count = -1;
1561    fontLF = start;
1562    while( start < end )
1563    {
1564         fontCache[start].count = -1;
1565         fontCache[start].lru = start + 1;
1566         start++;
1567    } 
1568 }
1569
1570 static fontObject* XFONT_LookupCachedFont( LPLOGFONT16 plf, UINT16* checksum )
1571 {
1572     UINT16      cs = __lfCheckSum( plf );
1573     int         i = fontMRU, prev = -1;
1574    
1575    *checksum = cs;
1576     while( i >= 0 )
1577     {
1578         if( fontCache[i].lfchecksum == cs &&
1579           !(fontCache[i].fo_flags & FO_REMOVED) )
1580         {
1581             /* FIXME: something more intelligent here */
1582
1583             if( !memcmp( plf, &fontCache[i].lf,
1584                          sizeof(LOGFONT16) - LF_FACESIZE ) &&
1585                 !lstrncmpi32A( plf->lfFaceName, fontCache[i].lf.lfFaceName, 
1586                                                             LF_FACESIZE ) )
1587             {
1588                 /* remove temporarily from the lru list */
1589
1590                 if( prev >= 0 )
1591                     fontCache[prev].lru = fontCache[i].lru;
1592                 else 
1593                     fontMRU = (INT16)fontCache[i].lru;
1594                 return (fontCache + i);
1595             }
1596         }
1597         prev = i;
1598         i = (INT16)fontCache[i].lru;
1599     }
1600     return NULL;
1601 }
1602
1603 static fontObject* XFONT_GetCacheEntry()
1604 {
1605     int         i;
1606
1607     if( fontLF == -1 )
1608     {
1609         int     prev_i, prev_j, j;
1610
1611         dprintf_font(stddeb,"font cache is full\n");
1612
1613         /* lookup the least recently used font */
1614
1615         for( prev_i = prev_j = j = -1, i = fontMRU; i >= 0; i = (INT16)fontCache[i].lru )
1616         {
1617             if( fontCache[i].count <= 0 &&
1618               !(fontCache[i].fo_flags & FO_SYSTEM) )
1619             {
1620                 prev_j = prev_i;
1621                 j = i;
1622             }
1623             prev_i = i;
1624         }
1625
1626         if( j >= 0 )    /* unload font */
1627         {
1628             /* detach from the lru list */
1629
1630             dprintf_font(stddeb,"\tfreeing entry %i\n", j );
1631
1632             if( prev_j >= 0 )
1633                 fontCache[prev_j].lru = fontCache[j].lru;
1634             else fontMRU = (INT16)fontCache[j].lru;
1635
1636             /* FIXME: lpXForm, lpPixmap */
1637             XFreeFont( display, fontCache[j].fs );
1638
1639             memset( fontCache + j, 0, sizeof(fontObject) );
1640             return (fontCache + j);
1641         }
1642         else            /* expand cache */
1643         {
1644             fontObject* newCache;
1645
1646             prev_i = fontCacheSize + FONTCACHE;
1647
1648             dprintf_font(stddeb,"\tgrowing font cache from %i to %i\n", fontCacheSize, prev_i );
1649
1650             if( (newCache = (fontObject*)HeapReAlloc(SystemHeap, 0,  
1651                                                      fontCache, prev_i)) )
1652             {
1653                 i = fontCacheSize;
1654                 fontCacheSize  = prev_i;
1655                 fontCache = newCache;
1656                 XFONT_GrowFreeList( i, fontCacheSize - 1);
1657             } 
1658             else return NULL;
1659         }
1660     }
1661
1662     /* detach from the free list */
1663
1664     i = fontLF;
1665     fontLF = (INT16)fontCache[i].lru;
1666     fontCache[i].count = 0;
1667     return (fontCache + i);
1668 }
1669
1670 static int XFONT_ReleaseCacheEntry(fontObject* pfo)
1671 {
1672     UINT32      u = (UINT32)(pfo - fontCache);
1673
1674     if( u < fontCacheSize ) return (--fontCache[u].count);
1675     return -1;
1676 }
1677
1678 /***********************************************************************
1679  *           X Device Font Objects
1680  */
1681 static X_PHYSFONT XFONT_RealizeFont( LPLOGFONT16 plf )
1682 {
1683     UINT16      checksum;
1684     fontObject* pfo = XFONT_LookupCachedFont( plf, &checksum );
1685
1686     if( !pfo )
1687     {
1688         fontMatch       fm = { NULL, NULL, 0, 0, plf};
1689         INT32           i, index;
1690
1691         if( XTextCaps & TC_SF_X_YINDEP ) fm.flags = FO_MATCH_XYINDEP;
1692
1693         /* allocate new font cache entry */
1694
1695         if( (pfo = XFONT_GetCacheEntry()) )
1696         {
1697             LPSTR       lpLFD = HeapAlloc( GetProcessHeap(), 0, MAX_LFD_LENGTH );
1698             
1699             if( lpLFD ) /* initialize entry and load font */
1700             {
1701                 UINT32  uRelaxLevel = 0;
1702
1703                 dprintf_font(stddeb,"XRealizeFont: (%u) '%s' h=%i weight=%i %s\n",
1704                                      plf->lfCharSet, plf->lfFaceName, plf->lfHeight, 
1705                                      plf->lfWeight, (plf->lfItalic) ? "Italic" : "" );
1706
1707                 XFONT_MatchDeviceFont( fontList, &fm );
1708
1709                 pfo->fr = fm.pfr;
1710                 pfo->fi = fm.pfi;
1711                 pfo->fo_flags = fm.flags & ~FO_MATCH_MASK;
1712
1713                 memcpy( &pfo->lf, plf, sizeof(LOGFONT16) );
1714                 pfo->lfchecksum = checksum;
1715
1716                 do
1717                 {
1718                     LFD_ComposeLFD( pfo, fm.height, lpLFD, uRelaxLevel++ );
1719                     if( (pfo->fs = XLoadQueryFont( display, lpLFD )) ) break;
1720                 } while( uRelaxLevel );
1721
1722                 if( XFONT_GetLeading( &pfo->fi->df, pfo->fs, &i, NULL ) )
1723                     pfo->foAvgCharWidth = (INT16)pfo->fs->per_char['X' - pfo->fs->min_char_or_byte2].width;
1724                 else
1725                     pfo->foAvgCharWidth = (INT16)XFONT_GetAvgCharWidth( &pfo->fi->df, pfo->fs );
1726                 pfo->foInternalLeading = (INT16)i;
1727
1728                 /* FIXME: If we've got a soft font or
1729                  * there are FO_SYNTH_... flags for the
1730                  * non PROOF_QUALITY request, the engine
1731                  * should rasterize characters into mono
1732                  * pixmaps and store them in the pfo->lpPixmap
1733                  * array (pfo->fs should be updated as well).
1734                  * X11DRV_ExtTextOut() must be heavily modified 
1735                  * to support pixmap blitting and FO_SYNTH_...
1736                  * styles.
1737                  */
1738
1739                 pfo->lpXForm = NULL;
1740                 pfo->lpPixmap = NULL;
1741
1742                 HeapFree( GetProcessHeap(), 0, lpLFD );
1743             } 
1744             else /* attach back to the free list */
1745             {
1746                 pfo->count = -1;
1747                 pfo->lru = fontLF;
1748                 fontLF = (pfo - fontCache);
1749                 pfo = NULL;
1750             }
1751         }
1752
1753         if( !pfo ) /* couldn't get a new entry, get one of the cached fonts */
1754         {
1755             UINT32              current_score, score = (UINT32)(-1);
1756
1757             i = index = fontMRU; 
1758             fm.flags |= FO_MATCH_PAF;
1759             do
1760             {
1761                 pfo = fontCache + i;
1762                 fm.pfr = pfo->fr; fm.pfi = pfo->fi;
1763
1764                 current_score = XFONT_Match( &fm );
1765                 if( current_score < score ) index = i;
1766
1767                 i =  pfo->lru;
1768             } while( i >= 0 );
1769             pfo = fontCache + index;
1770             pfo->count++;
1771             return (X_PHYSFONT)(X_PFONT_MAGIC | index);
1772         }
1773     }
1774  
1775     /* attach at the head of the lru list */
1776
1777     pfo->count++;
1778     pfo->lru = fontMRU;
1779     fontMRU = (pfo - fontCache);
1780
1781     dprintf_font(stddeb,"physfont %i\n", fontMRU);
1782
1783     return (X_PHYSFONT)(X_PFONT_MAGIC | fontMRU);
1784 }
1785
1786 /***********************************************************************
1787  *           XFONT_GetFontObject
1788  */
1789 fontObject* XFONT_GetFontObject( X_PHYSFONT pFont )
1790 {
1791     if( CHECK_PFONT(pFont) ) return __PFONT(pFont);
1792     return NULL;
1793 }
1794
1795 /***********************************************************************
1796  *           XFONT_GetFontStruct
1797  */
1798 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
1799 {
1800     if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
1801     return NULL;
1802 }
1803
1804 /***********************************************************************
1805  *           XFONT_GetFontInfo
1806  */
1807 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
1808 {
1809     if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
1810     return NULL;
1811 }
1812
1813
1814
1815 /* X11DRV Interface ****************************************************
1816  *                                                                     *
1817  * Exposed via the dc->funcs dispatch table.                           *
1818  *                                                                     *
1819  ***********************************************************************/
1820 /***********************************************************************
1821  *           X11DRV_FONT_SelectObject
1822  */
1823 HFONT32 X11DRV_FONT_SelectObject( DC* dc, HFONT32 hfont, FONTOBJ* font )
1824 {
1825     HFONT32 hPrevFont = 0;
1826
1827     if( CHECK_PFONT(dc->u.x.font) ) 
1828         XFONT_ReleaseCacheEntry( __PFONT(dc->u.x.font) );
1829
1830     dc->u.x.font = XFONT_RealizeFont( &font->logfont );
1831     hPrevFont = dc->w.hFont;
1832     dc->w.hFont = hfont;
1833
1834     return hPrevFont;
1835 }
1836
1837
1838 /***********************************************************************
1839  *
1840  *           X11DRV_EnumDeviceFonts
1841  */
1842 BOOL32  X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf, 
1843                                         DEVICEFONTENUMPROC proc, LPARAM lp )
1844 {
1845     ENUMLOGFONTEX16     lf;
1846     NEWTEXTMETRIC16     tm;
1847     fontResource*       pfr = fontList;
1848     BOOL32              b, bRet = 0;
1849
1850     if( plf->lfFaceName[0] )
1851     {
1852         pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
1853         if( pfr )
1854         {
1855             fontInfo*   pfi;
1856             for( pfi = pfr->fi; pfi; pfi = pfi->next )
1857                 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm, 
1858                         XFONT_GetFontMetric( pfi, &lf, &tm ), lp )) )
1859                      bRet = b;
1860                 else break;
1861         }
1862     }
1863     else
1864         for( ; pfr ; pfr = pfr->next )
1865             if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm, 
1866                        XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
1867                  bRet = b;
1868             else break;
1869
1870     return bRet;
1871 }
1872
1873
1874 /***********************************************************************
1875  *           X11DRV_GetTextExtentPoint
1876  */
1877 BOOL32 X11DRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT32 count,
1878                                   LPSIZE32 size )
1879 {
1880     XFontStruct* pfs = XFONT_GetFontStruct( dc->u.x.font );
1881     if( pfs )
1882     {
1883         int dir, ascent, descent;
1884         XCharStruct info;
1885
1886         XTextExtents( pfs, str, count, &dir, &ascent, &descent, &info );
1887         size->cx = abs((info.width + dc->w.breakRem + count * dc->w.charExtra)
1888                                                 * dc->wndExtX / dc->vportExtX);
1889         size->cy = abs((pfs->ascent + pfs->descent) * dc->wndExtY / dc->vportExtY);
1890         return TRUE;
1891     }
1892     return FALSE;
1893 }
1894
1895
1896 /***********************************************************************
1897  *           X11DRV_GetTextMetrics
1898  */
1899 BOOL32 X11DRV_GetTextMetrics(DC *dc, TEXTMETRIC32A *metrics)
1900 {
1901     if( CHECK_PFONT(dc->u.x.font) )
1902     {
1903         fontObject* pfo = __PFONT(dc->u.x.font);
1904         XFONT_GetTextMetric( pfo, metrics );
1905         return TRUE;
1906     }
1907     return FALSE;
1908 }
1909
1910
1911 /***********************************************************************
1912  *           X11DRV_GetCharWidth
1913  */
1914 BOOL32 X11DRV_GetCharWidth( DC *dc, UINT32 firstChar, UINT32 lastChar,
1915                             LPINT32 buffer )
1916 {
1917     XFontStruct* xfs = XFONT_GetFontStruct( dc->u.x.font );
1918
1919     if( xfs )
1920     {
1921         int i;
1922
1923         if (xfs->per_char == NULL)
1924             for (i = firstChar; i <= lastChar; i++)
1925                 *buffer++ = xfs->min_bounds.width;
1926         else
1927         {
1928             XCharStruct *cs, *def;
1929             static XCharStruct  __null_char = { 0, 0, 0, 0, 0, 0 };
1930
1931             CI_GET_CHAR_INFO(xfs, xfs->default_char, &__null_char, def);
1932
1933             for (i = firstChar; i <= lastChar; i++)
1934             {
1935                 if (i >= xfs->min_char_or_byte2 && i <= xfs->max_char_or_byte2)
1936                 {
1937                     cs = &xfs->per_char[(i - xfs->min_char_or_byte2)]; 
1938                     if (CI_NONEXISTCHAR(cs)) cs = def; 
1939                 } else cs = def;
1940                 *buffer++ = MAX( cs->width, 0 );
1941             }
1942         }
1943         return TRUE;
1944     }
1945     return FALSE;
1946 }
1947
1948 /***********************************************************************
1949  *                                                                     *
1950  *           Font Resource API                                         *
1951  *                                                                     *
1952  ***********************************************************************/
1953 /***********************************************************************
1954  *           AddFontResource16    (GDI.119)
1955  *
1956  *  Can be either .FON, or .FNT, or .TTF, or .FOT font file.
1957  *
1958  *  FIXME: Load header and find the best-matching font in the fontList;
1959  *         fixup dfPoints if all metrics are identical, otherwise create
1960  *         new fontAlias. When soft font support is ready this will
1961  *         simply create a new fontResource ('filename' will go into
1962  *         the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE 
1963  *         flag set. 
1964  */
1965 INT16 AddFontResource16( LPCSTR filename )
1966 {
1967     return AddFontResource32A( filename );
1968 }
1969
1970
1971 /***********************************************************************
1972  *           AddFontResource32A    (GDI32.2)
1973  */
1974 INT32 AddFontResource32A( LPCSTR str )
1975 {
1976     if (HIWORD(str))    /* font file */
1977         fprintf( stdnimp, "STUB: AddFontResource('%s')\n", str );
1978     else                /* font resource handle */
1979         fprintf( stdnimp, "STUB: AddFontResource(%04x)\n", LOWORD(str) );
1980     return 1;
1981 }
1982
1983
1984 /***********************************************************************
1985  *           AddFontResource32W    (GDI32.4)
1986  */
1987 INT32 AddFontResource32W( LPCWSTR str )
1988 {
1989     fprintf( stdnimp, "STUB: AddFontResource32W(%p)\n", str );
1990     return 1;
1991 }
1992
1993 /***********************************************************************
1994  *           RemoveFontResource16    (GDI.136)
1995  */
1996 BOOL16 RemoveFontResource16( LPCSTR str )
1997 {
1998     return RemoveFontResource32A( str );
1999 }
2000
2001
2002 /***********************************************************************
2003  *           RemoveFontResource32A    (GDI32.284)
2004  */
2005 BOOL32 RemoveFontResource32A( LPCSTR str )
2006 {
2007     if (HIWORD(str))
2008         fprintf( stdnimp, "STUB: RemoveFontResource('%s')\n", str );
2009     else
2010         fprintf( stdnimp, "STUB: RemoveFontResource(%04x)\n", LOWORD(str) );
2011     return TRUE;
2012 }
2013
2014
2015 /***********************************************************************
2016  *           RemoveFontResource32W    (GDI32.286)
2017  */
2018 BOOL32 RemoveFontResource32W( LPCWSTR str )
2019 {
2020     fprintf( stdnimp, "STUB: RemoveFontResource32W(%p)\n", str );
2021     return TRUE;
2022 }
2023
2024