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