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