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

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

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

  1 /*
  2  * FreeType font engine interface
  3  *
  4  * Copyright 2001 Huw D M Davies for CodeWeavers.
  5  * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
  6  *
  7  * This file contains the WineEng* functions.
  8  *
  9  * This library is free software; you can redistribute it and/or
 10  * modify it under the terms of the GNU Lesser General Public
 11  * License as published by the Free Software Foundation; either
 12  * version 2.1 of the License, or (at your option) any later version.
 13  *
 14  * This library is distributed in the hope that it will be useful,
 15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17  * Lesser General Public License for more details.
 18  *
 19  * You should have received a copy of the GNU Lesser General Public
 20  * License along with this library; if not, write to the Free Software
 21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 22  */
 23 
 24 #include "config.h"
 25 #include "wine/port.h"
 26 
 27 #include <stdarg.h>
 28 #include <stdlib.h>
 29 #ifdef HAVE_SYS_STAT_H
 30 # include <sys/stat.h>
 31 #endif
 32 #ifdef HAVE_SYS_MMAN_H
 33 # include <sys/mman.h>
 34 #endif
 35 #include <string.h>
 36 #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]