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

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

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