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