~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/gdi32/freetype.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  * FreeType font engine interface
  3  *
  4  * Copyright 2001 Huw D M Davies for CodeWeavers.
  5  * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
  6  *
  7  * This file contains the WineEng* functions.
  8  *
  9  * This library is free software; you can redistribute it and/or
 10  * modify it under the terms of the GNU Lesser General Public
 11  * License as published by the Free Software Foundation; either
 12  * version 2.1 of the License, or (at your option) any later version.
 13  *
 14  * This library is distributed in the hope that it will be useful,
 15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17  * Lesser General Public License for more details.
 18  *
 19  * You should have received a copy of the GNU Lesser General Public
 20  * License along with this library; if not, write to the Free Software
 21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 22  */
 23 
 24 #include "config.h"
 25 #include "wine/port.h"
 26 
 27 #include <stdarg.h>
 28 #include <stdlib.h>
 29 #ifdef HAVE_SYS_STAT_H
 30 # include <sys/stat.h>
 31 #endif
 32 #ifdef HAVE_SYS_MMAN_H
 33 # include <sys/mman.h>
 34 #endif
 35 #include <string.h>
 36 #include <dirent.h>
 37 #include <stdio.h>
 38 #include <assert.h>
 39 
 40 #ifdef HAVE_CARBON_CARBON_H
 41 #define LoadResource __carbon_LoadResource
 42 #define CompareString __carbon_CompareString
 43 #define GetCurrentThread __carbon_GetCurrentThread
 44 #define GetCurrentProcess __carbon_GetCurrentProcess
 45 #define AnimatePalette __carbon_AnimatePalette
 46 #define EqualRgn __carbon_EqualRgn
 47 #define FillRgn __carbon_FillRgn
 48 #define FrameRgn __carbon_FrameRgn
 49 #define GetPixel __carbon_GetPixel
 50 #define InvertRgn __carbon_InvertRgn
 51 #define LineTo __carbon_LineTo
 52 #define OffsetRgn __carbon_OffsetRgn
 53 #define PaintRgn __carbon_PaintRgn
 54 #define Polygon __carbon_Polygon
 55 #define ResizePalette __carbon_ResizePalette
 56 #define SetRectRgn __carbon_SetRectRgn
 57 #include <Carbon/Carbon.h>
 58 #undef LoadResource
 59 #undef CompareString
 60 #undef GetCurrentThread
 61 #undef _CDECL
 62 #undef DPRINTF
 63 #undef GetCurrentProcess
 64 #undef AnimatePalette
 65 #undef EqualRgn
 66 #undef FillRgn
 67 #undef FrameRgn
 68 #undef GetPixel
 69 #undef InvertRgn
 70 #undef LineTo
 71 #undef OffsetRgn
 72 #undef PaintRgn
 73 #undef Polygon
 74 #undef ResizePalette
 75 #undef SetRectRgn
 76 #endif /* HAVE_CARBON_CARBON_H */
 77 
 78 #include "windef.h"
 79 #include "winbase.h"
 80 #include "winternl.h"
 81 #include "winerror.h"
 82 #include "winreg.h"
 83 #include "wingdi.h"
 84 #include "gdi_private.h"
 85 #include "wine/unicode.h"
 86 #include "wine/debug.h"
 87 #include "wine/list.h"
 88 
 89 WINE_DEFAULT_DEBUG_CHANNEL(font);
 90 
 91 #ifdef HAVE_FREETYPE
 92 
 93 #ifdef HAVE_FT2BUILD_H
 94 #include <ft2build.h>
 95 #endif
 96 #ifdef HAVE_FREETYPE_FREETYPE_H
 97 #include <freetype/freetype.h>
 98 #endif
 99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
