Removed #include of wingdi.h and windef.h from winuser.h (and resolved
[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( SystemHeap, 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(SystemHeap, 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( SystemHeap, 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( SystemHeap, 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(SystemHeap, 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(SystemHeap, 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(SystemHeap, 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( SystemHeap, 0, pfr->fi );
1605         pfr->fi = pfi;
1606     }
1607     HeapFree( SystemHeap, 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(SystemHeap, 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( SystemHeap, 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( SystemHeap, 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(SystemHeap, 0, x_pattern[i]);
1838         if (!typeface)
1839             break;
1840
1841         lfd = LFD_Parse(typeface);
1842         if (!lfd)
1843         {
1844             HeapFree(SystemHeap, 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(SystemHeap, 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(SystemHeap, 0, sizeof(fontResource)); 
1866             if (fr)
1867             {
1868                 memset(fr, 0, sizeof(fontResource));
1869               
1870                 fr->resource = (LFD*) HeapAlloc(SystemHeap, 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(SystemHeap, 0, lfd->foundry);
1875                 fr->resource->family = HEAP_strdupA(SystemHeap, 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(SystemHeap, 0, lfd);
1938         HeapFree(SystemHeap, 0, typeface);
1939     }
1940     if( fi ) HeapFree(SystemHeap, 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( SystemHeap, 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( SystemHeap, 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_CheckIniSection
2125  *
2126  * INIT ONLY
2127  *
2128  *   Examines wine.conf for old/invalid font entries and recommend changes to
2129  *   the user.
2130  *
2131  *   Revision history
2132  *        05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
2133  *             Original implementation.
2134  */
2135 static void XFONT_CheckIniCallback(char const *, char const *, void *);
2136
2137 static char const  *fontmsgprologue =
2138 "Wine warning:\n"
2139 "   The following entries in the [fonts] section of the wine.conf file are\n"
2140 "   obsolete or invalid:\n";
2141
2142 static char const  *fontmsgepilogue =
2143 "   These entries should be eliminated or updated.\n"
2144 "   See the documentation/fonts file for more information.\n";
2145
2146 static int XFONT_CheckIniSection(void)
2147 {
2148     int  found = 0;
2149
2150     PROFILE_EnumerateWineIniSection("Fonts", &XFONT_CheckIniCallback,
2151                     (void *)&found);
2152     if(found)
2153         MESSAGE(fontmsgepilogue);
2154
2155     return 1;
2156 }
2157
2158 static void  XFONT_CheckIniCallback(
2159     char const  *key,
2160     char const  *value,
2161     void  *found)
2162 {
2163     /* Ignore any keys that start with potential comment characters "'", '#',
2164        or ';'. */
2165     if(key[0] == '\'' || key[0] == '#' || key[0] == ';' || key[0] == '\0')
2166         return;
2167
2168     /* Make sure this is a valid key */
2169     if((strncasecmp(key, INIAliasSection, 5) == 0) ||
2170        (strncasecmp(key, INIIgnoreSection, 6) == 0) ||
2171        (strcasecmp( key, INIDefault) == 0) ||
2172        (strcasecmp( key, INIDefaultFixed) == 0) ||
2173        (strcasecmp( key, INIGlobalMetrics) == 0) ||
2174        (strcasecmp( key, INIResolution) == 0) ||
2175        (strcasecmp( key, INIDefaultSerif) == 0) ||
2176        (strcasecmp( key, INIDefaultSansSerif) ==0) )
2177     {
2178         /* Valid key; make sure the value doesn't contain a wildcard */
2179         if(strchr(value, '*')) {
2180             if(*(int *)found == 0) {
2181                 MESSAGE(fontmsgprologue);
2182                 ++*(int *)found;
2183             }
2184             MESSAGE("     %s=%s [no wildcards allowed]\n", key, value);
2185         }
2186     }
2187     else {
2188         /* Not a valid key */
2189         if(*(int *)found == 0) {
2190             MESSAGE(fontmsgprologue);
2191             ++*(int *)found;
2192         }
2193         
2194         MESSAGE("     %s=%s [obsolete]\n", key, value);
2195     }
2196
2197     return;
2198 }
2199
2200 /***********************************************************************
2201  *           XFONT_GetPointResolution()
2202  *
2203  * INIT ONLY
2204  *
2205  * Here we initialize DefResolution which is used in the
2206  * XFONT_Match() penalty function. We also load the point
2207  * resolution value (higher values result in larger fonts).
2208  */
2209 static int XFONT_GetPointResolution( DeviceCaps* pDevCaps )
2210 {
2211     int i, j, point_resolution, num = 3; 
2212     int allowed_xfont_resolutions[3] = { 72, 75, 100 };
2213     int best = 0, best_diff = 65536;
2214
2215     point_resolution = PROFILE_GetWineIniInt( INIFontSection, INIResolution, 0 );
2216     if( !point_resolution )
2217         point_resolution = pDevCaps->logPixelsY;
2218     else
2219         pDevCaps->logPixelsX = pDevCaps->logPixelsY = point_resolution;
2220
2221
2222     /* FIXME We can only really guess at a best DefResolution
2223      * - this should be configurable
2224      */
2225     for( i = best = 0; i < num; i++ )
2226     {
2227         j = abs( point_resolution - allowed_xfont_resolutions[i] );
2228         if( j < best_diff )
2229         {
2230             best = i;
2231             best_diff = j;
2232         }
2233     }
2234     DefResolution = allowed_xfont_resolutions[best];
2235
2236     /* FIXME - do win95,nt40,... do this as well ? */
2237     if (TWEAK_WineLook == WIN98_LOOK)
2238     {
2239         /* Lie about the screen size, so that eg MM_LOMETRIC becomes MM_logical_LOMETRIC */
2240         int denom;
2241         denom = pDevCaps->logPixelsX * 10;
2242         pDevCaps->horzSize = (pDevCaps->horzRes * 254 + (denom>>1)) / denom;
2243         denom = pDevCaps->logPixelsY * 10;
2244         pDevCaps->vertSize = (pDevCaps->vertRes * 254 + (denom>>1)) / denom;
2245     }
2246
2247     return point_resolution;
2248 }
2249
2250
2251 /***********************************************************************
2252  *            XFONT_Match
2253  *
2254  * Compute the matching score between the logical font and the device font.
2255  *
2256  * contributions from highest to lowest:
2257  *      charset
2258  *      fixed pitch
2259  *      height
2260  *      family flags (only when the facename is not present)
2261  *      width
2262  *      weight, italics, underlines, strikeouts
2263  *
2264  * NOTE: you can experiment with different penalty weights to see what happens.
2265  * http://premium.microsoft.com/msdn/library/techart/f365/f36b/f37b/d38b/sa8bf.htm
2266  */
2267 static UINT XFONT_Match( fontMatch* pfm )
2268 {
2269    fontInfo*    pfi = pfm->pfi;         /* device font to match */
2270    LPLOGFONT16  plf = pfm->plf;         /* wanted logical font */
2271    UINT       penalty = 0;
2272    BOOL       bR6 = pfm->flags & FO_MATCH_XYINDEP;    /* from TextCaps */
2273    BOOL       bScale = pfi->fi_flags & FI_SCALABLE;
2274    int d = 0, height;
2275
2276    TRACE("\t[ %-2ipt h=%-3i w=%-3i %s%s]\n", pfi->df.dfPoints,
2277                  pfi->df.dfPixHeight, pfi->df.dfAvgWidth,
2278                 (pfi->df.dfWeight > FW_NORMAL) ? "Bold " : "Normal ",
2279                 (pfi->df.dfItalic) ? "Italic" : "" );
2280
2281    pfm->flags &= FO_MATCH_MASK;
2282
2283 /* Charset */
2284    if( plf->lfCharSet == DEFAULT_CHARSET )
2285    {
2286        if( (pfi->df.dfCharSet != ANSI_CHARSET) && (pfi->df.dfCharSet != DEFAULT_CHARSET) ) 
2287             penalty += 0x200;
2288    }
2289    else if (plf->lfCharSet != pfi->df.dfCharSet) penalty += 0x200;
2290
2291 /* Height */
2292    height = -1;
2293    {
2294        if( plf->lfHeight > 0 )
2295        {
2296            int h = pfi->df.dfPixHeight;
2297            d = h - plf->lfHeight;
2298            height = plf->lfHeight;
2299        }
2300        else
2301        {
2302            int h = pfi->df.dfPixHeight - pfi->df.dfInternalLeading;
2303            if (h)
2304            {
2305                d = h + plf->lfHeight;
2306                height = (-plf->lfHeight * pfi->df.dfPixHeight) / h;
2307            }
2308            else
2309            {
2310                ERR("PixHeight == InternalLeading\n");
2311                penalty += 0x1000; /* dont want this */
2312            }
2313        }
2314    }
2315
2316    if( height == 0 )
2317        pfm->height = 1; /* Very small */
2318    else if( d )
2319    {
2320        if( bScale )
2321            pfm->height = height;
2322        else if( (plf->lfQuality != PROOF_QUALITY) && bR6 )
2323        {
2324            if( d > 0 )  /* do not shrink raster fonts */
2325            {
2326                pfm->height = pfi->df.dfPixHeight;
2327                penalty += (pfi->df.dfPixHeight - height) * 0x4;
2328            }
2329            else         /* expand only in integer multiples */
2330            {
2331                pfm->height = height - height%pfi->df.dfPixHeight;
2332                penalty += (height - pfm->height + 1) * height / pfi->df.dfPixHeight;
2333            }
2334        }
2335        else /* can't be scaled at all */
2336        {
2337            if( plf->lfQuality != PROOF_QUALITY) pfm->flags |= FO_SYNTH_HEIGHT;
2338            pfm->height = pfi->df.dfPixHeight;
2339            penalty += (d > 0)? d * 0x8 : -d * 0x10;
2340        }
2341    }
2342    else
2343        pfm->height = pfi->df.dfPixHeight;
2344
2345 /* Pitch and Family */
2346    if( pfm->flags & FO_MATCH_PAF ) {
2347        int family = plf->lfPitchAndFamily & FF_FAMILY;
2348
2349        /* TMPF_FIXED_PITCH means exactly the opposite */
2350        if( plf->lfPitchAndFamily & FIXED_PITCH ) {
2351            if( pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH ) penalty += 0x100;
2352        } else /* Variable is the default */
2353            if( !(pfi->df.dfPitchAndFamily & TMPF_FIXED_PITCH) ) penalty += 0x2;
2354
2355        if (family != FF_DONTCARE && family != (pfi->df.dfPitchAndFamily & FF_FAMILY) )
2356            penalty += 0x10;
2357    }
2358
2359 /* Width */
2360    if( plf->lfWidth )
2361    {
2362        int h;
2363        if( bR6 || bScale ) h = 0; 
2364        else
2365        {
2366            /* FIXME: not complete */
2367
2368            pfm->flags |= FO_SYNTH_WIDTH;
2369            h = abs(plf->lfWidth - (pfm->height * pfi->df.dfAvgWidth)/pfi->df.dfPixHeight);
2370        }
2371        penalty += h * ( d ) ? 0x2 : 0x1 ;
2372    }
2373    else if( !(pfi->fi_flags & FI_NORMAL) ) penalty++;
2374
2375 /* Weight */
2376    if( plf->lfWeight != FW_DONTCARE )
2377    {
2378        penalty += abs(plf->lfWeight - pfi->df.dfWeight) / 40;
2379        if( plf->lfWeight > pfi->df.dfWeight ) pfm->flags |= FO_SYNTH_BOLD;
2380    } else if( pfi->df.dfWeight >= FW_BOLD ) penalty++;  /* choose normal by default */
2381
2382 /* Italic */
2383    if( plf->lfItalic != pfi->df.dfItalic )
2384    {
2385        penalty += 0x4;
2386        pfm->flags |= FO_SYNTH_ITALIC;
2387    }
2388 /* Underline */
2389    if( plf->lfUnderline ) pfm->flags |= FO_SYNTH_UNDERLINE;
2390
2391 /* Strikeout */   
2392    if( plf->lfStrikeOut ) pfm->flags |= FO_SYNTH_STRIKEOUT;
2393
2394
2395    if( penalty && !bScale && pfi->lfd_resolution != DefResolution ) 
2396        penalty++;
2397
2398    TRACE("  returning %i\n", penalty );
2399
2400    return penalty;
2401 }
2402
2403 /***********************************************************************
2404  *            XFONT_MatchFIList
2405  *
2406  * Scan a particular font resource for the best match.
2407  */
2408 static UINT XFONT_MatchFIList( fontMatch* pfm )
2409 {
2410   BOOL        skipRaster = (pfm->flags & FO_MATCH_NORASTER);
2411   UINT        current_score, score = (UINT)(-1);
2412   fontMatch   fm = *pfm;
2413
2414   for( fm.pfi = pfm->pfr->fi; fm.pfi && score; fm.pfi = fm.pfi->next)
2415   {
2416      if( skipRaster && !(fm.pfi->fi_flags & FI_SCALABLE) )
2417          continue;
2418
2419      current_score = XFONT_Match( &fm );
2420      if( score > current_score )
2421      {
2422         *pfm = fm;
2423         score = current_score;
2424      }
2425   }
2426   return score;
2427 }
2428
2429 /***********************************************************************
2430  *          XFONT_MatchDeviceFont
2431  *
2432  * Scan font resource tree.
2433  *
2434  */
2435 static void XFONT_MatchDeviceFont( fontResource* start, fontMatch* pfm)
2436 {
2437     fontMatch           fm = *pfm;
2438     UINT          current_score, score = (UINT)(-1);
2439     fontResource**      ppfr;
2440     
2441     TRACE("(%u) '%s' h=%i weight=%i %s\n",
2442           pfm->plf->lfCharSet, pfm->plf->lfFaceName, pfm->plf->lfHeight, 
2443           pfm->plf->lfWeight, (pfm->plf->lfItalic) ? "Italic" : "" );
2444
2445     pfm->pfi = NULL;
2446     if( fm.plf->lfFaceName[0] ) 
2447     {
2448         fm.pfr = XFONT_FindFIList( start, fm.plf->lfFaceName);
2449         if( fm.pfr ) /* match family */
2450         {
2451             TRACE("found facename '%s'\n", fm.pfr->lfFaceName );
2452             
2453             if( fm.pfr->fr_flags & FR_REMOVED )
2454                 fm.pfr = 0;
2455             else
2456             {
2457                 XFONT_MatchFIList( &fm );
2458                 *pfm = fm;
2459                 if (pfm->pfi)
2460                     return;
2461             }
2462         }
2463     }
2464
2465     /* match all available fonts */
2466
2467     fm.flags |= FO_MATCH_PAF;
2468     for( ppfr = &fontList; *ppfr && score; ppfr = &(*ppfr)->next )
2469     {
2470         if( (*ppfr)->fr_flags & FR_REMOVED )
2471         {
2472             if( (*ppfr)->fo_count == 0 )
2473                 XFONT_RemoveFontResource( ppfr );
2474             continue;
2475         }
2476         
2477         fm.pfr = *ppfr;
2478         
2479         TRACE("%s\n", fm.pfr->lfFaceName );
2480             
2481         current_score = XFONT_MatchFIList( &fm );
2482         if( current_score < score )
2483         {
2484             score = current_score;
2485             *pfm = fm;
2486         }
2487     }
2488 }
2489
2490
2491 /***********************************************************************
2492  *           X Font Cache
2493  */
2494 static void XFONT_GrowFreeList(int start, int end)
2495 {
2496    /* add all entries from 'start' up to and including 'end' */
2497
2498    memset( fontCache + start, 0, (end - start + 1) * sizeof(fontObject) );
2499
2500    fontCache[end].lru = fontLF;
2501    fontCache[end].count = -1;
2502    fontLF = start;
2503    while( start < end )
2504    {
2505         fontCache[start].count = -1;
2506         fontCache[start].lru = start + 1;
2507         start++;
2508    } 
2509 }
2510
2511 static fontObject* XFONT_LookupCachedFont( const LPLOGFONT16 plf, UINT16* checksum )
2512 {
2513     UINT16      cs = __lfCheckSum( plf );
2514     int         i = fontMRU, prev = -1;
2515    
2516    *checksum = cs;
2517     while( i >= 0 )
2518     {
2519         if( fontCache[i].lfchecksum == cs &&
2520           !(fontCache[i].fo_flags & FO_REMOVED) )
2521         {
2522             /* FIXME: something more intelligent here ? */
2523
2524             if( !memcmp( plf, &fontCache[i].lf,
2525                          sizeof(LOGFONT16) - LF_FACESIZE ) &&
2526                 !strcmp( plf->lfFaceName, fontCache[i].lf.lfFaceName) )
2527             {
2528                 /* remove temporarily from the lru list */
2529                 if( prev >= 0 )
2530                     fontCache[prev].lru = fontCache[i].lru;
2531                 else 
2532                     fontMRU = (INT16)fontCache[i].lru;
2533                 return (fontCache + i);
2534             }
2535         }
2536         prev = i;
2537         i = (INT16)fontCache[i].lru;
2538     }
2539     return NULL;
2540 }
2541
2542 static fontObject* XFONT_GetCacheEntry(void)
2543 {
2544     int         i;
2545
2546     if( fontLF == -1 )
2547     {
2548         int     prev_i, prev_j, j;
2549
2550         TRACE("font cache is full\n");
2551
2552         /* lookup the least recently used font */
2553
2554         for( prev_i = prev_j = j = -1, i = fontMRU; i >= 0; i = (INT16)fontCache[i].lru )
2555         {
2556             if( fontCache[i].count <= 0 &&
2557               !(fontCache[i].fo_flags & FO_SYSTEM) )
2558             {
2559                 prev_j = prev_i;
2560                 j = i;
2561             }
2562             prev_i = i;
2563         }
2564
2565         if( j >= 0 )    /* unload font */
2566         {
2567             /* detach from the lru list */
2568
2569             TRACE("\tfreeing entry %i\n", j );
2570
2571             fontCache[j].fr->fo_count--;
2572
2573             if( prev_j >= 0 )
2574                 fontCache[prev_j].lru = fontCache[j].lru;
2575             else fontMRU = (INT16)fontCache[j].lru;
2576
2577             /* FIXME: lpXForm, lpPixmap */
2578             if(fontCache[j].lpX11Trans)
2579                 HeapFree( SystemHeap, 0, fontCache[j].lpX11Trans );
2580
2581             TSXFreeFont( display, fontCache[j].fs );
2582
2583             memset( fontCache + j, 0, sizeof(fontObject) );
2584             return (fontCache + j);
2585         }
2586         else            /* expand cache */
2587         {
2588             fontObject* newCache;
2589
2590             prev_i = fontCacheSize + FONTCACHE;
2591
2592             TRACE("\tgrowing font cache from %i to %i\n", fontCacheSize, prev_i );
2593
2594             if( (newCache = (fontObject*)HeapReAlloc(SystemHeap, 0,  
2595                                                      fontCache, prev_i)) )
2596             {
2597                 i = fontCacheSize;
2598                 fontCacheSize  = prev_i;
2599                 fontCache = newCache;
2600                 XFONT_GrowFreeList( i, fontCacheSize - 1);
2601             } 
2602             else return NULL;
2603         }
2604     }
2605
2606     /* detach from the free list */
2607
2608     i = fontLF;
2609     fontLF = (INT16)fontCache[i].lru;
2610     fontCache[i].count = 0;
2611     return (fontCache + i);
2612 }
2613
2614 static int XFONT_ReleaseCacheEntry(const fontObject* pfo)
2615 {
2616     UINT        u = (UINT)(pfo - fontCache);
2617
2618     if( u < fontCacheSize ) return (--fontCache[u].count);
2619     return -1;
2620 }
2621
2622 /***********************************************************************
2623  *           X11DRV_FONT_Init
2624  *
2625  * Initialize font resource list and allocate font cache.
2626  */
2627 BOOL X11DRV_FONT_Init( DeviceCaps* pDevCaps )
2628 {
2629   char**    x_pattern;
2630   unsigned  x_checksum;
2631   int       i,res, x_count, fd, buf_size;
2632   char      *buffer;
2633
2634   XFONT_CheckIniSection();
2635
2636   res = XFONT_GetPointResolution( pDevCaps );
2637       
2638   x_pattern = TSXListFonts(display, "*", MAX_FONTS, &x_count );
2639
2640   TRACE("Font Mapper: initializing %i fonts [logical dpi=%i, default dpi=%i]\n", 
2641                                     x_count, res, DefResolution);
2642   if (x_count == MAX_FONTS)      
2643       MESSAGE("There may be more fonts available - try increasing the value of MAX_FONTS\n");
2644
2645   for( i = x_checksum = 0; i < x_count; i++ )
2646   {
2647      int j;
2648 #if 0
2649      printf("%i\t: %s\n", i, x_pattern[i] );
2650 #endif
2651
2652      j = strlen( x_pattern[i] );
2653      if( j ) x_checksum ^= __genericCheckSum( x_pattern[i], j );
2654   }
2655   x_checksum |= X_PFONT_MAGIC;
2656   buf_size = 128;
2657   buffer = HeapAlloc( SystemHeap, 0, buf_size );
2658
2659   /* deal with systemwide font metrics cache */
2660
2661   if( PROFILE_GetWineIniString( INIFontSection, INIGlobalMetrics, "", buffer, buf_size ) )
2662   {
2663       fd = open( buffer, O_RDONLY );
2664       XFONT_ReadCachedMetrics(fd, DefResolution, x_checksum, x_count);
2665   }
2666   if (fontList == NULL)
2667   {
2668       /* try per-user */
2669       buffer = XFONT_UserMetricsCache( buffer, &buf_size );
2670       if( buffer[0] )
2671       {
2672           fd = open( buffer, O_RDONLY );
2673           XFONT_ReadCachedMetrics(fd, DefResolution, x_checksum, x_count);
2674       }
2675   }
2676
2677   if( fontList == NULL )        /* build metrics from scratch */
2678   {
2679       int n_ff = XFONT_BuildMetrics(x_pattern, DefResolution, x_checksum, x_count);
2680       if( buffer[0] )    /* update cached metrics */
2681       {
2682           fd = open( buffer, O_CREAT | O_TRUNC | O_RDWR, 0644 ); /* -rw-r--r-- */
2683           if( XFONT_WriteCachedMetrics( fd, x_checksum, x_count, n_ff ) == FALSE )
2684           {
2685               WARN("Unable to write to fontcache '%s'\n", buffer);
2686               if( fd >= 0) remove( buffer );    /* couldn't write entire file */
2687           }
2688       }
2689   }
2690
2691   TSXFreeFontNames(x_pattern);
2692
2693   /* check if we're dealing with X11 R6 server */
2694   {
2695       XFontStruct*  x_fs;
2696       strcpy(buffer, "-*-*-*-*-normal-*-[12 0 0 12]-*-72-*-*-*-iso8859-1");
2697       if( (x_fs = TSXLoadQueryFont(display, buffer)) )
2698       {
2699           XTextCaps |= TC_SF_X_YINDEP;
2700           TSXFreeFont(display, x_fs);
2701       }
2702   }
2703   HeapFree(SystemHeap, 0, buffer);
2704
2705   XFONT_WindowsNames();
2706   XFONT_LoadAliases();
2707   XFONT_LoadDefaults();
2708   XFONT_LoadIgnores();
2709
2710   InitializeCriticalSection( &crtsc_fonts_X11 );
2711   MakeCriticalSectionGlobal( &crtsc_fonts_X11 );
2712
2713   /* fontList initialization is over, allocate X font cache */
2714
2715   fontCache = (fontObject*) HeapAlloc(SystemHeap, 0, fontCacheSize * sizeof(fontObject));
2716   XFONT_GrowFreeList(0, fontCacheSize - 1);
2717
2718   TRACE("done!\n");
2719
2720   /* update text caps parameter */
2721
2722   pDevCaps->textCaps = XTextCaps;
2723
2724   RAW_ASCENT  = TSXInternAtom(display, "RAW_ASCENT", TRUE);
2725   RAW_DESCENT = TSXInternAtom(display, "RAW_DESCENT", TRUE);
2726   
2727   return TRUE;
2728 }
2729
2730 /**********************************************************************
2731  *      XFONT_SetX11Trans
2732  */
2733 static BOOL XFONT_SetX11Trans( fontObject *pfo )
2734 {
2735   char *fontName;
2736   Atom nameAtom;
2737   LFD* lfd;
2738
2739   TSXGetFontProperty( pfo->fs, XA_FONT, &nameAtom );
2740   fontName = TSXGetAtomName( display, nameAtom );
2741   lfd = LFD_Parse(fontName);
2742   if (!lfd)
2743   {
2744       TSXFree(fontName);
2745       return FALSE;
2746   }
2747
2748   if (lfd->pixel_size[0] != '[') {
2749       HeapFree(SystemHeap, 0, lfd);
2750       TSXFree(fontName);
2751       return FALSE;
2752   }
2753
2754 #define PX pfo->lpX11Trans
2755
2756   sscanf(lfd->pixel_size, "[%f%f%f%f]", &PX->a, &PX->b, &PX->c, &PX->d);
2757   TSXFree(fontName);
2758   HeapFree(SystemHeap, 0, lfd);
2759
2760   TSXGetFontProperty( pfo->fs, RAW_ASCENT, &PX->RAW_ASCENT );
2761   TSXGetFontProperty( pfo->fs, RAW_DESCENT, &PX->RAW_DESCENT );
2762
2763   PX->pixelsize = hypot(PX->a, PX->b);
2764   PX->ascent = PX->pixelsize / 1000.0 * PX->RAW_ASCENT;
2765   PX->descent = PX->pixelsize / 1000.0 * PX->RAW_DESCENT;
2766
2767   TRACE("[%f %f %f %f] RA = %ld RD = %ld\n",
2768         PX->a, PX->b, PX->c, PX->d,
2769         PX->RAW_ASCENT, PX->RAW_DESCENT);
2770
2771 #undef PX
2772   return TRUE;
2773 }
2774
2775 /***********************************************************************
2776  *           X Device Font Objects
2777  */
2778 static X_PHYSFONT XFONT_RealizeFont( const LPLOGFONT16 plf, LPCSTR* faceMatched)
2779 {
2780     UINT16      checksum;
2781     INT         index = 0;
2782     fontObject* pfo;
2783
2784     pfo = XFONT_LookupCachedFont( plf, &checksum );
2785     if( !pfo )
2786     {
2787         fontMatch       fm;
2788         INT             i;
2789
2790         fm.pfr = NULL;
2791         fm.pfi = NULL;
2792         fm.height = 0;
2793         fm.flags = 0;
2794         fm.plf = plf;
2795
2796         if( XTextCaps & TC_SF_X_YINDEP ) fm.flags = FO_MATCH_XYINDEP;
2797
2798         /* allocate new font cache entry */
2799
2800         if( (pfo = XFONT_GetCacheEntry()) )
2801         {
2802             /* initialize entry and load font */
2803             char lpLFD[MAX_LFD_LENGTH];
2804             UINT uRelaxLevel = 0;
2805
2806             if(abs(plf->lfHeight) > MAX_FONT_SIZE) {
2807                 ERR(
2808   "plf->lfHeight = %d, Creating a 100 pixel font and rescaling metrics \n", 
2809                     plf->lfHeight);
2810                 pfo->rescale = fabs(plf->lfHeight / 100.0);
2811                 if(plf->lfHeight > 0) plf->lfHeight = 100;
2812                 else plf->lfHeight = -100;
2813             } else
2814                 pfo->rescale = 1.0;
2815             
2816             XFONT_MatchDeviceFont( fontList, &fm );
2817             pfo->fr = fm.pfr;
2818             pfo->fi = fm.pfi;
2819             pfo->fr->fo_count++;
2820             pfo->fo_flags = fm.flags & ~FO_MATCH_MASK;
2821
2822             pfo->lf = *plf;
2823             pfo->lfchecksum = checksum;
2824
2825             do
2826             {
2827                 LFD_ComposeLFD( pfo, fm.height, lpLFD, uRelaxLevel++ );
2828                 if( (pfo->fs = TSXLoadQueryFont( display, lpLFD )) ) break;
2829             } while( uRelaxLevel );
2830
2831                 
2832             if(pfo->lf.lfEscapement != 0) {
2833                 pfo->lpX11Trans = HeapAlloc(SystemHeap, 0, sizeof(XFONTTRANS));
2834                 if(!XFONT_SetX11Trans( pfo )) {
2835                     HeapFree(SystemHeap, 0, pfo->lpX11Trans);
2836                     pfo->lpX11Trans = NULL;
2837                 }
2838             }
2839             XFONT_GetLeading( &pfo->fi->df, pfo->fs,
2840                               &pfo->foInternalLeading, NULL, pfo->lpX11Trans );
2841             pfo->foAvgCharWidth = (INT16)XFONT_GetAvgCharWidth(&pfo->fi->df, pfo->fs, pfo->lpX11Trans );
2842             pfo->foMaxCharWidth = (INT16)XFONT_GetMaxCharWidth(pfo->fs, pfo->lpX11Trans);
2843             
2844             /* FIXME: If we've got a soft font or
2845              * there are FO_SYNTH_... flags for the
2846              * non PROOF_QUALITY request, the engine
2847              * should rasterize characters into mono
2848              * pixmaps and store them in the pfo->lpPixmap
2849              * array (pfo->fs should be updated as well).
2850              * array (pfo->fs should be updated as well).
2851              * X11DRV_ExtTextOut() must be heavily modified 
2852              * to support pixmap blitting and FO_SYNTH_...
2853              * styles.
2854              */
2855
2856             pfo->lpPixmap = NULL;
2857         }
2858         
2859         if( !pfo ) /* couldn't get a new entry, get one of the cached fonts */
2860         {
2861             UINT                current_score, score = (UINT)(-1);
2862
2863             i = index = fontMRU; 
2864             fm.flags |= FO_MATCH_PAF;
2865             do
2866             {
2867                 pfo = fontCache + i;
2868                 fm.pfr = pfo->fr; fm.pfi = pfo->fi;
2869
2870                 current_score = XFONT_Match( &fm );
2871                 if( current_score < score ) index = i;
2872
2873                 i =  pfo->lru;
2874             } while( i >= 0 );
2875             pfo = fontCache + index;
2876             goto END;
2877         }
2878     }
2879
2880     /* attach at the head of the lru list */
2881     pfo->lru = fontMRU;
2882     index = fontMRU = (pfo - fontCache);
2883  
2884 END:
2885     pfo->count++;
2886
2887     TRACE("physfont %i\n", index);
2888     *faceMatched = pfo->fi->df.dfFace;
2889
2890     return (X_PHYSFONT)(X_PFONT_MAGIC | index);
2891 }
2892
2893 /***********************************************************************
2894  *           XFONT_GetFontObject
2895  */
2896 fontObject* XFONT_GetFontObject( X_PHYSFONT pFont )
2897 {
2898     if( CHECK_PFONT(pFont) ) return __PFONT(pFont);
2899     return NULL;
2900 }
2901
2902 /***********************************************************************
2903  *           XFONT_GetFontStruct
2904  */
2905 XFontStruct* XFONT_GetFontStruct( X_PHYSFONT pFont )
2906 {
2907     if( CHECK_PFONT(pFont) ) return __PFONT(pFont)->fs;
2908     return NULL;
2909 }
2910
2911 /***********************************************************************
2912  *           XFONT_GetFontInfo
2913  */
2914 LPIFONTINFO16 XFONT_GetFontInfo( X_PHYSFONT pFont )
2915 {
2916     if( CHECK_PFONT(pFont) ) return &(__PFONT(pFont)->fi->df);
2917     return NULL;
2918 }
2919
2920
2921
2922 /* X11DRV Interface ****************************************************
2923  *                                                                     *
2924  * Exposed via the dc->funcs dispatch table.                           *
2925  *                                                                     *
2926  ***********************************************************************/
2927 /***********************************************************************
2928  *           X11DRV_FONT_SelectObject
2929  */
2930 HFONT X11DRV_FONT_SelectObject( DC* dc, HFONT hfont, FONTOBJ* font )
2931 {
2932     HFONT hPrevFont = 0;
2933     LOGFONT16 lf;
2934     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
2935
2936     EnterCriticalSection( &crtsc_fonts_X11 );
2937
2938     if( CHECK_PFONT(physDev->font) ) 
2939         XFONT_ReleaseCacheEntry( __PFONT(physDev->font) );
2940
2941     lf = font->logfont;
2942
2943     /* Make sure we don't change the sign when converting to device coords */
2944     /* FIXME - check that the other drivers do this correctly */
2945     if (lf.lfWidth)
2946     {
2947         int vpt = abs(dc->vportExtX);
2948         int wnd = abs(dc->wndExtX);
2949         lf.lfWidth = (abs(lf.lfWidth) * vpt + (wnd>>1))/wnd;
2950         if (lf.lfWidth == 0)
2951             lf.lfWidth = 1; /* Minimum width */
2952     }
2953     if (lf.lfHeight)
2954     {
2955         int vpt = abs(dc->vportExtY);
2956         int wnd = abs(dc->wndExtY);
2957         if (lf.lfHeight > 0)
2958             lf.lfHeight = (lf.lfHeight * vpt + (wnd>>1))/wnd;
2959         else
2960             lf.lfHeight = (lf.lfHeight * vpt - (wnd>>1))/wnd;
2961
2962         if (lf.lfHeight == 0)
2963             lf.lfHeight = MIN_FONT_SIZE;
2964     }
2965     else
2966         lf.lfHeight = -(DEF_POINT_SIZE * dc->w.devCaps->logPixelsY + (72>>1)) / 72;
2967     
2968     {
2969         /* Fixup aliases before passing to RealizeFont */
2970         /* alias = Windows name in the alias table */
2971         LPCSTR alias = XFONT_UnAlias( lf.lfFaceName );
2972         LPCSTR faceMatched;
2973
2974         TRACE("hfont=%04x\n", hfont); /* to connect with the trace from RealizeFont */
2975         physDev->font = XFONT_RealizeFont( &lf, &faceMatched );
2976
2977         /* set face to the requested facename if it matched 
2978          * so that GetTextFace can get the correct face name
2979          */
2980         if (alias && !strcmp(faceMatched, lf.lfFaceName))
2981             strcpy( font->logfont.lfFaceName, alias );
2982         else
2983             strcpy( font->logfont.lfFaceName, faceMatched );
2984     }
2985
2986     hPrevFont = dc->w.hFont;
2987     dc->w.hFont = hfont;
2988
2989     LeaveCriticalSection( &crtsc_fonts_X11 );
2990
2991     return hPrevFont;
2992 }
2993
2994
2995 /***********************************************************************
2996  *
2997  *           X11DRV_EnumDeviceFonts
2998  */
2999 BOOL    X11DRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf, 
3000                                         DEVICEFONTENUMPROC proc, LPARAM lp )
3001 {
3002     ENUMLOGFONTEX16     lf;
3003     NEWTEXTMETRIC16     tm;
3004     fontResource*       pfr = fontList;
3005     BOOL                b, bRet = 0;
3006
3007     if( plf->lfFaceName[0] )
3008     {
3009         /* enum all entries in this resource */
3010         pfr = XFONT_FindFIList( pfr, plf->lfFaceName );
3011         if( pfr )
3012         {
3013             fontInfo*   pfi;
3014             for( pfi = pfr->fi; pfi; pfi = pfi->next )
3015             {
3016                 /* Note: XFONT_GetFontMetric() will have to
3017                    release the crit section, font list will
3018                    have to be retraversed on return */
3019
3020                 if( (b = (*proc)( &lf, &tm, 
3021                         XFONT_GetFontMetric( pfi, &lf, &tm ), lp )) )
3022                      bRet = b;
3023                 else break;
3024             }
3025         }
3026     }
3027     else /* enum first entry in each resource */
3028         for( ; pfr ; pfr = pfr->next )
3029         {
3030             if(pfr->fi)
3031             {
3032                 if( (b = (*proc)( &lf, &tm, 
3033                         XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
3034                      bRet = b;
3035                 else break;
3036             }
3037         }
3038     return bRet;
3039 }
3040
3041
3042 /***********************************************************************
3043  *           X11DRV_GetTextExtentPoint
3044  */
3045 BOOL X11DRV_GetTextExtentPoint( DC *dc, LPCWSTR str, INT count,
3046                                   LPSIZE size )
3047 {
3048     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
3049     fontObject* pfo = XFONT_GetFontObject( physDev->font );
3050
3051     TRACE("%s %d\n", debugstr_wn(str,count), count);
3052     if( pfo ) {
3053         if( !pfo->lpX11Trans ) {
3054             int dir, ascent, descent, i;
3055             XCharStruct info;
3056             XChar2b *p = HeapAlloc( GetProcessHeap(), 0,
3057                                     count * sizeof(XChar2b) );
3058             for(i = 0; i < count; i++) {
3059                 p[i].byte1 = str[i] >> 8;
3060                 p[i].byte2 = str[i] & 0xff;
3061             }
3062             TSXTextExtents16( pfo->fs, p, count, &dir, &ascent, &descent, &info );
3063             size->cx = abs((info.width + dc->w.breakRem + count * 
3064                             dc->w.charExtra) * dc->wndExtX / dc->vportExtX);
3065             size->cy = abs((pfo->fs->ascent + pfo->fs->descent) * 
3066                            dc->wndExtY / dc->vportExtY);
3067             HeapFree( GetProcessHeap(), 0, p );
3068         } else {
3069             INT i;
3070             float x = 0.0, y = 0.0;
3071             for(i = 0; i < count; i++) {
3072                 x += pfo->fs->per_char ? 
3073            pfo->fs->per_char[str[i] - pfo->fs->min_char_or_byte2].attributes : 
3074            pfo->fs->min_bounds.attributes;
3075             }
3076             y = pfo->lpX11Trans->RAW_ASCENT + pfo->lpX11Trans->RAW_DESCENT;
3077             TRACE("x = %f y = %f\n", x, y);
3078             x *= pfo->lpX11Trans->pixelsize / 1000.0;
3079             y *= pfo->lpX11Trans->pixelsize / 1000.0; 
3080             size->cx = fabs((x + dc->w.breakRem + count * dc->w.charExtra) *
3081                              dc->wndExtX / dc->vportExtX);
3082             size->cy = fabs(y * dc->wndExtY / dc->vportExtY);
3083         }
3084         size->cx *= pfo->rescale;
3085         size->cy *= pfo->rescale;
3086         return TRUE;
3087     }
3088     return FALSE;
3089 }
3090
3091
3092 /***********************************************************************
3093  *           X11DRV_GetTextMetrics
3094  */
3095 BOOL X11DRV_GetTextMetrics(DC *dc, TEXTMETRICA *metrics)
3096 {
3097     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
3098
3099     if( CHECK_PFONT(physDev->font) )
3100     {
3101         fontObject* pfo = __PFONT(physDev->font);
3102         XFONT_GetTextMetrics( pfo, metrics );
3103
3104         return TRUE;
3105     }
3106     return FALSE;
3107 }
3108
3109
3110 /***********************************************************************
3111  *           X11DRV_GetCharWidth
3112  */
3113 BOOL X11DRV_GetCharWidth( DC *dc, UINT firstChar, UINT lastChar,
3114                             LPINT buffer )
3115 {
3116     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
3117     fontObject* pfo = XFONT_GetFontObject( physDev->font );
3118
3119     if( pfo )
3120     {
3121         int i;
3122
3123         if (pfo->fs->per_char == NULL)
3124             for (i = firstChar; i <= lastChar; i++)
3125                 if(pfo->lpX11Trans)
3126                     *buffer++ = pfo->fs->min_bounds.attributes *
3127                       pfo->lpX11Trans->pixelsize / 1000.0 * pfo->rescale;
3128                 else
3129                     *buffer++ = pfo->fs->min_bounds.width * pfo->rescale;
3130         else
3131         {
3132             XCharStruct *cs, *def;
3133             static XCharStruct  __null_char = { 0, 0, 0, 0, 0, 0 };
3134
3135             CI_GET_CHAR_INFO(pfo->fs, pfo->fs->default_char, &__null_char,
3136                              def);
3137
3138             for (i = firstChar; i <= lastChar; i++)
3139             {
3140                 if (i >= pfo->fs->min_char_or_byte2 && 
3141                     i <= pfo->fs->max_char_or_byte2)
3142                 {
3143                     cs = &pfo->fs->per_char[(i - pfo->fs->min_char_or_byte2)]; 
3144                     if (CI_NONEXISTCHAR(cs)) cs = def; 
3145                 } else cs = def;
3146                 if(pfo->lpX11Trans)
3147                     *buffer++ = MAX(cs->attributes, 0) *
3148                       pfo->lpX11Trans->pixelsize / 1000.0 * pfo->rescale;
3149                 else
3150                     *buffer++ = MAX(cs->width, 0 ) * pfo->rescale;
3151             }
3152         }
3153
3154         return TRUE;
3155     }
3156     return FALSE;
3157 }
3158
3159 #endif /* !defined(X_DISPLAY_MISSING) */
3160
3161 /***********************************************************************
3162  *                                                                     *
3163  *           Font Resource API                                         *
3164  *                                                                     *
3165  ***********************************************************************/
3166 /***********************************************************************
3167  *           AddFontResource16    (GDI.119)
3168  *
3169  *  Can be either .FON, or .FNT, or .TTF, or .FOT font file.
3170  *
3171  *  FIXME: Load header and find the best-matching font in the fontList;
3172  *         fixup dfPoints if all metrics are identical, otherwise create
3173  *         new fontAlias. When soft font support is ready this will
3174  *         simply create a new fontResource ('filename' will go into
3175  *         the pfr->resource field) with FR_SOFTFONT/FR_SOFTRESOURCE 
3176  *         flag set. 
3177  */
3178 INT16 WINAPI AddFontResource16( LPCSTR filename )
3179 {
3180     return AddFontResourceA( filename );
3181 }
3182
3183
3184 /***********************************************************************
3185  *           AddFontResource32A    (GDI32.2)
3186  */
3187 INT WINAPI AddFontResourceA( LPCSTR str )
3188 {
3189     FIXME("(%s): stub\n", debugres_a(str));
3190     return 1;
3191 }
3192
3193
3194 /***********************************************************************
3195  *           AddFontResource32W    (GDI32.4)
3196  */
3197 INT WINAPI AddFontResourceW( LPCWSTR str )
3198 {
3199     FIXME("(%s): stub\n", debugres_w(str) );
3200     return 1;
3201 }
3202
3203 /***********************************************************************
3204  *           RemoveFontResource16    (GDI.136)
3205  */
3206 BOOL16 WINAPI RemoveFontResource16( SEGPTR str )
3207 {
3208     FIXME("(%s): stub\n",       debugres_a(PTR_SEG_TO_LIN(str)));
3209     return TRUE;
3210 }
3211
3212
3213 /***********************************************************************
3214  *           RemoveFontResource32A    (GDI32.284)
3215  */
3216 BOOL WINAPI RemoveFontResourceA( LPCSTR str )
3217 {
3218 /*  This is how it should look like */
3219 /*
3220     fontResource** ppfr;
3221     BOOL32 retVal = FALSE;
3222
3223     EnterCriticalSection( &crtsc_fonts_X11 );
3224     for( ppfr = &fontList; *ppfr; ppfr = &(*ppfr)->next )
3225          if( !strcasecmp( (*ppfr)->lfFaceName, str ) )
3226          {
3227              if(((*ppfr)->fr_flags & (FR_SOFTFONT | FR_SOFTRESOURCE)) &&
3228                  (*ppfr)->hOwnerProcess == GetCurrentProcess() )
3229              {
3230                  if( (*ppfr)->fo_count )
3231                      (*ppfr)->fr_flags |= FR_REMOVED;
3232                  else
3233                      XFONT_RemoveFontResource( ppfr );
3234              }
3235              retVal = TRUE;
3236          }
3237     LeaveCriticalSection( &crtsc_fonts_X11 );
3238     return retVal;
3239  */
3240     FIXME("(%s): stub\n", debugres_a(str));
3241     return TRUE;
3242 }
3243
3244
3245 /***********************************************************************
3246  *           RemoveFontResource32W    (GDI32.286)
3247  */
3248 BOOL WINAPI RemoveFontResourceW( LPCWSTR str )
3249 {
3250     FIXME("(%s): stub\n", debugres_w(str) );
3251     return TRUE;
3252 }
3253