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