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