101 #endif
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
104 #endif
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
110 #else
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
113 # endif
114 #endif
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
117 #endif
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
120 #endif
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
129 #endif
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
132 #endif
133 
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
135 typedef enum
136 {
137     FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138     FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139     FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
141 #endif
142 
143 static FT_Library library = 0;
144 typedef struct
145 {
146     FT_Int major;
147     FT_Int minor;
148     FT_Int patch;
149 } FT_Version_t;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
152 
153 static void *ft_handle = NULL;
154 
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
183 #endif
184 
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
198 #endif
199 
200 #undef MAKE_FUNCPTR
201 
202 #ifndef FT_MAKE_TAG
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204         ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205           ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
206 #endif
207 
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
210 #endif
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
213 #endif
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
216 #endif
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
219 #endif
220 
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
223 #else
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
225 #endif
226 
227 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
228 typedef struct {
229     FT_Short height;
230     FT_Short width;
231     FT_Pos size;
232     FT_Pos x_ppem;
233     FT_Pos y_ppem;
234     FT_Short internal_leading;
235 } Bitmap_Size;
236 
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238    So to let this compile on older versions of FreeType we'll define the
239    new structure here. */
240 typedef struct {
241     FT_Short height, width;
242     FT_Pos size, x_ppem, y_ppem;
243 } My_FT_Bitmap_Size;
244 
245 struct enum_data
246 {
247     ENUMLOGFONTEXW elf;
248     NEWTEXTMETRICEXW ntm;
249     DWORD type;
250 };
251 
252 typedef struct tagFace {
253     struct list entry;
254     WCHAR *StyleName;
255     char *file;
256     void *font_data_ptr;
257     DWORD font_data_size;
258     FT_Long face_index;
259     FONTSIGNATURE fs;
260     FONTSIGNATURE fs_links;
261     DWORD ntmFlags;
262     FT_Fixed font_version;
263     BOOL scalable;
264     Bitmap_Size size;     /* set if face is a bitmap */
265     BOOL external; /* TRUE if we should manually add this font to the registry */
266     struct tagFamily *family;
267     /* Cached data for Enum */
268     struct enum_data *cached_enum_data;
269 } Face;
270 
271 typedef struct tagFamily {
272     struct list entry;
273     const WCHAR *FamilyName;
274     struct list faces;
275 } Family;
276 
277 typedef struct {
278     GLYPHMETRICS gm;
279     INT adv; /* These three hold to widths of the unrotated chars */
280     INT lsb;
281     INT bbx;
282     BOOL init;
283 } GM;
284 
285 typedef struct {
286     FLOAT eM11, eM12;
287     FLOAT eM21, eM22;
288 } FMAT2;
289 
290 typedef struct {
291     DWORD hash;
292     LOGFONTW lf;
293     FMAT2 matrix;
294     BOOL can_use_bitmap;
295 } FONT_DESC;
296 
297 typedef struct tagHFONTLIST {
298     struct list entry;
299     HFONT hfont;
300 } HFONTLIST;
301 
302 typedef struct {
303     struct list entry;
304     Face *face;
305     GdiFont *font;
306 } CHILD_FONT;
307 
308 struct tagGdiFont {
309     struct list entry;
310     GM **gm;
311     DWORD gmsize;
312     struct list hfontlist;
313     OUTLINETEXTMETRICW *potm;
314     DWORD total_kern_pairs;
315     KERNINGPAIR *kern_pairs;
316     struct list child_fonts;
317 
318     /* the following members can be accessed without locking, they are never modified after creation */
319     FT_Face ft_face;
320     struct font_mapping *mapping;
321     LPWSTR name;
322     int charset;
323     int codepage;
324     BOOL fake_italic;
325     BOOL fake_bold;
326     BYTE underline;
327     BYTE strikeout;
328     INT orientation;
329     FONT_DESC font_desc;
330     LONG aveWidth, ppem;
331     double scale_y;
332     SHORT yMax;
333     SHORT yMin;
334     DWORD ntmFlags;
335     FONTSIGNATURE fs;
336     GdiFont *base_font;
337     VOID *GSUB_Table;
338     DWORD cache_num;
339 };
340 
341 typedef struct {
342     struct list entry;
343     const WCHAR *font_name;
344     struct list links;
345 } SYSTEM_LINKS;
346 
347 #define GM_BLOCK_SIZE 128
348 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
349 
350 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
351 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
352 #define UNUSED_CACHE_SIZE 10
353 static struct list child_font_list = LIST_INIT(child_font_list);
354 static struct list system_links = LIST_INIT(system_links);
355 
356 static struct list font_subst_list = LIST_INIT(font_subst_list);
357 
358 static struct list font_list = LIST_INIT(font_list);
359 
360 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
361 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
362 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
363 
364 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
365 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
366                                            'W','i','n','d','o','w','s','\\',
367                                            'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
368                                            'F','o','n','t','s','\0'};
369 
370 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
371                                            'W','i','n','d','o','w','s',' ','N','T','\\',
372                                            'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
373                                            'F','o','n','t','s','\0'};
374 
375 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
376 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
377 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
378 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
379 
380 static const WCHAR * const SystemFontValues[4] = {
381     System_Value,
382     OEMFont_Value,
383     FixedSys_Value,
384     NULL
385 };
386 
387 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
388                                                'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
389 
390 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
391 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
392 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
393 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
394 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
395                                     'E','u','r','o','p','e','a','n','\0'};
396 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
397 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
398 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
399 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
400 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
401 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
402 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
403 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
404 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
405 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
406 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
407 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
408 
409 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
410     WesternW, /*00*/
411     Central_EuropeanW,
412     CyrillicW,
413     GreekW,
414     TurkishW,
415     HebrewW,
416     ArabicW,
417     BalticW,
418     VietnameseW, /*08*/
419     NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
420     ThaiW,
421     JapaneseW,
422     CHINESE_GB2312W,
423     HangulW,
424     CHINESE_BIG5W,
425     Hangul_Johab_W,
426     NULL, NULL, /*23*/
427     NULL, NULL, NULL, NULL, NULL, NULL, NULL,
428     SymbolW /*31*/
429 };
430 
431 typedef struct {
432     WCHAR *name;
433     INT charset;
434 } NameCs;
435 
436 typedef struct tagFontSubst {
437     struct list entry;
438     NameCs from;
439     NameCs to;
440 } FontSubst;
441 
442 struct font_mapping
443 {
444     struct list entry;
445     int         refcount;
446     dev_t       dev;
447     ino_t       ino;
448     void       *data;
449     size_t      size;
450 };
451 
452 static struct list mappings_list = LIST_INIT( mappings_list );
453 
454 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
455 
456 static CRITICAL_SECTION freetype_cs;
457 static CRITICAL_SECTION_DEBUG critsect_debug =
458 {
459     0, 0, &freetype_cs,
460     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
461       0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
462 };
463 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
464 
465 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
466 
467 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
468 static BOOL use_default_fallback = FALSE;
469 
470 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
471 
472 /****************************************
473  *   Notes on .fon files
474  *
475  * The fonts System, FixedSys and Terminal are special.  There are typically multiple
476  * versions installed for different resolutions and codepages.  Windows stores which one to use
477  * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
478  *    Key            Meaning
479  *  FIXEDFON.FON    FixedSys
480  *  FONTS.FON       System
481  *  OEMFONT.FON     Terminal
482  *  LogPixels       Current dpi set by the display control panel applet
483  *                  (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
484  *                  also has a LogPixels value that appears to mirror this)
485  *
486  * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
487  * (vgaoem.fon would be your oemfont.fon if you have a US setup).
488  * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
489  * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
490  * so that makes sense.
491  *
492  * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
493  * to be mapped into the registry on Windows 2000 at least).
494  * I have
495  * woafont=app850.fon
496  * ega80woa.fon=ega80850.fon
497  * ega40woa.fon=ega40850.fon
498  * cga80woa.fon=cga80850.fon
499  * cga40woa.fon=cga40850.fon
500  */
501 
502 /* These are all structures needed for the GSUB table */
503 
504 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
505 #define TATEGAKI_LOWER_BOUND  0x02F1
506 
507 typedef struct {
508     DWORD version;
509     WORD ScriptList;
510     WORD FeatureList;
511     WORD LookupList;
512 } GSUB_Header;
513 
514 typedef struct {
515     CHAR ScriptTag[4];
516     WORD Script;
517 } GSUB_ScriptRecord;
518 
519 typedef struct {
520     WORD ScriptCount;
521     GSUB_ScriptRecord ScriptRecord[1];
522 } GSUB_ScriptList;
523 
524 typedef struct {
525     CHAR LangSysTag[4];
526     WORD LangSys;
527 } GSUB_LangSysRecord;
528 
529 typedef struct {
530     WORD DefaultLangSys;
531     WORD LangSysCount;
532     GSUB_LangSysRecord LangSysRecord[1];
533 } GSUB_Script;
534 
535 typedef struct {
536     WORD LookupOrder; /* Reserved */
537     WORD ReqFeatureIndex;
538     WORD FeatureCount;
539     WORD FeatureIndex[1];
540 } GSUB_LangSys;
541 
542 typedef struct {
543     CHAR FeatureTag[4];
544     WORD Feature;
545 } GSUB_FeatureRecord;
546 
547 typedef struct {
548     WORD FeatureCount;
549     GSUB_FeatureRecord FeatureRecord[1];
550 } GSUB_FeatureList;
551 
552 typedef struct {
553     WORD FeatureParams; /* Reserved */
554     WORD LookupCount;
555     WORD LookupListIndex[1];
556 } GSUB_Feature;
557 
558 typedef struct {
559     WORD LookupCount;
560     WORD Lookup[1];
561 } GSUB_LookupList;
562 
563 typedef struct {
564     WORD LookupType;
565     WORD LookupFlag;
566     WORD SubTableCount;
567     WORD SubTable[1];
568 } GSUB_LookupTable;
569 
570 typedef struct {
571     WORD CoverageFormat;
572     WORD GlyphCount;
573     WORD GlyphArray[1];
574 } GSUB_CoverageFormat1;
575 
576 typedef struct {
577     WORD Start;
578     WORD End;
579     WORD StartCoverageIndex;
580 } GSUB_RangeRecord;
581 
582 typedef struct {
583     WORD CoverageFormat;
584     WORD RangeCount;
585     GSUB_RangeRecord RangeRecord[1];
586 } GSUB_CoverageFormat2;
587 
588 typedef struct {
589     WORD SubstFormat; /* = 1 */
590     WORD Coverage;
591     WORD DeltaGlyphID;
592 } GSUB_SingleSubstFormat1;
593 
594 typedef struct {
595     WORD SubstFormat; /* = 2 */
596     WORD Coverage;
597     WORD GlyphCount;
598     WORD Substitute[1];
599 }GSUB_SingleSubstFormat2;
600 
601 #ifdef HAVE_CARBON_CARBON_H
602 static char *find_cache_dir(void)
603 {
604     FSRef ref;
605     OSErr err;
606     static char cached_path[MAX_PATH];
607     static const char *wine = "/Wine", *fonts = "/Fonts";
608 
609     if(*cached_path) return cached_path;
610 
611     err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
612     if(err != noErr)
613     {
614         WARN("can't create cached data folder\n");
615         return NULL;
616     }
617     err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
618     if(err != noErr)
619     {
620         WARN("can't create cached data path\n");
621         *cached_path = '\0';
622         return NULL;
623     }
624     if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
625     {
626         ERR("Could not create full path\n");
627         *cached_path = '\0';
628         return NULL;
629     }
630     strcat(cached_path, wine);
631 
632     if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
633     {
634         WARN("Couldn't mkdir %s\n", cached_path);
635         *cached_path = '\0';
636         return NULL;
637     }
638     strcat(cached_path, fonts);
639     if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
640     {
641         WARN("Couldn't mkdir %s\n", cached_path);
642         *cached_path = '\0';
643         return NULL;
644     }
645     return cached_path;
646 }
647 
648 /******************************************************************
649  *            expand_mac_font
650  *
651  * Extracts individual TrueType font files from a Mac suitcase font
652  * and saves them into the user's caches directory (see
653  * find_cache_dir()).
654  * Returns a NULL terminated array of filenames.
655  *
656  * We do this because they are apps that try to read ttf files
657  * themselves and they don't like Mac suitcase files.
658  */
659 static char **expand_mac_font(const char *path)
660 {
661     FSRef ref;
662     SInt16 res_ref;
663     OSStatus s;
664     unsigned int idx;
665     const char *out_dir;
666     const char *filename;
667     int output_len;
668     struct {
669         char **array;
670         unsigned int size, max_size;
671     } ret;
672 
673     TRACE("path %s\n", path);
674 
675     s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
676     if(s != noErr)
677     {
678         WARN("failed to get ref\n");
679         return NULL;
680     }
681 
682     s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
683     if(s != noErr)
684     {
685         TRACE("no data fork, so trying resource fork\n");
686         res_ref = FSOpenResFile(&ref, fsRdPerm);
687         if(res_ref == -1)
688         {
689             TRACE("unable to open resource fork\n");
690             return NULL;
691         }
692     }
693 
694     ret.size = 0;
695     ret.max_size = 10;
696     ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
697     if(!ret.array)
698     {
699         CloseResFile(res_ref);
700         return NULL;
701     }
702 
703     out_dir = find_cache_dir();
704 
705     filename = strrchr(path, '/');
706     if(!filename) filename = path;
707     else filename++;
708 
709     /* output filename has the form out_dir/filename_%04x.ttf */
710     output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
711 
712     UseResFile(res_ref);
713     idx = 1;
714     while(1)
715     {
716         FamRec *fam_rec;
717         unsigned short *num_faces_ptr, num_faces, face;
718         AsscEntry *assoc;
719         Handle fond;
720         ResType fond_res = FT_MAKE_TAG('F','O','N','D');
721 
722         fond = Get1IndResource(fond_res, idx);
723         if(!fond) break;
724         TRACE("got fond resource %d\n", idx);
725         HLock(fond);
726 
727         fam_rec = *(FamRec**)fond;
728         num_faces_ptr = (unsigned short *)(fam_rec + 1);
729         num_faces = GET_BE_WORD(*num_faces_ptr);
730         num_faces++;
731         assoc = (AsscEntry*)(num_faces_ptr + 1);
732         TRACE("num faces %04x\n", num_faces);
733         for(face = 0; face < num_faces; face++, assoc++)
734         {
735             Handle sfnt;
736             ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
737             unsigned short size, font_id;
738             char *output;
739 
740             size = GET_BE_WORD(assoc->fontSize);
741             font_id = GET_BE_WORD(assoc->fontID);
742             if(size != 0)
743             {
744                 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
745                 continue;
746             }
747 
748             TRACE("trying to load sfnt id %04x\n", font_id);
749             sfnt = GetResource(sfnt_res, font_id);
750             if(!sfnt)
751             {
752                 TRACE("can't get sfnt resource %04x\n", font_id);
753                 continue;
754             }
755 
756             output = HeapAlloc(GetProcessHeap(), 0, output_len);
757             if(output)
758             {
759                 int fd;
760 
761                 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
762 
763                 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
764                 if(fd != -1 || errno == EEXIST)
765                 {
766                     if(fd != -1)
767                     {
768                         unsigned char *sfnt_data;
769 
770                         HLock(sfnt);
771                         sfnt_data = *(unsigned char**)sfnt;
772                         write(fd, sfnt_data, GetHandleSize(sfnt));
773                         HUnlock(sfnt);
774                         close(fd);
775                     }
776                     if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
777                     {
778                         ret.max_size *= 2;
779                         ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
780                     }
781                     ret.array[ret.size++] = output;
782                 }
783                 else
784                 {
785                     WARN("unable to create %s\n", output);
786                     HeapFree(GetProcessHeap(), 0, output);
787                 }
788             }
789             ReleaseResource(sfnt);
790         }
791         HUnlock(fond);
792         ReleaseResource(fond);
793         idx++;
794     }
795     CloseResFile(res_ref);
796 
797     return ret.array;
798 }
799 
800 #endif /* HAVE_CARBON_CARBON_H */
801 
802 static inline BOOL is_win9x(void)
803 {
804     return GetVersion() & 0x80000000;
805 }
806 /* 
807    This function builds an FT_Fixed from a double. It fails if the absolute
808    value of the float number is greater than 32768.
809 */
810 static inline FT_Fixed FT_FixedFromFloat(double f)
811 {
812         return f * 0x10000;
813 }
814 
815 /* 
816    This function builds an FT_Fixed from a FIXED. It simply put f.value 
817    in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
818 */
819 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
820 {
821         return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
822 }
823 
824 
825 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
826 {
827     Family *family;
828     Face *face;
829     const char *file;
830     DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
831     char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
832 
833     WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
834     TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
835 
836     LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
837     {
838         if(face_name && strcmpiW(face_name, family->FamilyName))
839             continue;
840         LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
841         {
842             if (!face->file)
843                 continue;
844             file = strrchr(face->file, '/');
845             if(!file)
846                 file = face->file;
847             else
848                 file++;
849             if(!strcasecmp(file, file_nameA))
850             {
851                 HeapFree(GetProcessHeap(), 0, file_nameA);
852                 return face;
853             }
854         }
855     }
856     HeapFree(GetProcessHeap(), 0, file_nameA);
857     return NULL;
858 }
859 
860 static Family *find_family_from_name(const WCHAR *name)
861 {
862     Family *family;
863 
864     LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
865     {
866         if(!strcmpiW(family->FamilyName, name))
867             return family;
868     }
869 
870     return NULL;
871 }
872 
873 static void DumpSubstList(void)
874 {
875     FontSubst *psub;
876 
877     LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
878     {
879         if(psub->from.charset != -1 || psub->to.charset != -1)
880             TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
881               psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
882         else
883             TRACE("%s -> %s\n", debugstr_w(psub->from.name),
884                   debugstr_w(psub->to.name));
885     }
886     return;
887 }
888 
889 static LPWSTR strdupW(LPCWSTR p)
890 {
891     LPWSTR ret;
892     DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
893     ret = HeapAlloc(GetProcessHeap(), 0, len);
894     memcpy(ret, p, len);
895     return ret;
896 }
897 
898 static LPSTR strdupA(LPCSTR p)
899 {
900     LPSTR ret;
901     DWORD len = (strlen(p) + 1);
902     ret = HeapAlloc(GetProcessHeap(), 0, len);
903     memcpy(ret, p, len);
904     return ret;
905 }
906 
907 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
908                                  INT from_charset)
909 {
910     FontSubst *element;
911 
912     LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
913     {
914         if(!strcmpiW(element->from.name, from_name) &&
915            (element->from.charset == from_charset ||
916             element->from.charset == -1))
917             return element;
918     }
919 
920     return NULL;
921 }
922 
923 #define ADD_FONT_SUBST_FORCE  1
924 
925 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
926 {
927     FontSubst *from_exist, *to_exist;
928 
929     from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
930 
931     if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
932     {
933         list_remove(&from_exist->entry);
934         HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
935         HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
936         HeapFree(GetProcessHeap(), 0, from_exist);
937         from_exist = NULL;
938     }
939 
940     if(!from_exist)
941     {
942         to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
943 
944         if(to_exist)
945         {
946             HeapFree(GetProcessHeap(), 0, subst->to.name);
947             subst->to.name = strdupW(to_exist->to.name);
948         }
949             
950         list_add_tail(subst_list, &subst->entry);
951 
952         return TRUE;
953     }
954 
955     HeapFree(GetProcessHeap(), 0, subst->from.name);
956     HeapFree(GetProcessHeap(), 0, subst->to.name);
957     HeapFree(GetProcessHeap(), 0, subst);
958     return FALSE;
959 }
960 
961 static void split_subst_info(NameCs *nc, LPSTR str)
962 {
963     CHAR *p = strrchr(str, ',');
964     DWORD len;
965 
966     nc->charset = -1;
967     if(p && *(p+1)) {
968         nc->charset = strtol(p+1, NULL, 10);
969         *p = '\0';
970     }
971     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
972     nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
973     MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
974 }
975 
976 static void LoadSubstList(void)
977 {
978     FontSubst *psub;
979     HKEY hkey;
980     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
981     LPSTR value;
982     LPVOID data;
983 
984     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
985                    "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
986                    &hkey) == ERROR_SUCCESS) {
987 
988         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
989                          &valuelen, &datalen, NULL, NULL);
990 
991         valuelen++; /* returned value doesn't include room for '\0' */
992         value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
993         data = HeapAlloc(GetProcessHeap(), 0, datalen);
994 
995         dlen = datalen;
996         vlen = valuelen;
997         while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
998                             &dlen) == ERROR_SUCCESS) {
999             TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1000 
1001             psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1002             split_subst_info(&psub->from, value);
1003             split_subst_info(&psub->to, data);
1004 
1005             /* Win 2000 doesn't allow mapping between different charsets
1006                or mapping of DEFAULT_CHARSET */
1007             if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1008                psub->to.charset == DEFAULT_CHARSET) {
1009                 HeapFree(GetProcessHeap(), 0, psub->to.name);
1010                 HeapFree(GetProcessHeap(), 0, psub->from.name);
1011                 HeapFree(GetProcessHeap(), 0, psub);
1012             } else {
1013                 add_font_subst(&font_subst_list, psub, 0);
1014             }
1015             /* reset dlen and vlen */
1016             dlen = datalen;
1017             vlen = valuelen;
1018         }
1019         HeapFree(GetProcessHeap(), 0, data);
1020         HeapFree(GetProcessHeap(), 0, value);
1021         RegCloseKey(hkey);
1022     }
1023 }
1024 
1025 static WCHAR *get_familyname(FT_Face ft_face)
1026 {
1027     WCHAR *family = NULL;
1028     FT_SfntName name;
1029     FT_UInt num_names, name_index, i;
1030 
1031     if(FT_IS_SFNT(ft_face))
1032     {
1033         num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1034 
1035         for(name_index = 0; name_index < num_names; name_index++)
1036         {
1037             if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1038             {
1039                 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1040                    (name.language_id == GetUserDefaultLCID()) &&
1041                    (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1042                    (name.encoding_id == TT_MS_ID_UNICODE_CS))
1043                 {
1044                     /* String is not nul terminated and string_len is a byte length. */
1045                     family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1046                     for(i = 0; i < name.string_len / 2; i++)
1047                     {
1048                         WORD *tmp = (WORD *)&name.string[i * 2];
1049                         family[i] = GET_BE_WORD(*tmp);
1050                     }
1051                     family[i] = 0;
1052 
1053                     TRACE("Got localised name %s\n", debugstr_w(family));
1054                     return family;
1055                 }
1056             }
1057         }
1058     }
1059 
1060     return NULL;
1061 }
1062 
1063 
1064 /*****************************************************************
1065  *  load_sfnt_table
1066  *
1067  * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1068  * of FreeType that don't export this function.
1069  *
1070  */
1071 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1072 {
1073 
1074     FT_Error err;
1075 
1076     /* If the FT_Load_Sfnt_Table function is there we'll use it */
1077     if(pFT_Load_Sfnt_Table)
1078     {
1079         err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1080     }
1081 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1082     else  /* Do it the hard way */
1083     {
1084         TT_Face tt_face = (TT_Face) ft_face;
1085         SFNT_Interface *sfnt;
1086         if (FT_Version.major==2 && FT_Version.minor==0)
1087         {
1088             /* 2.0.x */
1089             sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1090         }
1091         else
1092         {
1093             /* A field was added in the middle of the structure in 2.1.x */
1094             sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1095         }
1096         err = sfnt->load_any(tt_face, table, offset, buf, len);
1097     }
1098 #else
1099     else
1100     {
1101         static int msg;
1102         if(!msg)
1103         {
1104             MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1105                     "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1106                     "Please upgrade your freetype library.\n");
1107             msg++;
1108         }
1109         err = FT_Err_Unimplemented_Feature;
1110     }
1111 #endif
1112     return err;
1113 }
1114 
1115 static inline int TestStyles(DWORD flags, DWORD styles)
1116 {
1117     return (flags & styles) == styles;
1118 }
1119 
1120 static int StyleOrdering(Face *face)
1121 {
1122     if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1123         return 3;
1124     if (TestStyles(face->ntmFlags, NTM_ITALIC))
1125         return 2;
1126     if (TestStyles(face->ntmFlags, NTM_BOLD))
1127         return 1;
1128     if (TestStyles(face->ntmFlags, NTM_REGULAR))
1129         return 0;
1130 
1131     WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1132          debugstr_w(face->family->FamilyName),
1133          debugstr_w(face->StyleName),
1134          face->ntmFlags);
1135 
1136     return 9999;
1137 }
1138 
1139 /* Add a style of face to a font family using an ordering of the list such
1140    that regular fonts come before bold and italic, and single styles come
1141    before compound styles.  */
1142 static void AddFaceToFamily(Face *face, Family *family)
1143 {
1144     struct list *entry;
1145 
1146     LIST_FOR_EACH( entry, &family->faces )
1147     {
1148         Face *ent = LIST_ENTRY(entry, Face, entry);
1149         if (StyleOrdering(face) < StyleOrdering(ent)) break;
1150     }
1151     list_add_before( entry, &face->entry );
1152 }
1153 
1154 #define ADDFONT_EXTERNAL_FONT 0x01
1155 #define ADDFONT_FORCE_BITMAP  0x02
1156 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1157 {
1158     FT_Face ft_face;
1159     TT_OS2 *pOS2;
1160     TT_Header *pHeader = NULL;
1161     WCHAR *english_family, *localised_family, *StyleW;
1162     DWORD len;
1163     Family *family;
1164     Face *face;
1165     struct list *family_elem_ptr, *face_elem_ptr;
1166     FT_Error err;
1167     FT_Long face_index = 0, num_faces;
1168 #ifdef HAVE_FREETYPE_FTWINFNT_H
1169     FT_WinFNT_HeaderRec winfnt_header;
1170 #endif
1171     int i, bitmap_num, internal_leading;
1172     FONTSIGNATURE fs;
1173 
1174     /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1175     assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1176 
1177 #ifdef HAVE_CARBON_CARBON_H
1178     if(file && !fake_family)
1179     {
1180         char **mac_list = expand_mac_font(file);
1181         if(mac_list)
1182         {
1183             BOOL had_one = FALSE;
1184             char **cursor;
1185             for(cursor = mac_list; *cursor; cursor++)
1186             {
1187                 had_one = TRUE;
1188                 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1189                 HeapFree(GetProcessHeap(), 0, *cursor);
1190             }
1191             HeapFree(GetProcessHeap(), 0, mac_list);
1192             if(had_one)
1193                 return 1;
1194         }
1195     }
1196 #endif /* HAVE_CARBON_CARBON_H */
1197 
1198     do {
1199         char *family_name = fake_family;
1200 
1201         if (file)
1202         {
1203             TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1204             err = pFT_New_Face(library, file, face_index, &ft_face);
1205         } else
1206         {
1207             TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1208             err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1209         }
1210 
1211         if(err != 0) {
1212             WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1213             return 0;
1214         }
1215 
1216         if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1217             WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1218             pFT_Done_Face(ft_face);
1219             return 0;
1220         }
1221 
1222         /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1223         if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1224             WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1225             pFT_Done_Face(ft_face);
1226             return 0;
1227         }
1228 
1229         if(FT_IS_SFNT(ft_face))
1230         {
1231             if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1232                !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1233                !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1234             {
1235                 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1236                       "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1237                 pFT_Done_Face(ft_face);
1238                 return 0;
1239             }
1240 
1241             /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1242                we don't want to load these. */
1243             if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1244             {
1245                 FT_ULong len = 0;
1246 
1247                 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1248                 {
1249                     TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1250                     pFT_Done_Face(ft_face);
1251                     return 0;
1252                 }
1253             }
1254         }
1255 
1256         if(!ft_face->family_name || !ft_face->style_name) {
1257             TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1258             pFT_Done_Face(ft_face);
1259             return 0;
1260         }
1261 
1262         if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1263         {
1264             TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1265             pFT_Done_Face(ft_face);
1266             return 0;
1267         }
1268 
1269         if (target_family)
1270         {
1271             localised_family = get_familyname(ft_face);
1272             if (localised_family && strcmpiW(localised_family,target_family)!=0)
1273             {
1274                 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1275                 HeapFree(GetProcessHeap(), 0, localised_family);
1276                 num_faces = ft_face->num_faces;
1277                 pFT_Done_Face(ft_face);
1278                 continue;
1279             }
1280             HeapFree(GetProcessHeap(), 0, localised_family);
1281         }
1282 
1283         if(!family_name)
1284             family_name = ft_face->family_name;
1285 
1286         bitmap_num = 0;
1287         do {
1288             My_FT_Bitmap_Size *size = NULL;
1289             FT_ULong tmp_size;
1290 
1291             if(!FT_IS_SCALABLE(ft_face))
1292                 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1293 
1294             len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1295             english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1296             MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1297 
1298             localised_family = NULL;
1299             if(!fake_family) {
1300                 localised_family = get_familyname(ft_face);
1301                 if(localised_family && !strcmpW(localised_family, english_family)) {
1302                     HeapFree(GetProcessHeap(), 0, localised_family);
1303                     localised_family = NULL;
1304                 }
1305             }
1306 
1307             family = NULL;
1308             LIST_FOR_EACH(family_elem_ptr, &font_list) {
1309                 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1310                 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1311                     break;
1312                 family = NULL;
1313             }
1314             if(!family) {
1315                 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1316                 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1317                 list_init(&family->faces);
1318                 list_add_tail(&font_list, &family->entry);
1319 
1320                 if(localised_family) {
1321                     FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1322                     subst->from.name = strdupW(english_family);
1323                     subst->from.charset = -1;
1324                     subst->to.name = strdupW(localised_family);
1325                     subst->to.charset = -1;
1326                     add_font_subst(&font_subst_list, subst, 0);
1327                 }
1328             }
1329             HeapFree(GetProcessHeap(), 0, localised_family);
1330             HeapFree(GetProcessHeap(), 0, english_family);
1331 
1332             len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1333             StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1334             MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1335 
1336             internal_leading = 0;
1337             memset(&fs, 0, sizeof(fs));
1338 
1339             pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1340             if(pOS2) {
1341                 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1342                 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1343                 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1344                 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1345                 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1346                 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1347                 if(pOS2->version == 0) {
1348                     FT_UInt dummy;
1349 
1350                     if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1351                         fs.fsCsb[0] |= FS_LATIN1;
1352                     else
1353                         fs.fsCsb[0] |= FS_SYMBOL;
1354                 }
1355             }
1356 #ifdef HAVE_FREETYPE_FTWINFNT_H
1357             else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1358                 CHARSETINFO csi;
1359                 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1360                       winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1361                 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1362                     fs = csi.fs;
1363                 internal_leading = winfnt_header.internal_leading;
1364             }
1365 #endif
1366 
1367             face_elem_ptr = list_head(&family->faces);
1368             while(face_elem_ptr) {
1369                 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1370                 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1371                 if(!strcmpW(face->StyleName, StyleW) &&
1372                    (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1373                     TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1374                           debugstr_w(family->FamilyName), debugstr_w(StyleW),
1375                           face->font_version,  pHeader ? pHeader->Font_Revision : 0);
1376 
1377                     if(fake_family) {
1378                         TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1379                         HeapFree(GetProcessHeap(), 0, StyleW);
1380                         pFT_Done_Face(ft_face);
1381                         return 1;
1382                     }
1383                     if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1384                         TRACE("Original font is newer so skipping this one\n");
1385                         HeapFree(GetProcessHeap(), 0, StyleW);
1386                         pFT_Done_Face(ft_face);
1387                         return 1;
1388                     } else {
1389                         TRACE("Replacing original with this one\n");
1390                         list_remove(&face->entry);
1391                         HeapFree(GetProcessHeap(), 0, face->file);
1392                         HeapFree(GetProcessHeap(), 0, face->StyleName);
1393                         HeapFree(GetProcessHeap(), 0, face);
1394                         break;
1395                     }
1396                 }
1397             }
1398             face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1399             face->cached_enum_data = NULL;
1400             face->StyleName = StyleW;
1401             if (file)
1402             {
1403                 face->file = strdupA(file);
1404                 face->font_data_ptr = NULL;
1405                 face->font_data_size = 0;
1406             }
1407             else
1408             {
1409                 face->file = NULL;
1410                 face->font_data_ptr = font_data_ptr;
1411                 face->font_data_size = font_data_size;
1412             }
1413             face->face_index = face_index;
1414             face->ntmFlags = 0;
1415             if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1416                 face->ntmFlags |= NTM_ITALIC;
1417             if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1418                 face->ntmFlags |= NTM_BOLD;
1419             if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1420             face->font_version = pHeader ? pHeader->Font_Revision : 0;
1421             face->family = family;
1422             face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1423             face->fs = fs;
1424             memset(&face->fs_links, 0, sizeof(face->fs_links));
1425 
1426             if(FT_IS_SCALABLE(ft_face)) {
1427                 memset(&face->size, 0, sizeof(face->size));
1428                 face->scalable = TRUE;
1429             } else {
1430                 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1431                       size->height, size->width, size->size >> 6,
1432                       size->x_ppem >> 6, size->y_ppem >> 6);
1433                 face->size.height = size->height;
1434                 face->size.width = size->width;
1435                 face->size.size = size->size;
1436                 face->size.x_ppem = size->x_ppem;
1437                 face->size.y_ppem = size->y_ppem;
1438                 face->size.internal_leading = internal_leading;
1439                 face->scalable = FALSE;
1440             }
1441 
1442             /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1443             tmp_size = 0;
1444             if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1445             {
1446                 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1447                 face->ntmFlags |= NTM_PS_OPENTYPE;
1448             }
1449 
1450             TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1451                   face->fs.fsCsb[0], face->fs.fsCsb[1],
1452                   face->fs.fsUsb[0], face->fs.fsUsb[1],
1453                   face->fs.fsUsb[2], face->fs.fsUsb[3]);
1454 
1455 
1456             if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1457                 for(i = 0; i < ft_face->num_charmaps; i++) {
1458                     switch(ft_face->charmaps[i]->encoding) {
1459                     case FT_ENCODING_UNICODE:
1460                     case FT_ENCODING_APPLE_ROMAN:
1461                         face->fs.fsCsb[0] |= FS_LATIN1;
1462                         break;
1463                     case FT_ENCODING_MS_SYMBOL:
1464                         face->fs.fsCsb[0] |= FS_SYMBOL;
1465                         break;
1466                     default:
1467                         break;
1468                     }
1469                 }
1470             }
1471 
1472             if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1473                 have_installed_roman_font = TRUE;
1474 
1475             AddFaceToFamily(face, family);
1476 
1477         } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1478 
1479         num_faces = ft_face->num_faces;
1480         pFT_Done_Face(ft_face);
1481         TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1482               debugstr_w(StyleW));
1483     } while(num_faces > ++face_index);
1484     return num_faces;
1485 }
1486 
1487 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1488 {
1489     return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1490 }
1491 
1492 static void DumpFontList(void)
1493 {
1494     Family *family;
1495     Face *face;
1496     struct list *family_elem_ptr, *face_elem_ptr;
1497 
1498     LIST_FOR_EACH(family_elem_ptr, &font_list) {
1499         family = LIST_ENTRY(family_elem_ptr, Family, entry); 
1500         TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1501         LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1502             face = LIST_ENTRY(face_elem_ptr, Face, entry);
1503             TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1504             if(!face->scalable)
1505                 TRACE(" %d", face->size.height);
1506             TRACE("\n");
1507         }
1508     }
1509     return;
1510 }
1511 
1512 /***********************************************************
1513  * The replacement list is a way to map an entire font
1514  * family onto another family.  For example adding
1515  *
1516  * [HKCU\Software\Wine\Fonts\Replacements]
1517  * "Wingdings"="Winedings"
1518  *
1519  * would enumerate the Winedings font both as Winedings and
1520  * Wingdings.  However if a real Wingdings font is present the
1521  * replacement does not take place.
1522  * 
1523  */
1524 static void LoadReplaceList(void)
1525 {
1526     HKEY hkey;
1527     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1528     LPWSTR value;
1529     LPVOID data;
1530     Family *family;
1531     Face *face;
1532     struct list *family_elem_ptr, *face_elem_ptr;
1533     CHAR familyA[400];
1534 
1535     /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1536     if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1537     {
1538         RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1539                          &valuelen, &datalen, NULL, NULL);
1540 
1541         valuelen++; /* returned value doesn't include room for '\0' */
1542         value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1543         data = HeapAlloc(GetProcessHeap(), 0, datalen);
1544 
1545         dlen = datalen;
1546         vlen = valuelen;
1547         while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1548                             &dlen) == ERROR_SUCCESS) {
1549             TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1550             /* "NewName"="Oldname" */
1551             WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1552 
1553             /* Find the old family and hence all of the font files
1554                in that family */
1555             LIST_FOR_EACH(family_elem_ptr, &font_list) {
1556                 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1557                 if(!strcmpiW(family->FamilyName, data)) {
1558                     LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1559                         face = LIST_ENTRY(face_elem_ptr, Face, entry);
1560                         TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1561                               debugstr_w(face->StyleName), familyA);
1562                         /* Now add a new entry with the new family name */
1563                         AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1564                     }
1565                     break;
1566                 }
1567             }
1568             /* reset dlen and vlen */
1569             dlen = datalen;
1570             vlen = valuelen;
1571         }
1572         HeapFree(GetProcessHeap(), 0, data);
1573         HeapFree(GetProcessHeap(), 0, value);
1574         RegCloseKey(hkey);
1575     }
1576 }
1577 
1578 /*************************************************************
1579  * init_system_links
1580  */
1581 static BOOL init_system_links(void)
1582 {
1583     static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1584                                         'W','i','n','d','o','w','s',' ','N','T','\\',
1585                                         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1586                                         'S','y','s','t','e','m','L','i','n','k',0};
1587     HKEY hkey;
1588     BOOL ret = FALSE;
1589     DWORD type, max_val, max_data, val_len, data_len, index;
1590     WCHAR *value, *data;
1591     WCHAR *entry, *next;
1592     SYSTEM_LINKS *font_link, *system_font_link;
1593     CHILD_FONT *child_font;
1594     static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1595     static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1596     static const WCHAR System[] = {'S','y','s','t','e','m',0};
1597     FONTSIGNATURE fs;
1598     Family *family;
1599     Face *face;
1600     FontSubst *psub;
1601 
1602     if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1603     {
1604         RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1605         value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1606         data = HeapAlloc(GetProcessHeap(), 0, max_data);
1607         val_len = max_val + 1;
1608         data_len = max_data;
1609         index = 0;
1610         while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1611         {
1612             TRACE("%s:\n", debugstr_w(value));
1613 
1614             memset(&fs, 0, sizeof(fs));
1615             font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1616             psub = get_font_subst(&font_subst_list, value, -1);
1617             font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1618             list_init(&font_link->links);
1619             for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1620             {
1621                 WCHAR *face_name;
1622                 CHILD_FONT *child_font;
1623 
1624                 TRACE("\t%s\n", debugstr_w(entry));
1625 
1626                 next = entry + strlenW(entry) + 1;
1627                 
1628                 face_name = strchrW(entry, ',');
1629                 if(face_name)
1630                 {
1631                     *face_name++ = 0;
1632                     while(isspaceW(*face_name))
1633                         face_name++;
1634 
1635                     psub = get_font_subst(&font_subst_list, face_name, -1);
1636                     if(psub)
1637                         face_name = psub->to.name;
1638                 }
1639                 face = find_face_from_filename(entry, face_name);
1640                 if(!face)
1641                 {
1642                     TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1643                     continue;
1644                 }
1645 
1646                 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1647                 child_font->face = face;
1648                 child_font->font = NULL;
1649                 fs.fsCsb[0] |= face->fs.fsCsb[0];
1650                 fs.fsCsb[1] |= face->fs.fsCsb[1];
1651                 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1652                 list_add_tail(&font_link->links, &child_font->entry);
1653             }
1654             family = find_family_from_name(font_link->font_name);
1655             if(family)
1656             {
1657                 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1658                 {
1659                     face->fs_links = fs;
1660                 }
1661             }
1662             list_add_tail(&system_links, &font_link->entry);
1663             val_len = max_val + 1;
1664             data_len = max_data;
1665         }
1666 
1667         HeapFree(GetProcessHeap(), 0, value);
1668         HeapFree(GetProcessHeap(), 0, data);
1669         RegCloseKey(hkey);
1670     }
1671 
1672     /* Explicitly add an entry for the system font, this links to Tahoma and any links
1673        that Tahoma has */
1674 
1675     system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1676     system_font_link->font_name = strdupW(System);
1677     list_init(&system_font_link->links);    
1678 
1679     face = find_face_from_filename(tahoma_ttf, Tahoma);
1680     if(face)
1681     {
1682         child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1683         child_font->face = face;
1684         child_font->font = NULL;
1685         TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1686         list_add_tail(&system_font_link->links, &child_font->entry);
1687     }
1688     LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1689     {
1690         if(!strcmpiW(font_link->font_name, Tahoma))
1691         {
1692             CHILD_FONT *font_link_entry;
1693             LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1694             {
1695                 CHILD_FONT *new_child;
1696                 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1697                 new_child->face = font_link_entry->face;
1698                 new_child->font = NULL;
1699                 list_add_tail(&system_font_link->links, &new_child->entry);
1700             }
1701             break;
1702         }
1703     }
1704     list_add_tail(&system_links, &system_font_link->entry);
1705     return ret;
1706 }
1707 
1708 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1709 {
1710     DIR *dir;
1711     struct dirent *dent;
1712     char path[MAX_PATH];
1713 
1714     TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1715 
1716     dir = opendir(dirname);
1717     if(!dir) {
1718         WARN("Can't open directory %s\n", debugstr_a(dirname));
1719         return FALSE;
1720     }
1721     while((dent = readdir(dir)) != NULL) {
1722         struct stat statbuf;
1723 
1724         if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1725             continue;
1726 
1727         TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1728 
1729         sprintf(path, "%s/%s", dirname, dent->d_name);
1730 
1731         if(stat(path, &statbuf) == -1)
1732         {
1733             WARN("Can't stat %s\n", debugstr_a(path));
1734             continue;
1735         }
1736         if(S_ISDIR(statbuf.st_mode))
1737             ReadFontDir(path, external_fonts);
1738         else
1739             AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1740     }
1741     closedir(dir);
1742     return TRUE;
1743 }
1744 
1745 static void load_fontconfig_fonts(void)
1746 {
1747 #ifdef SONAME_LIBFONTCONFIG
1748     void *fc_handle = NULL;
1749     FcConfig *config;
1750     FcPattern *pat;
1751     FcObjectSet *os;
1752     FcFontSet *fontset;
1753     int i, len;
1754     char *file;
1755     const char *ext;
1756 
1757     fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1758     if(!fc_handle) {
1759         TRACE("Wine cannot find the fontconfig library (%s).\n",
1760               SONAME_LIBFONTCONFIG);
1761         return;
1762     }
1763 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1764 LOAD_FUNCPTR(FcConfigGetCurrent);
1765 LOAD_FUNCPTR(FcFontList);
1766 LOAD_FUNCPTR(FcFontSetDestroy);
1767 LOAD_FUNCPTR(FcInit);
1768 LOAD_FUNCPTR(FcObjectSetAdd);
1769 LOAD_FUNCPTR(FcObjectSetCreate);
1770 LOAD_FUNCPTR(FcObjectSetDestroy);
1771 LOAD_FUNCPTR(FcPatternCreate);
1772 LOAD_FUNCPTR(FcPatternDestroy);
1773 LOAD_FUNCPTR(FcPatternGetBool);
1774 LOAD_FUNCPTR(FcPatternGetString);
1775 #undef LOAD_FUNCPTR
1776 
1777     if(!pFcInit()) return;
1778     
1779     config = pFcConfigGetCurrent();
1780     pat = pFcPatternCreate();
1781     os = pFcObjectSetCreate();
1782     pFcObjectSetAdd(os, FC_FILE);
1783     pFcObjectSetAdd(os, FC_SCALABLE);
1784     fontset = pFcFontList(config, pat, os);
1785     if(!fontset) return;
1786     for(i = 0; i < fontset->nfont; i++) {
1787         FcBool scalable;
1788 
1789         if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1790             continue;
1791         TRACE("fontconfig: %s\n", file);
1792 
1793         /* We're just interested in OT/TT fonts for now, so this hack just
1794            picks up the scalable fonts without extensions .pf[ab] to save time
1795            loading every other font */
1796 
1797         if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1798         {
1799             TRACE("not scalable\n");
1800             continue;
1801         }
1802 
1803         len = strlen( file );
1804         if(len < 4) continue;
1805         ext = &file[ len - 3 ];
1806         if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1807             AddFontFileToList(file, NULL, NULL,  ADDFONT_EXTERNAL_FONT);
1808     }
1809     pFcFontSetDestroy(fontset);
1810     pFcObjectSetDestroy(os);
1811     pFcPatternDestroy(pat);
1812  sym_not_found:
1813 #endif
1814     return;
1815 }
1816 
1817 static BOOL load_font_from_data_dir(LPCWSTR file)
1818 {
1819     BOOL ret = FALSE;
1820     const char *data_dir = wine_get_data_dir();
1821 
1822     if (!data_dir) data_dir = wine_get_build_dir();
1823 
1824     if (data_dir)
1825     {
1826         INT len;
1827         char *unix_name;
1828 
1829         len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1830 
1831         unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1832 
1833         strcpy(unix_name, data_dir);
1834         strcat(unix_name, "/fonts/");
1835 
1836         WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1837 
1838         EnterCriticalSection( &freetype_cs );
1839         ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1840         LeaveCriticalSection( &freetype_cs );
1841         HeapFree(GetProcessHeap(), 0, unix_name);
1842     }
1843     return ret;
1844 }
1845 
1846 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1847 {
1848     static const WCHAR slashW[] = {'\\','\0'};
1849     BOOL ret = FALSE;
1850     WCHAR windowsdir[MAX_PATH];
1851     char *unixname;
1852 
1853     GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1854     strcatW(windowsdir, fontsW);
1855     strcatW(windowsdir, slashW);
1856     strcatW(windowsdir, file);
1857     if ((unixname = wine_get_unix_file_name(windowsdir))) {
1858         EnterCriticalSection( &freetype_cs );
1859         ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1860         LeaveCriticalSection( &freetype_cs );
1861         HeapFree(GetProcessHeap(), 0, unixname);
1862     }
1863     return ret;
1864 }
1865 
1866 static void load_system_fonts(void)
1867 {
1868     HKEY hkey;
1869     WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1870     const WCHAR * const *value;
1871     DWORD dlen, type;
1872     static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1873     char *unixname;
1874 
1875     if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1876         GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1877         strcatW(windowsdir, fontsW);
1878         for(value = SystemFontValues; *value; value++) { 
1879             dlen = sizeof(data);
1880             if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1881                type == REG_SZ) {
1882                 BOOL added = FALSE;
1883 
1884                 sprintfW(pathW, fmtW, windowsdir, data);
1885                 if((unixname = wine_get_unix_file_name(pathW))) {
1886                     added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1887                     HeapFree(GetProcessHeap(), 0, unixname);
1888                 }
1889                 if (!added)
1890                     load_font_from_data_dir(data);
1891             }
1892         }
1893         RegCloseKey(hkey);
1894     }
1895 }
1896 
1897 /*************************************************************
1898  *
1899  * This adds registry entries for any externally loaded fonts
1900  * (fonts from fontconfig or FontDirs).  It also deletes entries
1901  * of no longer existing fonts.
1902  *
1903  */
1904 static void update_reg_entries(void)
1905 {
1906     HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1907     LPWSTR valueW;
1908     DWORD len, len_fam;
1909     Family *family;
1910     Face *face;
1911     struct list *family_elem_ptr, *face_elem_ptr;
1912     WCHAR *file;
1913     static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1914     static const WCHAR spaceW[] = {' ', '\0'};
1915     char *path;
1916 
1917     if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1918                        0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1919         ERR("Can't create Windows font reg key\n");
1920         goto end;
1921     }
1922 
1923     if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1924                        0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1925         ERR("Can't create Windows font reg key\n");
1926         goto end;
1927     }
1928 
1929     if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1930                        0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1931         ERR("Can't create external font reg key\n");
1932         goto end;
1933     }
1934 
1935     /* enumerate the fonts and add external ones to the two keys */
1936 
1937     LIST_FOR_EACH(family_elem_ptr, &font_list) {
1938         family = LIST_ENTRY(family_elem_ptr, Family, entry); 
1939         len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1940         LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1941             face = LIST_ENTRY(face_elem_ptr, Face, entry);
1942             if(!face->external) continue;
1943             len = len_fam;
1944             if (!(face->ntmFlags & NTM_REGULAR))
1945                 len = len_fam + strlenW(face->StyleName) + 1;
1946             valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1947             strcpyW(valueW, family->FamilyName);
1948             if(len != len_fam) {
1949                 strcatW(valueW, spaceW);
1950                 strcatW(valueW, face->StyleName);
1951             }
1952             strcatW(valueW, TrueType);
1953 
1954             file = wine_get_dos_file_name(face->file);
1955             if(file)
1956                 len = strlenW(file) + 1;
1957             else
1958             {
1959                 if((path = strrchr(face->file, '/')) == NULL)
1960                     path = face->file;
1961                 else
1962                     path++;
1963                 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1964 
1965                 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1966                 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1967             }
1968             RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1969             RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1970             RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1971 
1972             HeapFree(GetProcessHeap(), 0, file);
1973             HeapFree(GetProcessHeap(), 0, valueW);
1974         }
1975     }
1976  end:
1977     if(external_key) RegCloseKey(external_key);
1978     if(win9x_key) RegCloseKey(win9x_key);
1979     if(winnt_key) RegCloseKey(winnt_key);
1980     return;
1981 }
1982 
1983 static void delete_external_font_keys(void)
1984 {
1985     HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1986     DWORD dlen, vlen, datalen, valuelen, i, type;
1987     LPWSTR valueW;
1988     LPVOID data;
1989 
1990     if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1991                        0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1992         ERR("Can't create Windows font reg key\n");
1993         goto end;
1994     }
1995 
1996     if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1997                        0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1998         ERR("Can't create Windows font reg key\n");
1999         goto end;
2000     }
2001 
2002     if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2003         ERR("Can't create external font reg key\n");
2004         goto end;
2005     }
2006 
2007     /* Delete all external fonts added last time */
2008 
2009     RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2010                      &valuelen, &datalen, NULL, NULL);
2011     valuelen++; /* returned value doesn't include room for '\0' */
2012     valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2013     data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2014 
2015     dlen = datalen * sizeof(WCHAR);
2016     vlen = valuelen;
2017     i = 0;
2018     while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2019                         &dlen) == ERROR_SUCCESS) {
2020 
2021         RegDeleteValueW(winnt_key, valueW);
2022         RegDeleteValueW(win9x_key, valueW);
2023         /* reset dlen and vlen */
2024         dlen = datalen;
2025         vlen = valuelen;
2026     }
2027     HeapFree(GetProcessHeap(), 0, data);
2028     HeapFree(GetProcessHeap(), 0, valueW);
2029 
2030     /* Delete the old external fonts key */
2031     RegCloseKey(external_key);
2032     RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2033 
2034  end:
2035     if(win9x_key) RegCloseKey(win9x_key);
2036     if(winnt_key) RegCloseKey(winnt_key);
2037 }
2038 
2039 /*************************************************************
2040  *    WineEngAddFontResourceEx
2041  *
2042  */
2043 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2044 {
2045     INT ret = 0;
2046     if (ft_handle)  /* do it only if we have freetype up and running */
2047     {
2048         char *unixname;
2049 
2050         if(flags)
2051             FIXME("Ignoring flags %x\n", flags);
2052 
2053         if((unixname = wine_get_unix_file_name(file)))
2054         {
2055             EnterCriticalSection( &freetype_cs );
2056             ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2057             LeaveCriticalSection( &freetype_cs );
2058             HeapFree(GetProcessHeap(), 0, unixname);
2059         }
2060         if (!ret && !strchrW(file, '\\')) {
2061             /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2062             ret = load_font_from_winfonts_dir(file);
2063             if (!ret) {
2064                 /* Try in datadir/fonts (or builddir/fonts),
2065                  * needed for Magic the Gathering Online
2066                  */
2067                 ret = load_font_from_data_dir(file);
2068             }
2069         }
2070     }
2071    return ret;
2072 }
2073 
2074 /*************************************************************
2075  *    WineEngAddFontMemResourceEx
2076  *
2077  */
2078 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2079 {
2080     if (ft_handle)  /* do it only if we have freetype up and running */
2081     {
2082         PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2083 
2084         TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2085         memcpy(pFontCopy, pbFont, cbFont);
2086 
2087         EnterCriticalSection( &freetype_cs );
2088         *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2089         LeaveCriticalSection( &freetype_cs );
2090 
2091         if (*pcFonts == 0)
2092         {
2093             TRACE("AddFontToList failed\n");
2094             HeapFree(GetProcessHeap(), 0, pFontCopy);
2095             return NULL;
2096         }
2097         /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2098          * For now return something unique but quite random
2099          */
2100         TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2101         return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2102     }
2103 
2104     *pcFonts = 0;
2105     return 0;
2106 }
2107 
2108 /*************************************************************
2109  *    WineEngRemoveFontResourceEx
2110  *
2111  */
2112 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2113 {
2114     FIXME(":stub\n");
2115     return TRUE;
2116 }
2117 
2118 static const struct nls_update_font_list
2119 {
2120     UINT ansi_cp, oem_cp;
2121     const char *oem, *fixed, *system;
2122     const char *courier, *serif, *small, *sserif;
2123     /* these are for font substitutes */
2124     const char *shelldlg, *tmsrmn;
2125     const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2126                *helv_0, *tmsrmn_0;
2127     const struct subst
2128     {
2129         const char *from, *to;
2130     } arial_0, courier_new_0, times_new_roman_0;
2131 } nls_update_font_list[] =
2132 {
2133     /* Latin 1 (United States) */
2134     { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2135       "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2136       "Tahoma","Times New Roman",
2137       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2138       { 0 }, { 0 }, { 0 }
2139     },
2140     /* Latin 1 (Multilingual) */
2141     { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2142       "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2143       "Tahoma","Times New Roman",  /* FIXME unverified */
2144       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2145       { 0 }, { 0 }, { 0 }
2146     },
2147     /* Eastern Europe */
2148     { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2149       "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2150       "Tahoma","Times New Roman", /* FIXME unverified */
2151       "Fixedsys,238", "System,238",
2152       "Courier New,238", "MS Serif,238", "Small Fonts,238",
2153       "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2154       { "Arial CE,0", "Arial,238" },
2155       { "Courier New CE,0", "Courier New,238" },
2156       { "Times New Roman CE,0", "Times New Roman,238" }
2157     },
2158     /* Cyrillic */
2159     { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2160       "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2161       "Tahoma","Times New Roman", /* FIXME unverified */
2162       "Fixedsys,204", "System,204",
2163       "Courier New,204", "MS Serif,204", "Small Fonts,204",
2164       "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2165       { "Arial Cyr,0", "Arial,204" },
2166       { "Courier New Cyr,0", "Courier New,204" },
2167       { "Times New Roman Cyr,0", "Times New Roman,204" }
2168     },
2169     /* Greek */
2170     { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2171       "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2172       "Tahoma","Times New Roman", /* FIXME unverified */
2173       "Fixedsys,161", "System,161",
2174       "Courier New,161", "MS Serif,161", "Small Fonts,161",
2175       "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2176       { "Arial Greek,0", "Arial,161" },
2177       { "Courier New Greek,0", "Courier New,161" },
2178       { "Times New Roman Greek,0", "Times New Roman,161" }
2179     },
2180     /* Turkish */
2181     { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2182       "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2183       "Tahoma","Times New Roman", /* FIXME unverified */
2184       "Fixedsys,162", "System,162",
2185       "Courier New,162", "MS Serif,162", "Small Fonts,162",
2186       "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2187       { "Arial Tur,0", "Arial,162" },
2188       { "Courier New Tur,0", "Courier New,162" },
2189       { "Times New Roman Tur,0", "Times New Roman,162" }
2190     },
2191     /* Hebrew */
2192     { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2193       "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2194       "Tahoma","Times New Roman", /* FIXME unverified */
2195       "Fixedsys,177", "System,177",
2196       "Courier New,177", "MS Serif,177", "Small Fonts,177",
2197       "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2198       { 0 }, { 0 }, { 0 }
2199     },
2200     /* Arabic */
2201     { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2202       "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2203       "Tahoma","Times New Roman", /* FIXME unverified */
2204       "Fixedsys,178", "System,178",
2205       "Courier New,178", "MS Serif,178", "Small Fonts,178",
2206       "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2207       { 0 }, { 0 }, { 0 }
2208     },
2209     /* Baltic */
2210     { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2211       "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2212       "Tahoma","Times New Roman", /* FIXME unverified */
2213       "Fixedsys,186", "System,186",
2214       "Courier New,186", "MS Serif,186", "Small Fonts,186",
2215       "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2216       { "Arial Baltic,0", "Arial,186" },
2217       { "Courier New Baltic,0", "Courier New,186" },
2218       { "Times New Roman Baltic,0", "Times New Roman,186" }
2219     },
2220     /* Vietnamese */
2221     { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2222       "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2223       "Tahoma","Times New Roman", /* FIXME unverified */
2224       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2225       { 0 }, { 0 }, { 0 }
2226     },
2227     /* Thai */
2228     { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2229       "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2230       "Tahoma","Times New Roman", /* FIXME unverified */
2231       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2232       { 0 }, { 0 }, { 0 }
2233     },
2234     /* Japanese */
2235     { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2236       "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2237       "MS UI Gothic","MS Serif",
2238       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2239       { 0 }, { 0 }, { 0 }
2240     },
2241     /* Chinese Simplified */
2242     { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2243       "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2244       "Tahoma", "Times New Roman", /* FIXME unverified */
2245       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2246       { 0 }, { 0 }, { 0 }
2247     },
2248     /* Korean */
2249     { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2250       "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2251       "Gulim",  "Batang",
2252       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2253       { 0 }, { 0 }, { 0 }
2254     },
2255     /* Chinese Traditional */
2256     { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2257       "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2258       "PMingLiU",  "MingLiU",
2259       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2260       { 0 }, { 0 }, { 0 }
2261     }
2262 };
2263 
2264 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2265 {
2266     return ( ansi_cp == 932       /* CP932 for Japanese */
2267             || ansi_cp == 936     /* CP936 for Chinese Simplified */
2268             || ansi_cp == 949     /* CP949 for Korean */
2269             || ansi_cp == 950 );  /* CP950 for Chinese Traditional */
2270 }
2271 
2272 static inline HKEY create_fonts_NT_registry_key(void)
2273 {
2274     HKEY hkey = 0;
2275 
2276     RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2277                     0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2278     return hkey;
2279 }
2280 
2281 static inline HKEY create_fonts_9x_registry_key(void)
2282 {
2283     HKEY hkey = 0;
2284 
2285     RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2286                     0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2287     return hkey;
2288 }
2289 
2290 static inline HKEY create_config_fonts_registry_key(void)
2291 {
2292     HKEY hkey = 0;
2293 
2294     RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2295                     0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2296     return hkey;
2297 }
2298 
2299 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2300 {
2301     RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2302     RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2303     RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2304     RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2305 }
2306 
2307 static void set_value_key(HKEY hkey, const char *name, const char *value)
2308 {
2309     if (value)
2310         RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2311     else if (name)
2312         RegDeleteValueA(hkey, name);
2313 }
2314 
2315 static void update_font_info(void)
2316 {
2317     char buf[40], cpbuf[40];
2318     DWORD len, type;
2319     HKEY hkey = 0;
2320     UINT i, ansi_cp = 0, oem_cp = 0;
2321     BOOL done = FALSE;
2322 
2323     if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2324         return;
2325 
2326     GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2327                    (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2328     GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2329                    (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2330     sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2331 
2332     /* Setup Default_Fallback usage for DBCS ANSI codepages */
2333     if (is_dbcs_ansi_cp(ansi_cp))
2334         use_default_fallback = TRUE;
2335 
2336     len = sizeof(buf);
2337     if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2338     {
2339         if (!strcmp( buf, cpbuf ))  /* already set correctly */
2340         {
2341             RegCloseKey(hkey);
2342             return;
2343         }
2344         TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2345     }
2346     else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2347 
2348     RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2349     RegCloseKey(hkey);
2350 
2351     for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2352     {
2353         HKEY hkey;
2354 
2355         if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2356             nls_update_font_list[i].oem_cp == oem_cp)
2357         {
2358             hkey = create_config_fonts_registry_key();
2359             RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2360             RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2361             RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2362             RegCloseKey(hkey);
2363 
2364             hkey = create_fonts_NT_registry_key();
2365             add_font_list(hkey, &nls_update_font_list[i]);
2366             RegCloseKey(hkey);
2367 
2368             hkey = create_fonts_9x_registry_key();
2369             add_font_list(hkey, &nls_update_font_list[i]);
2370             RegCloseKey(hkey);
2371 
2372             if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2373             {
2374                 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2375                                strlen(nls_update_font_list[i].shelldlg)+1);
2376                 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2377                                strlen(nls_update_font_list[i].tmsrmn)+1);
2378 
2379                 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2380                 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2381                 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2382                 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2383                 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2384                 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2385                 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2386                 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2387 
2388                 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2389                 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2390                 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2391 
2392                 RegCloseKey(hkey);
2393             }
2394             done = TRUE;
2395         }
2396         else
2397         {
2398             /* Delete the FontSubstitutes from other locales */
2399             if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2400             {
2401                 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2402                 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2403                 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2404                 RegCloseKey(hkey);
2405             }
2406         }
2407     }
2408     if (!done)
2409         FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2410 }
2411 
2412 
2413 static BOOL init_freetype(void)
2414 {
2415     ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2416     if(!ft_handle) {
2417         WINE_MESSAGE(
2418       "Wine cannot find the FreeType font library.  To enable Wine to\n"
2419       "use TrueType fonts please install a version of FreeType greater than\n"
2420       "or equal to 2.0.5.\n"
2421       "http://www.freetype.org\n");
2422         return FALSE;
2423     }
2424 
2425 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
2426 
2427     LOAD_FUNCPTR(FT_Vector_Unit)
2428     LOAD_FUNCPTR(FT_Done_Face)
2429     LOAD_FUNCPTR(FT_Get_Char_Index)
2430     LOAD_FUNCPTR(FT_Get_Module)
2431     LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2432     LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2433     LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2434     LOAD_FUNCPTR(FT_Init_FreeType)
2435     LOAD_FUNCPTR(FT_Load_Glyph)
2436     LOAD_FUNCPTR(FT_Matrix_Multiply)
2437     LOAD_FUNCPTR(FT_MulFix)
2438     LOAD_FUNCPTR(FT_New_Face)
2439     LOAD_FUNCPTR(FT_New_Memory_Face)
2440     LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2441     LOAD_FUNCPTR(FT_Outline_Transform)
2442     LOAD_FUNCPTR(FT_Outline_Translate)
2443     LOAD_FUNCPTR(FT_Select_Charmap)
2444     LOAD_FUNCPTR(FT_Set_Charmap)
2445     LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2446     LOAD_FUNCPTR(FT_Vector_Transform)
2447 
2448 #undef LOAD_FUNCPTR
2449     /* Don't warn if these ones are missing */
2450     pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2451     pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2452     pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2453     pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2454     pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2455 #ifdef HAVE_FREETYPE_FTWINFNT_H
2456     pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2457 #endif
2458       if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2459          !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2460         /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2461            <= 2.0.3 has FT_Sqrt64 */
2462           goto sym_not_found;
2463       }
2464 
2465     if(pFT_Init_FreeType(&library) != 0) {
2466         ERR("Can't init FreeType library\n");
2467         wine_dlclose(ft_handle, NULL, 0);
2468         ft_handle = NULL;
2469         return FALSE;
2470     }
2471     FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2472     if (pFT_Library_Version)
2473         pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2474 
2475     if (FT_Version.major<=0)
2476     {
2477         FT_Version.major=2;
2478         FT_Version.minor=0;
2479         FT_Version.patch=5;
2480     }
2481     TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2482     FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2483                        ((FT_Version.minor <<  8) & 0x00ff00) |
2484                        ((FT_Version.patch      ) & 0x0000ff);
2485 
2486     return TRUE;
2487 
2488 sym_not_found:
2489     WINE_MESSAGE(
2490       "Wine cannot find certain functions that it needs inside the FreeType\n"
2491       "font library.  To enable Wine to use TrueType fonts please upgrade\n"
2492       "FreeType to at least version 2.0.5.\n"
2493       "http://www.freetype.org\n");
2494     wine_dlclose(ft_handle, NULL, 0);
2495     ft_handle = NULL;
2496     return FALSE;
2497 }
2498 
2499 /*************************************************************
2500  *    WineEngInit
2501  *
2502  * Initialize FreeType library and create a list of available faces
2503  */
2504 BOOL WineEngInit(void)
2505 {
2506     static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2507     static const WCHAR pathW[] = {'P','a','t','h',0};
2508     HKEY hkey;
2509     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2510     LPVOID data;
2511     WCHAR windowsdir[MAX_PATH];
2512     char *unixname;
2513     HANDLE font_mutex;
2514     const char *data_dir;
2515 
2516     TRACE("\n");
2517 
2518     /* update locale dependent font info in registry */
2519     update_font_info();
2520 
2521     if(!init_freetype()) return FALSE;
2522 
2523     if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2524         ERR("Failed to create font mutex\n");
2525         return FALSE;
2526     }
2527     WaitForSingleObject(font_mutex, INFINITE);
2528 
2529     delete_external_font_keys();
2530 
2531     /* load the system bitmap fonts */
2532     load_system_fonts();
2533 
2534     /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2535     GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2536     strcatW(windowsdir, fontsW);
2537     if((unixname = wine_get_unix_file_name(windowsdir)))
2538     {
2539         ReadFontDir(unixname, FALSE);
2540         HeapFree(GetProcessHeap(), 0, unixname);
2541     }
2542 
2543     /* load the system truetype fonts */
2544     data_dir = wine_get_data_dir();
2545     if (!data_dir) data_dir = wine_get_build_dir();
2546     if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2547         strcpy(unixname, data_dir);
2548         strcat(unixname, "/fonts/");
2549         ReadFontDir(unixname, TRUE);
2550         HeapFree(GetProcessHeap(), 0, unixname);
2551     }
2552 
2553     /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2554        for any fonts not installed in %WINDOWSDIR%\Fonts.  They will have their
2555        full path as the entry.  Also look for any .fon fonts, since ReadFontDir
2556        will skip these. */
2557     if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2558                    is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2559                    &hkey) == ERROR_SUCCESS) {
2560         LPWSTR valueW;
2561         RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2562                          &valuelen, &datalen, NULL, NULL);
2563 
2564         valuelen++; /* returned value doesn't include room for '\0' */
2565         valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2566         data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2567         if (valueW && data)
2568         {
2569             dlen = datalen * sizeof(WCHAR);
2570             vlen = valuelen;
2571             while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2572                                 &dlen) == ERROR_SUCCESS) {
2573                 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2574                 {
2575                     if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2576                     {
2577                         AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2578                         HeapFree(GetProcessHeap(), 0, unixname);
2579                     }
2580                 }
2581                 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2582                 {
2583                     WCHAR pathW[MAX_PATH];
2584                     static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2585                     BOOL added = FALSE;
2586 
2587                     sprintfW(pathW, fmtW, windowsdir, data);
2588                     if((unixname = wine_get_unix_file_name(pathW)))
2589                     {
2590                         added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2591                         HeapFree(GetProcessHeap(), 0, unixname);
2592                     }
2593                     if (!added)
2594                         load_font_from_data_dir(data);
2595                 }
2596                 /* reset dlen and vlen */
2597                 dlen = datalen;
2598                 vlen = valuelen;
2599             }
2600         }
2601         HeapFree(GetProcessHeap(), 0, data);
2602         HeapFree(GetProcessHeap(), 0, valueW);
2603         RegCloseKey(hkey);
2604     }
2605 
2606     load_fontconfig_fonts();
2607 
2608     /* then look in any directories that we've specified in the config file */
2609     /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2610     if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2611     {
2612         DWORD len;
2613         LPWSTR valueW;
2614         LPSTR valueA, ptr;
2615 
2616         if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2617         {
2618             len += sizeof(WCHAR);
2619             valueW = HeapAlloc( GetProcessHeap(), 0, len );
2620             if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2621             {
2622                 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2623                 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2624                 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2625                 TRACE( "got font path %s\n", debugstr_a(valueA) );
2626                 ptr = valueA;
2627                 while (ptr)
2628                 {
2629                     LPSTR next = strchr( ptr, ':' );
2630                     if (next) *next++ = 0;
2631                     ReadFontDir( ptr, TRUE );
2632                     ptr = next;
2633                 }
2634                 HeapFree( GetProcessHeap(), 0, valueA );
2635             }
2636             HeapFree( GetProcessHeap(), 0, valueW );
2637         }
2638         RegCloseKey(hkey);
2639     }
2640 
2641     DumpFontList();
2642     LoadSubstList();
2643     DumpSubstList();
2644     LoadReplaceList();
2645     update_reg_entries();
2646 
2647     init_system_links();
2648     
2649     ReleaseMutex(font_mutex);
2650     return TRUE;
2651 }
2652 
2653 
2654 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2655 {
2656     TT_OS2 *pOS2;
2657     TT_HoriHeader *pHori;
2658 
2659     LONG ppem;
2660 
2661     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2662     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2663 
2664     if(height == 0) height = 16;
2665 
2666     /* Calc. height of EM square:
2667      *
2668      * For +ve lfHeight we have
2669      * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2670      * Re-arranging gives:
2671      * ppem = units_per_em * lfheight / (winAscent + winDescent)
2672      *
2673      * For -ve lfHeight we have
2674      * |lfHeight| = ppem
2675      * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2676      * with il = winAscent + winDescent - units_per_em]
2677      *
2678      */
2679 
2680     if(height > 0) {
2681         if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2682             ppem = MulDiv(ft_face->units_per_EM, height,
2683                           pHori->Ascender - pHori->Descender);
2684         else
2685             ppem = MulDiv(ft_face->units_per_EM, height,
2686                           pOS2->usWinAscent + pOS2->usWinDescent);
2687     }
2688     else
2689         ppem = -height;
2690 
2691     return ppem;
2692 }
2693 
2694 static struct font_mapping *map_font_file( const char *name )
2695 {
2696     struct font_mapping *mapping;
2697     struct stat st;
2698     int fd;
2699 
2700     if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2701     if (fstat( fd, &st ) == -1) goto error;
2702 
2703     LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2704     {
2705         if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2706         {
2707             mapping->refcount++;
2708             close( fd );
2709             return mapping;
2710         }
2711     }
2712     if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2713         goto error;
2714 
2715     mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2716     close( fd );
2717 
2718     if (mapping->data == MAP_FAILED)
2719     {
2720         HeapFree( GetProcessHeap(), 0, mapping );
2721         return NULL;
2722     }
2723     mapping->refcount = 1;
2724     mapping->dev = st.st_dev;
2725     mapping->ino = st.st_ino;
2726     mapping->size = st.st_size;
2727     list_add_tail( &mappings_list, &mapping->entry );
2728     return mapping;
2729 
2730 error:
2731     close( fd );
2732     return NULL;
2733 }
2734 
2735 static void unmap_font_file( struct font_mapping *mapping )
2736 {
2737     if (!--mapping->refcount)
2738     {
2739         list_remove( &mapping->entry );
2740         munmap( mapping->data, mapping->size );
2741         HeapFree( GetProcessHeap(), 0, mapping );
2742     }
2743 }
2744 
2745 static LONG load_VDMX(GdiFont*, LONG);
2746 
2747 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2748 {
2749     FT_Error err;
2750     FT_Face ft_face;
2751     void *data_ptr;
2752     DWORD data_size;
2753 
2754     TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2755 
2756     if (face->file)
2757     {
2758         if (!(font->mapping = map_font_file( face->file )))
2759         {
2760             WARN("failed to map %s\n", debugstr_a(face->file));
2761             return 0;
2762         }
2763         data_ptr = font->mapping->data;
2764         data_size = font->mapping->size;
2765     }
2766     else
2767     {
2768         data_ptr = face->font_data_ptr;
2769         data_size = face->font_data_size;
2770     }
2771 
2772     err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2773     if(err) {
2774         ERR("FT_New_Face rets %d\n", err);
2775         return 0;
2776     }
2777 
2778     /* set it here, as load_VDMX needs it */
2779     font->ft_face = ft_face;
2780 
2781     if(FT_IS_SCALABLE(ft_face)) {
2782         /* load the VDMX table if we have one */
2783         font->ppem = load_VDMX(font, height);
2784         if(font->ppem == 0)
2785             font->ppem = calc_ppem_for_height(ft_face, height);
2786         TRACE("height %d => ppem %d\n", height, font->ppem);
2787 
2788         if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2789             WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2790     } else {
2791         font->ppem = height;
2792         if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2793             WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2794     }
2795     return ft_face;
2796 }
2797 
2798 
2799 static int get_nearest_charset(Face *face, int *cp)
2800 {
2801   /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2802      a single face with the requested charset.  The idea is to check if
2803      the selected font supports the current ANSI codepage, if it does
2804      return the corresponding charset, else return the first charset */
2805 
2806     CHARSETINFO csi;
2807     int acp = GetACP(), i;
2808     DWORD fs0;
2809 
2810     *cp = acp;
2811     if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2812         if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2813             return csi.ciCharset;
2814 
2815     for(i = 0; i < 32; i++) {
2816         fs0 = 1L << i;
2817         if(face->fs.fsCsb[0] & fs0) {
2818             if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2819                 *cp = csi.ciACP;
2820                 return csi.ciCharset;
2821             }
2822             else
2823                 FIXME("TCI failing on %x\n", fs0);
2824         }
2825     }
2826 
2827     FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2828           face->fs.fsCsb[0], face->file);
2829     *cp = acp;
2830     return DEFAULT_CHARSET;
2831 }
2832 
2833 static GdiFont *alloc_font(void)
2834 {
2835     GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2836     ret->gmsize = 1;
2837     ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2838     ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2839     ret->potm = NULL;
2840     ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2841     ret->total_kern_pairs = (DWORD)-1;
2842     ret->kern_pairs = NULL;
2843     list_init(&ret->hfontlist);
2844     list_init(&ret->child_fonts);
2845     return ret;
2846 }
2847 
2848 static void free_font(GdiFont *font)
2849 {
2850     struct list *cursor, *cursor2;
2851     int i;
2852 
2853     LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2854     {
2855         CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2856         struct list *first_hfont;
2857         HFONTLIST *hfontlist;
2858         list_remove(cursor);
2859         if(child->font)
2860         {
2861             first_hfont = list_head(&child->font->hfontlist);
2862             hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2863             DeleteObject(hfontlist->hfont);
2864             HeapFree(GetProcessHeap(), 0, hfontlist);
2865             free_font(child->font);
2866         }
2867         HeapFree(GetProcessHeap(), 0, child);
2868     }
2869 
2870     if (font->ft_face) pFT_Done_Face(font->ft_face);
2871     if (font->mapping) unmap_font_file( font->mapping );
2872     HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2873     HeapFree(GetProcessHeap(), 0, font->potm);
2874     HeapFree(GetProcessHeap(), 0, font->name);
2875     for (i = 0; i < font->gmsize; i++)
2876         HeapFree(GetProcessHeap(),0,font->gm[i]);
2877     HeapFree(GetProcessHeap(), 0, font->gm);
2878     HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2879     HeapFree(GetProcessHeap(), 0, font);
2880 }
2881 
2882 
2883 /*************************************************************
2884  * load_VDMX
2885  *
2886  * load the vdmx entry for the specified height
2887  */
2888 
2889 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2890           ( ( (FT_ULong)_x4 << 24 ) |     \
2891             ( (FT_ULong)_x3 << 16 ) |     \
2892             ( (FT_ULong)_x2 <<  8 ) |     \
2893               (FT_ULong)_x1         )
2894 
2895 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2896 
2897 typedef struct {
2898     BYTE bCharSet;
2899     BYTE xRatio;
2900     BYTE yStartRatio;
2901     BYTE yEndRatio;
2902 } Ratios;
2903 
2904 typedef struct {
2905     WORD recs;
2906     BYTE startsz;
2907     BYTE endsz;
2908 } VDMX_group;
2909 
2910 static LONG load_VDMX(GdiFont *font, LONG height)
2911 {
2912     WORD hdr[3], tmp;
2913     VDMX_group group;
2914     BYTE devXRatio, devYRatio;
2915     USHORT numRecs, numRatios;
2916     DWORD result, offset = -1;
2917     LONG ppem = 0;
2918     int i;
2919 
2920     result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2921 
2922     if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2923         return ppem;
2924 
2925     /* FIXME: need the real device aspect ratio */
2926     devXRatio = 1;
2927     devYRatio = 1;
2928 
2929     numRecs = GET_BE_WORD(hdr[1]);
2930     numRatios = GET_BE_WORD(hdr[2]);
2931 
2932     TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2933     for(i = 0; i < numRatios; i++) {
2934         Ratios ratio;
2935 
2936         offset = (3 * 2) + (i * sizeof(Ratios));
2937         WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2938         offset = -1;
2939 
2940         TRACE("Ratios[%d] %d  %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2941 
2942         if((ratio.xRatio == 0 &&
2943             ratio.yStartRatio == 0 &&
2944             ratio.yEndRatio == 0) ||
2945            (devXRatio == ratio.xRatio &&
2946             devYRatio >= ratio.yStartRatio &&
2947             devYRatio <= ratio.yEndRatio))
2948             {
2949                 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2950                 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2951                 offset = GET_BE_WORD(tmp);
2952                 break;
2953             }
2954     }
2955 
2956     if(offset == -1) {
2957         FIXME("No suitable ratio found\n");
2958         return ppem;
2959     }
2960 
2961     if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2962         USHORT recs;
2963         BYTE startsz, endsz;
2964         WORD *vTable;
2965 
2966         recs = GET_BE_WORD(group.recs);
2967         startsz = group.startsz;
2968         endsz = group.endsz;
2969 
2970         TRACE("recs=%d  startsz=%d  endsz=%d\n", recs, startsz, endsz);
2971 
2972         vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2973         result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2974         if(result == GDI_ERROR) {
2975             FIXME("Failed to retrieve vTable\n");
2976             goto end;
2977         }
2978 
2979         if(height > 0) {
2980             for(i = 0; i < recs; i++) {
2981                 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2982                 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2983                 ppem = GET_BE_WORD(vTable[i * 3]);
2984 
2985                 if(yMax + -yMin == height) {
2986                     font->yMax = yMax;
2987                     font->yMin = yMin;
2988                     TRACE("ppem %d found; height=%d  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
2989                     break;
2990                 }
2991                 if(yMax + -yMin > height) {
2992                     if(--i < 0) {
2993                         ppem = 0;
2994                         goto end; /* failed */
2995                     }
2996                     font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2997                     font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2998                     ppem = GET_BE_WORD(vTable[i * 3]);
2999                     TRACE("ppem %d found; height=%d  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
3000                     break;
3001                 }
3002             }
3003             if(!font->yMax) {
3004                 ppem = 0;
3005                 TRACE("ppem not found for height %d\n", height);
3006             }
3007         } else {
3008             ppem = -height;
3009             if(ppem < startsz || ppem > endsz)
3010                 goto end;
3011 
3012             for(i = 0; i < recs; i++) {
3013                 USHORT yPelHeight;
3014                 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3015 
3016                 if(yPelHeight > ppem)
3017                     break; /* failed */
3018 
3019                 if(yPelHeight == ppem) {
3020                     font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3021                     font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3022                     TRACE("ppem %d found; yMax=%d  yMin=%d\n", ppem, font->yMax, font->yMin);
3023                     break;
3024                 }
3025             }
3026         }
3027         end:
3028         HeapFree(GetProcessHeap(), 0, vTable);
3029     }
3030 
3031     return ppem;
3032 }
3033 
3034 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3035 {
3036     if(font->font_desc.hash != fd->hash) return TRUE;
3037     if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3038     if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3039     if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3040     return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3041 }
3042 
3043 static void calc_hash(FONT_DESC *pfd)
3044 {
3045     DWORD hash = 0, *ptr, two_chars;
3046     WORD *pwc;
3047     unsigned int i;
3048 
3049     for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3050         hash ^= *ptr;
3051     for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3052         hash ^= *ptr;
3053     for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3054         two_chars = *ptr;
3055         pwc = (WCHAR *)&two_chars;
3056         if(!*pwc) break;
3057         *pwc = toupperW(*pwc);
3058         pwc++;
3059         *pwc = toupperW(*pwc);
3060         hash ^= two_chars;
3061         if(!*pwc) break;
3062     }
3063     hash ^= !pfd->can_use_bitmap;
3064     pfd->hash = hash;
3065     return;
3066 }
3067 
3068 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3069 {
3070     GdiFont *ret;
3071     FONT_DESC fd;
3072     HFONTLIST *hflist;
3073     struct list *font_elem_ptr, *hfontlist_elem_ptr;
3074 
3075     fd.lf = *plf;
3076     fd.matrix = *pmat;
3077     fd.can_use_bitmap = can_use_bitmap;
3078     calc_hash(&fd);
3079 
3080     /* try the in-use list */
3081     LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3082         ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3083         if(!fontcmp(ret, &fd)) {
3084             if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3085             LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3086                 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3087                 if(hflist->hfont == hfont)
3088                     return ret;
3089             }
3090             hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3091             hflist->hfont = hfont;
3092             list_add_head(&ret->hfontlist, &hflist->entry);
3093             return ret;
3094         }
3095     }
3096  
3097     /* then the unused list */
3098     font_elem_ptr = list_head(&unused_gdi_font_list);
3099     while(font_elem_ptr) {
3100         ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3101         font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3102         if(!fontcmp(ret, &fd)) {
3103             if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3104             assert(list_empty(&ret->hfontlist));
3105             TRACE("Found %p in unused list\n", ret);
3106             list_remove(&ret->entry);
3107             list_add_head(&gdi_font_list, &ret->entry);
3108             hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3109             hflist->hfont = hfont;
3110             list_add_head(&ret->hfontlist, &hflist->entry);
3111             return ret;
3112         }
3113     }
3114     return NULL;
3115 }
3116 
3117 static void add_to_cache(GdiFont *font)
3118 {
3119     static DWORD cache_num = 1;
3120 
3121     font->cache_num = cache_num++;
3122     list_add_head(&gdi_font_list, &font->entry);
3123 }
3124 
3125 /*************************************************************
3126  * create_child_font_list
3127  */
3128 static BOOL create_child_font_list(GdiFont *font)
3129 {
3130     BOOL ret = FALSE;
3131     SYSTEM_LINKS *font_link;
3132     CHILD_FONT *font_link_entry, *new_child;
3133 
3134     LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3135     {
3136         if(!strcmpW(font_link->font_name, font->name))
3137         {
3138             TRACE("found entry in system list\n");
3139             LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3140             {
3141                 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3142                 new_child->face = font_link_entry->face;
3143                 new_child->font = NULL;
3144                 list_add_tail(&font->child_fonts, &new_child->entry);
3145                 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3146             }
3147             ret = TRUE;
3148             break;
3149         }
3150     }
3151     /*
3152      * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3153      * Sans Serif.  This is how asian windows get default fallbacks for fonts
3154      */
3155     if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3156         font->charset != OEM_CHARSET &&
3157         strcmpW(font->name,szDefaultFallbackLink) != 0)
3158         LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3159         {
3160             if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3161             {
3162                 TRACE("found entry in default fallback list\n");
3163                 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3164                 {
3165                     new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3166                     new_child->face = font_link_entry->face;
3167                     new_child->font = NULL;
3168                     list_add_tail(&font->child_fonts, &new_child->entry);
3169                     TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3170                 }
3171                 ret = TRUE;
3172                 break;
3173             }
3174         }
3175 
3176     return ret;
3177 }
3178 
3179 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3180 {
3181     FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3182 
3183     if (pFT_Set_Charmap)
3184     {
3185         FT_Int i;
3186         FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3187 
3188         cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3189 
3190         for (i = 0; i < ft_face->num_charmaps; i++)
3191         {
3192             if (ft_face->charmaps[i]->encoding == encoding)
3193             {
3194                 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3195                        ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3196 
3197                 switch (ft_face->charmaps[i]->platform_id)
3198                 {
3199                     default:
3200                         cmap_def = ft_face->charmaps[i];
3201                         break;
3202                     case 0: /* Apple Unicode */
3203                         cmap0 = ft_face->charmaps[i];
3204                         break;
3205                     case 1: /* Macintosh */
3206                         cmap1 = ft_face->charmaps[i];
3207                         break;
3208                     case 2: /* ISO */
3209                         cmap2 = ft_face->charmaps[i];
3210                         break;
3211                     case 3: /* Microsoft */
3212                         cmap3 = ft_face->charmaps[i];
3213                         break;
3214                 }
3215             }
3216 
3217             if (cmap3) /* prefer Microsoft cmap table */
3218                 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3219             else if (cmap1)
3220                 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3221             else if (cmap2)
3222                 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3223             else if (cmap0)
3224                 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3225             else if (cmap_def)
3226                 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3227         }
3228         return ft_err == FT_Err_Ok;
3229     }
3230 
3231     return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3232 }
3233 
3234 /*************************************************************
3235  * WineEngCreateFontInstance
3236  *
3237  */
3238 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3239 {
3240     GdiFont *ret;
3241     Face *face, *best, *best_bitmap;
3242     Family *family, *last_resort_family;
3243     struct list *family_elem_ptr, *face_elem_ptr;
3244     INT height, width = 0;
3245     unsigned int score = 0, new_score;
3246     signed int diff = 0, newdiff;
3247     BOOL bd, it, can_use_bitmap;
3248     LOGFONTW lf;
3249     CHARSETINFO csi;
3250     HFONTLIST *hflist;
3251     FMAT2 dcmat;
3252     FontSubst *psub = NULL;
3253 
3254     EnterCriticalSection( &freetype_cs );
3255 
3256     LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3257     {
3258         struct list *first_hfont = list_head(&ret->hfontlist);
3259         hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3260         if(hflist->hfont == hfont)
3261         {
3262             LeaveCriticalSection( &freetype_cs );
3263             return ret;
3264         }
3265     }
3266 
3267     if (!GetObjectW( hfont, sizeof(lf), &lf ))
3268     {
3269         LeaveCriticalSection( &freetype_cs );
3270         return NULL;
3271     }
3272     lf.lfWidth = abs(lf.lfWidth);
3273 
3274     can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3275 
3276     TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3277           debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3278           lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3279           lf.lfEscapement);
3280 
3281     if(dc->GraphicsMode == GM_ADVANCED)
3282         memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3283     else
3284     {
3285         /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3286            font scaling abilities. */
3287         dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3288         dcmat.eM21 = dcmat.eM12 = 0;
3289     }
3290 
3291     TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3292                                         dcmat.eM21, dcmat.eM22);
3293 
3294     /* check the cache first */
3295     if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3296         TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3297         LeaveCriticalSection( &freetype_cs );
3298         return ret;
3299     }
3300 
3301     TRACE("not in cache\n");
3302     if(list_empty(&font_list)) /* No fonts installed */
3303     {
3304         TRACE("No fonts installed\n");
3305         LeaveCriticalSection( &freetype_cs );
3306         return NULL;
3307     }
3308     if(!have_installed_roman_font)
3309     {
3310         TRACE("No roman font installed\n");
3311         LeaveCriticalSection( &freetype_cs );
3312         return NULL;
3313     }
3314 
3315     ret = alloc_font();
3316 
3317     ret->font_desc.matrix = dcmat;
3318     ret->font_desc.lf = lf;
3319     ret->font_desc.can_use_bitmap = can_use_bitmap;
3320     calc_hash(&ret->font_desc);
3321     hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3322     hflist->hfont = hfont;
3323     list_add_head(&ret->hfontlist, &hflist->entry);
3324 
3325     /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3326        SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3327        original value lfCharSet.  Note this is a special case for
3328        Symbol and doesn't happen at least for "Wingdings*" */
3329 
3330     if(!strcmpiW(lf.lfFaceName, SymbolW))
3331         lf.lfCharSet = SYMBOL_CHARSET;
3332