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

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

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

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