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