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

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

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