~ [ 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 static WCHAR *get_familyname(FT_Face ft_face)
1030 {
1031     WCHAR *family = NULL;
1032     FT_SfntName name;
1033     FT_UInt num_names, name_index, i;
1034 
1035     if(FT_IS_SFNT(ft_face))
1036     {
1037         num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1038 
1039         for(name_index = 0; name_index < num_names; name_index++)
1040         {
1041             if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1042             {
1043                 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
1044                    (name.language_id == GetUserDefaultLCID()) &&
1045                    (name.platform_id == TT_PLATFORM_MICROSOFT) &&
1046                    (name.encoding_id == TT_MS_ID_UNICODE_CS))
1047                 {
1048                     /* String is not nul terminated and string_len is a byte length. */
1049                     family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1050                     for(i = 0; i < name.string_len / 2; i++)
1051                     {
1052                         WORD *tmp = (WORD *)&name.string[i * 2];
1053                         family[i] = GET_BE_WORD(*tmp);
1054                     }
1055                     family[i] = 0;
1056 
1057                     TRACE("Got localised name %s\n", debugstr_w(family));
1058                     return family;
1059                 }
1060             }
1061         }
1062     }
1063 
1064     return NULL;
1065 }
1066 
1067 
1068 /*****************************************************************
1069  *  load_sfnt_table
1070  *
1071  * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1072  * of FreeType that don't export this function.
1073  *
1074  */
1075 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1076 {
1077 
1078     FT_Error err;
1079 
1080     /* If the FT_Load_Sfnt_Table function is there we'll use it */
1081     if(pFT_Load_Sfnt_Table)
1082     {
1083         err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1084     }
1085 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1086     else  /* Do it the hard way */
1087     {
1088         TT_Face tt_face = (TT_Face) ft_face;
1089         SFNT_Interface *sfnt;
1090         if (FT_Version.major==2 && FT_Version.minor==0)
1091         {
1092             /* 2.0.x */
1093             sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1094         }
1095         else
1096         {
1097             /* A field was added in the middle of the structure in 2.1.x */
1098             sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1099         }
1100         err = sfnt->load_any(tt_face, table, offset, buf, len);
1101     }
1102 #else
1103     else
1104     {
1105         static int msg;
1106         if(!msg)
1107         {
1108             MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1109                     "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1110                     "Please upgrade your freetype library.\n");
1111             msg++;
1112         }
1113         err = FT_Err_Unimplemented_Feature;
1114     }
1115 #endif
1116     return err;
1117 }
1118 
1119 static inline int TestStyles(DWORD flags, DWORD styles)
1120 {
1121     return (flags & styles) == styles;
1122 }
1123 
1124 static int StyleOrdering(Face *face)
1125 {
1126     if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1127         return 3;
1128     if (TestStyles(face->ntmFlags, NTM_ITALIC))
1129         return 2;
1130     if (TestStyles(face->ntmFlags, NTM_BOLD))
1131         return 1;
1132     if (TestStyles(face->ntmFlags, NTM_REGULAR))
1133         return 0;
1134 
1135     WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1136          debugstr_w(face->family->FamilyName),
1137          debugstr_w(face->StyleName),
1138          face->ntmFlags);
1139 
1140     return 9999;
1141 }
1142 
1143 /* Add a style of face to a font family using an ordering of the list such
1144    that regular fonts come before bold and italic, and single styles come
1145    before compound styles.  */
1146 static void AddFaceToFamily(Face *face, Family *family)
1147 {
1148     struct list *entry;
1149 
1150     LIST_FOR_EACH( entry, &family->faces )
1151     {
1152         Face *ent = LIST_ENTRY(entry, Face, entry);
1153         if (StyleOrdering(face) < StyleOrdering(ent)) break;
1154     }
1155     list_add_before( entry, &face->entry );
1156 }
1157 
1158 #define ADDFONT_EXTERNAL_FONT 0x01
1159 #define ADDFONT_FORCE_BITMAP  0x02
1160 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1161 {
1162     FT_Face ft_face;
1163     TT_OS2 *pOS2;
1164     TT_Header *pHeader = NULL;
1165     WCHAR *english_family, *localised_family, *StyleW;
1166     DWORD len;
1167     Family *family;
1168     Face *face;
1169     struct list *family_elem_ptr, *face_elem_ptr;
1170     FT_Error err;
1171     FT_Long face_index = 0, num_faces;
1172 #ifdef HAVE_FREETYPE_FTWINFNT_H
1173     FT_WinFNT_HeaderRec winfnt_header;
1174 #endif
1175     int i, bitmap_num, internal_leading;
1176     FONTSIGNATURE fs;
1177 
1178     /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1179     assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1180 
1181 #ifdef HAVE_CARBON_CARBON_H
1182     if(file && !fake_family)
1183     {
1184         char **mac_list = expand_mac_font(file);
1185         if(mac_list)
1186         {
1187             BOOL had_one = FALSE;
1188             char **cursor;
1189             for(cursor = mac_list; *cursor; cursor++)
1190             {
1191                 had_one = TRUE;
1192                 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1193                 HeapFree(GetProcessHeap(), 0, *cursor);
1194             }
1195             HeapFree(GetProcessHeap(), 0, mac_list);
1196             if(had_one)
1197                 return 1;
1198         }
1199     }
1200 #endif /* HAVE_CARBON_CARBON_H */
1201 
1202     do {
1203         char *family_name = fake_family;
1204 
1205         if (file)
1206         {
1207             TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1208             err = pFT_New_Face(library, file, face_index, &ft_face);
1209         } else
1210         {
1211             TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1212             err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1213         }
1214 
1215         if(err != 0) {
1216             WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1217             return 0;
1218         }
1219 
1220         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*/
1221             WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1222             pFT_Done_Face(ft_face);
1223             return 0;
1224         }
1225 
1226         /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1227         if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1228             WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1229             pFT_Done_Face(ft_face);
1230             return 0;
1231         }
1232 
1233         if(FT_IS_SFNT(ft_face))
1234         {
1235             if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1236                !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1237                !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1238             {
1239                 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1240                       "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1241                 pFT_Done_Face(ft_face);
1242                 return 0;
1243             }
1244 
1245             /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1246                we don't want to load these. */
1247             if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1248             {
1249                 FT_ULong len = 0;
1250 
1251                 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1252                 {
1253                     TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1254                     pFT_Done_Face(ft_face);
1255                     return 0;
1256                 }
1257             }
1258         }
1259 
1260         if(!ft_face->family_name || !ft_face->style_name) {
1261             TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1262             pFT_Done_Face(ft_face);
1263             return 0;
1264         }
1265 
1266         if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1267         {
1268             TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1269             pFT_Done_Face(ft_face);
1270             return 0;
1271         }
1272 
1273         if (target_family)
1274         {
1275             localised_family = get_familyname(ft_face);
1276             if (localised_family && strcmpiW(localised_family,target_family)!=0)
1277             {
1278                 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1279                 HeapFree(GetProcessHeap(), 0, localised_family);
1280                 num_faces = ft_face->num_faces;
1281                 pFT_Done_Face(ft_face);
1282                 continue;
1283             }
1284             HeapFree(GetProcessHeap(), 0, localised_family);
1285         }
1286 
1287         if(!family_name)
1288             family_name = ft_face->family_name;
1289 
1290         bitmap_num = 0;
1291         do {
1292             My_FT_Bitmap_Size *size = NULL;
1293             FT_ULong tmp_size;
1294 
1295             if(!FT_IS_SCALABLE(ft_face))
1296                 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1297 
1298             len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1299             english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1300             MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1301 
1302             localised_family = NULL;
1303             if(!fake_family) {
1304                 localised_family = get_familyname(ft_face);
1305                 if(localised_family && !strcmpW(localised_family, english_family)) {
1306                     HeapFree(GetProcessHeap(), 0, localised_family);
1307                     localised_family = NULL;
1308                 }
1309             }
1310 
1311             family = NULL;
1312             LIST_FOR_EACH(family_elem_ptr, &font_list) {
1313                 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1314                 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1315                     break;
1316                 family = NULL;
1317             }
1318             if(!family) {
1319                 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1320                 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1321                 list_init(&family->faces);
1322                 list_add_tail(&font_list, &family->entry);
1323 
1324                 if(localised_family) {
1325                     FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1326                     subst->from.name = strdupW(english_family);
1327                     subst->from.charset = -1;
1328                     subst->to.name = strdupW(localised_family);
1329                     subst->to.charset = -1;
1330                     add_font_subst(&font_subst_list, subst, 0);
1331                 }
1332             }
1333             HeapFree(GetProcessHeap(), 0, localised_family);
1334             HeapFree(GetProcessHeap(), 0, english_family);
1335 
1336             len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1337             StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1338             MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1339 
1340             internal_leading = 0;
1341             memset(&fs, 0, sizeof(fs));
1342 
1343             pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1344             if(pOS2) {
1345                 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1346                 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1347                 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1348                 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1349                 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1350                 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1351                 if(pOS2->version == 0) {
1352                     FT_UInt dummy;
1353 
1354                     if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1355                         fs.fsCsb[0] |= FS_LATIN1;
1356                     else
1357                         fs.fsCsb[0] |= FS_SYMBOL;
1358                 }
1359             }
1360 #ifdef HAVE_FREETYPE_FTWINFNT_H
1361             else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1362                 CHARSETINFO csi;
1363                 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1364                       winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1365                 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1366                     fs = csi.fs;
1367                 internal_leading = winfnt_header.internal_leading;
1368             }
1369 #endif
1370 
1371             face_elem_ptr = list_head(&family->faces);
1372             while(face_elem_ptr) {
1373                 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1374                 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1375                 if(!strcmpW(face->StyleName, StyleW) &&
1376                    (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1377                     TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1378                           debugstr_w(family->FamilyName), debugstr_w(StyleW),
1379                           face->font_version,  pHeader ? pHeader->Font_Revision : 0);
1380 
1381                     if(fake_family) {
1382                         TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1383                         HeapFree(GetProcessHeap(), 0, StyleW);
1384                         pFT_Done_Face(ft_face);
1385                         return 1;
1386                     }
1387                     if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1388                         TRACE("Original font is newer so skipping this one\n");
1389                         HeapFree(GetProcessHeap(), 0, StyleW);
1390                         pFT_Done_Face(ft_face);
1391                         return 1;
1392                     } else {
1393                         TRACE("Replacing original with this one\n");
1394                         list_remove(&face->entry);
1395                         HeapFree(GetProcessHeap(), 0, face->file);
1396                         HeapFree(GetProcessHeap(), 0, face->StyleName);
1397                         HeapFree(GetProcessHeap(), 0, face);
1398                         break;
1399                     }
1400                 }
1401             }
1402             face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1403             face->cached_enum_data = NULL;
1404             face->StyleName = StyleW;
1405             if (file)
1406             {
1407                 face->file = strdupA(file);
1408                 face->font_data_ptr = NULL;
1409                 face->font_data_size = 0;
1410             }
1411             else
1412             {
1413                 face->file = NULL;
1414                 face->font_data_ptr = font_data_ptr;
1415                 face->font_data_size = font_data_size;
1416             }
1417             face->face_index = face_index;
1418             face->ntmFlags = 0;
1419             if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1420                 face->ntmFlags |= NTM_ITALIC;
1421             if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1422                 face->ntmFlags |= NTM_BOLD;
1423             if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1424             face->font_version = pHeader ? pHeader->Font_Revision : 0;
1425             face->family = family;
1426             face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1427             face->fs = fs;
1428             memset(&face->fs_links, 0, sizeof(face->fs_links));
1429 
1430             if(FT_IS_SCALABLE(ft_face)) {
1431                 memset(&face->size, 0, sizeof(face->size));
1432                 face->scalable = TRUE;
1433             } else {
1434                 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1435                       size->height, size->width, size->size >> 6,
1436                       size->x_ppem >> 6, size->y_ppem >> 6);
1437                 face->size.height = size->height;
1438                 face->size.width = size->width;
1439                 face->size.size = size->size;
1440                 face->size.x_ppem = size->x_ppem;
1441                 face->size.y_ppem = size->y_ppem;
1442                 face->size.internal_leading = internal_leading;
1443                 face->scalable = FALSE;
1444             }
1445 
1446             /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1447             tmp_size = 0;
1448             if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1449             {
1450                 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1451                 face->ntmFlags |= NTM_PS_OPENTYPE;
1452             }
1453 
1454             TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1455                   face->fs.fsCsb[0], face->fs.fsCsb[1],
1456                   face->fs.fsUsb[0], face->fs.fsUsb[1],
1457                   face->fs.fsUsb[2], face->fs.fsUsb[3]);
1458 
1459 
1460             if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1461                 for(i = 0; i < ft_face->num_charmaps; i++) {
1462                     switch(ft_face->charmaps[i]->encoding) {
1463                     case FT_ENCODING_UNICODE:
1464                     case FT_ENCODING_APPLE_ROMAN:
1465                         face->fs.fsCsb[0] |= FS_LATIN1;
1466                         break;
1467                     case FT_ENCODING_MS_SYMBOL:
1468                         face->fs.fsCsb[0] |= FS_SYMBOL;
1469                         break;
1470                     default:
1471                         break;
1472                     }
1473                 }
1474             }
1475 
1476             if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1477                 have_installed_roman_font = TRUE;
1478 
1479             AddFaceToFamily(face, family);
1480 
1481         } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1482 
1483         num_faces = ft_face->num_faces;
1484         pFT_Done_Face(ft_face);
1485         TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1486               debugstr_w(StyleW));
1487     } while(num_faces > ++face_index);
1488     return num_faces;
1489 }
1490 
1491 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1492 {
1493     return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1494 }
1495 
1496 static void DumpFontList(void)
1497 {
1498     Family *family;
1499     Face *face;
1500     struct list *family_elem_ptr, *face_elem_ptr;
1501 
1502     LIST_FOR_EACH(family_elem_ptr, &font_list) {
1503         family = LIST_ENTRY(family_elem_ptr, Family, entry); 
1504         TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1505         LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1506             face = LIST_ENTRY(face_elem_ptr, Face, entry);
1507             TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1508             if(!face->scalable)
1509                 TRACE(" %d", face->size.height);
1510             TRACE("\n");
1511         }
1512     }
1513     return;
1514 }
1515 
1516 /***********************************************************
1517  * The replacement list is a way to map an entire font
1518  * family onto another family.  For example adding
1519  *
1520  * [HKCU\Software\Wine\Fonts\Replacements]
1521  * "Wingdings"="Winedings"
1522  *
1523  * would enumerate the Winedings font both as Winedings and
1524  * Wingdings.  However if a real Wingdings font is present the
1525  * replacement does not take place.
1526  * 
1527  */
1528 static void LoadReplaceList(void)
1529 {
1530     HKEY hkey;
1531     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1532     LPWSTR value;
1533     LPVOID data;
1534     Family *family;
1535     Face *face;
1536     struct list *family_elem_ptr, *face_elem_ptr;
1537     CHAR familyA[400];
1538 
1539     /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1540     if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1541     {
1542         RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1543                          &valuelen, &datalen, NULL, NULL);
1544 
1545         valuelen++; /* returned value doesn't include room for '\0' */
1546         value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1547         data = HeapAlloc(GetProcessHeap(), 0, datalen);
1548 
1549         dlen = datalen;
1550         vlen = valuelen;
1551         while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1552                             &dlen) == ERROR_SUCCESS) {
1553             TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1554             /* "NewName"="Oldname" */
1555             WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1556 
1557             /* Find the old family and hence all of the font files
1558                in that family */
1559             LIST_FOR_EACH(family_elem_ptr, &font_list) {
1560                 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1561                 if(!strcmpiW(family->FamilyName, data)) {
1562                     LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1563                         face = LIST_ENTRY(face_elem_ptr, Face, entry);
1564                         TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1565                               debugstr_w(face->StyleName), familyA);
1566                         /* Now add a new entry with the new family name */
1567                         AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1568                     }
1569                     break;
1570                 }
1571             }
1572             /* reset dlen and vlen */
1573             dlen = datalen;
1574             vlen = valuelen;
1575         }
1576         HeapFree(GetProcessHeap(), 0, data);
1577         HeapFree(GetProcessHeap(), 0, value);
1578         RegCloseKey(hkey);
1579     }
1580 }
1581 
1582 /*************************************************************
1583  * init_system_links
1584  */
1585 static BOOL init_system_links(void)
1586 {
1587     static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1588                                         'W','i','n','d','o','w','s',' ','N','T','\\',
1589                                         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1590                                         'S','y','s','t','e','m','L','i','n','k',0};
1591     HKEY hkey;
1592     BOOL ret = FALSE;
1593     DWORD type, max_val, max_data, val_len, data_len, index;
1594     WCHAR *value, *data;
1595     WCHAR *entry, *next;
1596     SYSTEM_LINKS *font_link, *system_font_link;
1597     CHILD_FONT *child_font;
1598     static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1599     static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1600     static const WCHAR System[] = {'S','y','s','t','e','m',0};
1601     FONTSIGNATURE fs;
1602     Family *family;
1603     Face *face;
1604     FontSubst *psub;
1605 
1606     if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1607     {
1608         RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1609         value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1610         data = HeapAlloc(GetProcessHeap(), 0, max_data);
1611         val_len = max_val + 1;
1612         data_len = max_data;
1613         index = 0;
1614         while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1615         {
1616             TRACE("%s:\n", debugstr_w(value));
1617 
1618             memset(&fs, 0, sizeof(fs));
1619             font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1620             psub = get_font_subst(&font_subst_list, value, -1);
1621             font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1622             list_init(&font_link->links);
1623             for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1624             {
1625                 WCHAR *face_name;
1626                 CHILD_FONT *child_font;
1627 
1628                 TRACE("\t%s\n", debugstr_w(entry));
1629 
1630                 next = entry + strlenW(entry) + 1;
1631                 
1632                 face_name = strchrW(entry, ',');
1633                 if(face_name)
1634                 {
1635                     *face_name++ = 0;
1636                     while(isspaceW(*face_name))
1637                         face_name++;
1638 
1639                     psub = get_font_subst(&font_subst_list, face_name, -1);
1640                     if(psub)
1641                         face_name = psub->to.name;
1642                 }
1643                 face = find_face_from_filename(entry, face_name);
1644                 if(!face)
1645                 {
1646                     TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1647                     continue;
1648                 }
1649 
1650                 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1651                 child_font->face = face;
1652                 child_font->font = NULL;
1653                 fs.fsCsb[0] |= face->fs.fsCsb[0];
1654                 fs.fsCsb[1] |= face->fs.fsCsb[1];
1655                 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1656                 list_add_tail(&font_link->links, &child_font->entry);
1657             }
1658             family = find_family_from_name(font_link->font_name);
1659             if(family)
1660             {
1661                 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1662                 {
1663                     face->fs_links = fs;
1664                 }
1665             }
1666             list_add_tail(&system_links, &font_link->entry);
1667             val_len = max_val + 1;
1668             data_len = max_data;
1669         }
1670 
1671         HeapFree(GetProcessHeap(), 0, value);
1672         HeapFree(GetProcessHeap(), 0, data);
1673         RegCloseKey(hkey);
1674     }
1675 
1676     /* Explicitly add an entry for the system font, this links to Tahoma and any links
1677        that Tahoma has */
1678 
1679     system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1680     system_font_link->font_name = strdupW(System);
1681     list_init(&system_font_link->links);    
1682 
1683     face = find_face_from_filename(tahoma_ttf, Tahoma);
1684     if(face)
1685     {
1686         child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1687         child_font->face = face;
1688         child_font->font = NULL;
1689         TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1690         list_add_tail(&system_font_link->links, &child_font->entry);
1691     }
1692     LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1693     {
1694         if(!strcmpiW(font_link->font_name, Tahoma))
1695         {
1696             CHILD_FONT *font_link_entry;
1697             LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1698             {
1699                 CHILD_FONT *new_child;
1700                 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1701                 new_child->face = font_link_entry->face;
1702                 new_child->font = NULL;
1703                 list_add_tail(&system_font_link->links, &new_child->entry);
1704             }
1705             break;
1706         }
1707     }
1708     list_add_tail(&system_links, &system_font_link->entry);
1709     return ret;
1710 }
1711 
1712 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1713 {
1714     DIR *dir;
1715     struct dirent *dent;
1716     char path[MAX_PATH];
1717 
1718     TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1719 
1720     dir = opendir(dirname);
1721     if(!dir) {
1722         WARN("Can't open directory %s\n", debugstr_a(dirname));
1723         return FALSE;
1724     }
1725     while((dent = readdir(dir)) != NULL) {
1726         struct stat statbuf;
1727 
1728         if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1729             continue;
1730 
1731         TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1732 
1733         sprintf(path, "%s/%s", dirname, dent->d_name);
1734 
1735         if(stat(path, &statbuf) == -1)
1736         {
1737             WARN("Can't stat %s\n", debugstr_a(path));
1738             continue;
1739         }
1740         if(S_ISDIR(statbuf.st_mode))
1741             ReadFontDir(path, external_fonts);
1742         else
1743             AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1744     }
1745     closedir(dir);
1746     return TRUE;
1747 }
1748 
1749 static void load_fontconfig_fonts(void)
1750 {
1751 #ifdef SONAME_LIBFONTCONFIG
1752     void *fc_handle = NULL;
1753     FcConfig *config;
1754     FcPattern *pat;
1755     FcObjectSet *os;
1756     FcFontSet *fontset;
1757     int i, len;
1758     char *file;
1759     const char *ext;
1760 
1761     fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1762     if(!fc_handle) {
1763         TRACE("Wine cannot find the fontconfig library (%s).\n",
1764               SONAME_LIBFONTCONFIG);
1765         return;
1766     }
1767 #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;}
1768 LOAD_FUNCPTR(FcConfigGetCurrent);
1769 LOAD_FUNCPTR(FcFontList);
1770 LOAD_FUNCPTR(FcFontSetDestroy);
1771 LOAD_FUNCPTR(FcInit);
1772 LOAD_FUNCPTR(FcObjectSetAdd);
1773 LOAD_FUNCPTR(FcObjectSetCreate);
1774 LOAD_FUNCPTR(FcObjectSetDestroy);
1775 LOAD_FUNCPTR(FcPatternCreate);
1776 LOAD_FUNCPTR(FcPatternDestroy);
1777 LOAD_FUNCPTR(FcPatternGetBool);
1778 LOAD_FUNCPTR(FcPatternGetString);
1779 #undef LOAD_FUNCPTR
1780 
1781     if(!pFcInit()) return;
1782     
1783     config = pFcConfigGetCurrent();
1784     pat = pFcPatternCreate();
1785     os = pFcObjectSetCreate();
1786     pFcObjectSetAdd(os, FC_FILE);
1787     pFcObjectSetAdd(os, FC_SCALABLE);
1788     fontset = pFcFontList(config, pat, os);
1789     if(!fontset) return;
1790     for(i = 0; i < fontset->nfont; i++) {
1791         FcBool scalable;
1792 
1793         if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1794             continue;
1795         TRACE("fontconfig: %s\n", file);
1796 
1797         /* We're just interested in OT/TT fonts for now, so this hack just
1798            picks up the scalable fonts without extensions .pf[ab] to save time
1799            loading every other font */
1800 
1801         if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1802         {
1803             TRACE("not scalable\n");
1804             continue;
1805         }
1806 
1807         len = strlen( file );
1808         if(len < 4) continue;
1809         ext = &file[ len - 3 ];
1810         if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1811             AddFontFileToList(file, NULL, NULL,  ADDFONT_EXTERNAL_FONT);
1812     }
1813     pFcFontSetDestroy(fontset);
1814     pFcObjectSetDestroy(os);
1815     pFcPatternDestroy(pat);
1816  sym_not_found:
1817 #endif
1818     return;
1819 }
1820 
1821 static BOOL load_font_from_data_dir(LPCWSTR file)
1822 {
1823     BOOL ret = FALSE;
1824     const char *data_dir = wine_get_data_dir();
1825 
1826     if (!data_dir) data_dir = wine_get_build_dir();
1827 
1828     if (data_dir)
1829     {
1830         INT len;
1831         char *unix_name;
1832 
1833         len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1834 
1835         unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1836 
1837         strcpy(unix_name, data_dir);
1838         strcat(unix_name, "/fonts/");
1839 
1840         WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1841 
1842         EnterCriticalSection( &freetype_cs );
1843         ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1844         LeaveCriticalSection( &freetype_cs );
1845         HeapFree(GetProcessHeap(), 0, unix_name);
1846     }
1847     return ret;
1848 }
1849 
1850 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1851 {
1852     static const WCHAR slashW[] = {'\\','\0'};
1853     BOOL ret = FALSE;
1854     WCHAR windowsdir[MAX_PATH];
1855     char *unixname;
1856 
1857     GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1858     strcatW(windowsdir, fontsW);
1859     strcatW(windowsdir, slashW);
1860     strcatW(windowsdir, file);
1861     if ((unixname = wine_get_unix_file_name(windowsdir))) {
1862         EnterCriticalSection( &freetype_cs );
1863         ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1864         LeaveCriticalSection( &freetype_cs );
1865         HeapFree(GetProcessHeap(), 0, unixname);
1866     }
1867     return ret;
1868 }
1869 
1870 static void load_system_fonts(void)
1871 {
1872     HKEY hkey;
1873     WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1874     const WCHAR * const *value;
1875     DWORD dlen, type;
1876     static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1877     char *unixname;
1878 
1879     if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1880         GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1881         strcatW(windowsdir, fontsW);
1882         for(value = SystemFontValues; *value; value++) { 
1883             dlen = sizeof(data);
1884             if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1885                type == REG_SZ) {
1886                 BOOL added = FALSE;
1887 
1888                 sprintfW(pathW, fmtW, windowsdir, data);
1889                 if((unixname = wine_get_unix_file_name(pathW))) {
1890                     added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1891                     HeapFree(GetProcessHeap(), 0, unixname);
1892                 }
1893                 if (!added)
1894                     load_font_from_data_dir(data);
1895             }
1896         }
1897         RegCloseKey(hkey);
1898     }
1899 }
1900 
1901 /*************************************************************
1902  *
1903  * This adds registry entries for any externally loaded fonts
1904  * (fonts from fontconfig or FontDirs).  It also deletes entries
1905  * of no longer existing fonts.
1906  *
1907  */
1908 static void update_reg_entries(void)
1909 {
1910     HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1911     LPWSTR valueW;
1912     DWORD len, len_fam;
1913     Family *family;
1914     Face *face;
1915     struct list *family_elem_ptr, *face_elem_ptr;
1916     WCHAR *file;
1917     static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1918     static const WCHAR spaceW[] = {' ', '\0'};
1919     char *path;
1920 
1921     if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1922                        0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1923         ERR("Can't create Windows font reg key\n");
1924         goto end;
1925     }
1926 
1927     if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1928                        0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1929         ERR("Can't create Windows font reg key\n");
1930         goto end;
1931     }
1932 
1933     if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1934                        0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1935         ERR("Can't create external font reg key\n");
1936         goto end;
1937     }
1938 
1939     /* enumerate the fonts and add external ones to the two keys */
1940 
1941     LIST_FOR_EACH(family_elem_ptr, &font_list) {
1942         family = LIST_ENTRY(family_elem_ptr, Family, entry); 
1943         len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1944         LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1945             face = LIST_ENTRY(face_elem_ptr, Face, entry);
1946             if(!face->external) continue;
1947             len = len_fam;
1948             if (!(face->ntmFlags & NTM_REGULAR))
1949                 len = len_fam + strlenW(face->StyleName) + 1;
1950             valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1951             strcpyW(valueW, family->FamilyName);
1952             if(len != len_fam) {
1953                 strcatW(valueW, spaceW);
1954                 strcatW(valueW, face->StyleName);
1955             }
1956             strcatW(valueW, TrueType);
1957 
1958             file = wine_get_dos_file_name(face->file);
1959             if(file)
1960                 len = strlenW(file) + 1;
1961             else
1962             {
1963                 if((path = strrchr(face->file, '/')) == NULL)
1964                     path = face->file;
1965                 else
1966                     path++;
1967                 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1968 
1969                 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1970                 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1971             }
1972             RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1973             RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1974             RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1975 
1976             HeapFree(GetProcessHeap(), 0, file);
1977             HeapFree(GetProcessHeap(), 0, valueW);
1978         }
1979     }
1980  end:
1981     if(external_key) RegCloseKey(external_key);
1982     if(win9x_key) RegCloseKey(win9x_key);
1983     if(winnt_key) RegCloseKey(winnt_key);
1984     return;
1985 }
1986 
1987 static void delete_external_font_keys(void)
1988 {
1989     HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1990     DWORD dlen, vlen, datalen, valuelen, i, type;
1991     LPWSTR valueW;
1992     LPVOID data;
1993 
1994     if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1995                        0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1996         ERR("Can't create Windows font reg key\n");
1997         goto end;
1998     }
1999 
2000     if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2001                        0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2002         ERR("Can't create Windows font reg key\n");
2003         goto end;
2004     }
2005 
2006     if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2007         ERR("Can't create external font reg key\n");
2008         goto end;
2009     }
2010 
2011     /* Delete all external fonts added last time */
2012 
2013     RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2014                      &valuelen, &datalen, NULL, NULL);
2015     valuelen++; /* returned value doesn't include room for '\0' */
2016     valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2017     data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2018 
2019     dlen = datalen * sizeof(WCHAR);
2020     vlen = valuelen;
2021     i = 0;
2022     while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2023                         &dlen) == ERROR_SUCCESS) {
2024 
2025         RegDeleteValueW(winnt_key, valueW);
2026         RegDeleteValueW(win9x_key, valueW);
2027         /* reset dlen and vlen */
2028         dlen = datalen;
2029         vlen = valuelen;
2030     }
2031     HeapFree(GetProcessHeap(), 0, data);
2032     HeapFree(GetProcessHeap(), 0, valueW);
2033 
2034     /* Delete the old external fonts key */
2035     RegCloseKey(external_key);
2036     RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2037 
2038  end:
2039     if(win9x_key) RegCloseKey(win9x_key);
2040     if(winnt_key) RegCloseKey(winnt_key);
2041 }
2042 
2043 /*************************************************************
2044  *    WineEngAddFontResourceEx
2045  *
2046  */
2047 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2048 {
2049     INT ret = 0;
2050     if (ft_handle)  /* do it only if we have freetype up and running */
2051     {
2052         char *unixname;
2053 
2054         if(flags)
2055             FIXME("Ignoring flags %x\n", flags);
2056 
2057         if((unixname = wine_get_unix_file_name(file)))
2058         {
2059             EnterCriticalSection( &freetype_cs );
2060             ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2061             LeaveCriticalSection( &freetype_cs );
2062             HeapFree(GetProcessHeap(), 0, unixname);
2063         }
2064         if (!ret && !strchrW(file, '\\')) {
2065             /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2066             ret = load_font_from_winfonts_dir(file);
2067             if (!ret) {
2068                 /* Try in datadir/fonts (or builddir/fonts),
2069                  * needed for Magic the Gathering Online
2070                  */
2071                 ret = load_font_from_data_dir(file);
2072             }
2073         }
2074     }
2075    return ret;
2076 }
2077 
2078 /*************************************************************
2079  *    WineEngAddFontMemResourceEx
2080  *
2081  */
2082 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2083 {
2084     if (ft_handle)  /* do it only if we have freetype up and running */
2085     {
2086         PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2087 
2088         TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2089         memcpy(pFontCopy, pbFont, cbFont);
2090 
2091         EnterCriticalSection( &freetype_cs );
2092         *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2093         LeaveCriticalSection( &freetype_cs );
2094 
2095         if (*pcFonts == 0)
2096         {
2097             TRACE("AddFontToList failed\n");
2098             HeapFree(GetProcessHeap(), 0, pFontCopy);
2099             return NULL;
2100         }
2101         /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2102          * For now return something unique but quite random
2103          */
2104         TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2105         return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2106     }
2107 
2108     *pcFonts = 0;
2109     return 0;
2110 }
2111 
2112 /*************************************************************
2113  *    WineEngRemoveFontResourceEx
2114  *
2115  */
2116 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2117 {
2118     FIXME(":stub\n");
2119     return TRUE;
2120 }
2121 
2122 static const struct nls_update_font_list
2123 {
2124     UINT ansi_cp, oem_cp;
2125     const char *oem, *fixed, *system;
2126     const char *courier, *serif, *small, *sserif;
2127     /* these are for font substitutes */
2128     const char *shelldlg, *tmsrmn;
2129     const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2130                *helv_0, *tmsrmn_0;
2131     const struct subst
2132     {
2133         const char *from, *to;
2134     } arial_0, courier_new_0, times_new_roman_0;
2135 } nls_update_font_list[] =
2136 {
2137     /* Latin 1 (United States) */
2138     { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2139       "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2140       "Tahoma","Times New Roman",
2141       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2142       { 0 }, { 0 }, { 0 }
2143     },
2144     /* Latin 1 (Multilingual) */
2145     { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2146       "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2147       "Tahoma","Times New Roman",  /* FIXME unverified */
2148       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2149       { 0 }, { 0 }, { 0 }
2150     },
2151     /* Eastern Europe */
2152     { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2153       "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2154       "Tahoma","Times New Roman", /* FIXME unverified */
2155       "Fixedsys,238", "System,238",
2156       "Courier New,238", "MS Serif,238", "Small Fonts,238",
2157       "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2158       { "Arial CE,0", "Arial,238" },
2159       { "Courier New CE,0", "Courier New,238" },
2160       { "Times New Roman CE,0", "Times New Roman,238" }
2161     },
2162     /* Cyrillic */
2163     { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2164       "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2165       "Tahoma","Times New Roman", /* FIXME unverified */
2166       "Fixedsys,204", "System,204",
2167       "Courier New,204", "MS Serif,204", "Small Fonts,204",
2168       "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2169       { "Arial Cyr,0", "Arial,204" },
2170       { "Courier New Cyr,0", "Courier New,204" },
2171       { "Times New Roman Cyr,0", "Times New Roman,204" }
2172     },
2173     /* Greek */
2174     { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2175       "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2176       "Tahoma","Times New Roman", /* FIXME unverified */
2177       "Fixedsys,161", "System,161",
2178       "Courier New,161", "MS Serif,161", "Small Fonts,161",
2179       "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2180       { "Arial Greek,0", "Arial,161" },
2181       { "Courier New Greek,0", "Courier New,161" },
2182       { "Times New Roman Greek,0", "Times New Roman,161" }
2183     },
2184     /* Turkish */
2185     { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2186       "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2187       "Tahoma","Times New Roman", /* FIXME unverified */
2188       "Fixedsys,162", "System,162",
2189       "Courier New,162", "MS Serif,162", "Small Fonts,162",
2190       "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2191       { "Arial Tur,0", "Arial,162" },
2192       { "Courier New Tur,0", "Courier New,162" },
2193       { "Times New Roman Tur,0", "Times New Roman,162" }
2194     },
2195     /* Hebrew */
2196     { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2197       "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2198       "Tahoma","Times New Roman", /* FIXME unverified */
2199       "Fixedsys,177", "System,177",
2200       "Courier New,177", "MS Serif,177", "Small Fonts,177",
2201       "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2202       { 0 }, { 0 }, { 0 }
2203     },
2204     /* Arabic */
2205     { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2206       "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2207       "Tahoma","Times New Roman", /* FIXME unverified */
2208       "Fixedsys,178", "System,178",
2209       "Courier New,178", "MS Serif,178", "Small Fonts,178",
2210       "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2211       { 0 }, { 0 }, { 0 }
2212     },
2213     /* Baltic */
2214     { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2215       "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2216       "Tahoma","Times New Roman", /* FIXME unverified */
2217       "Fixedsys,186", "System,186",
2218       "Courier New,186", "MS Serif,186", "Small Fonts,186",
2219       "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2220       { "Arial Baltic,0", "Arial,186" },
2221       { "Courier New Baltic,0", "Courier New,186" },
2222       { "Times New Roman Baltic,0", "Times New Roman,186" }
2223     },
2224     /* Vietnamese */
2225     { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2226       "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2227       "Tahoma","Times New Roman", /* FIXME unverified */
2228       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2229       { 0 }, { 0 }, { 0 }
2230     },
2231     /* Thai */
2232     { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2233       "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2234       "Tahoma","Times New Roman", /* FIXME unverified */
2235       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2236       { 0 }, { 0 }, { 0 }
2237     },
2238     /* Japanese */
2239     { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2240       "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2241       "MS UI Gothic","MS Serif",
2242       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2243       { 0 }, { 0 }, { 0 }
2244     },
2245     /* Chinese Simplified */
2246     { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2247       "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2248       "Tahoma", "Times New Roman", /* FIXME unverified */
2249       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2250       { 0 }, { 0 }, { 0 }
2251     },
2252     /* Korean */
2253     { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2254       "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2255       "Gulim",  "Batang",
2256       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2257       { 0 }, { 0 }, { 0 }
2258     },
2259     /* Chinese Traditional */
2260     { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2261       "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2262       "PMingLiU",  "MingLiU",
2263       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2264       { 0 }, { 0 }, { 0 }
2265     }
2266 };
2267 
2268 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2269 {
2270     return ( ansi_cp == 932       /* CP932 for Japanese */
2271             || ansi_cp == 936     /* CP936 for Chinese Simplified */
2272             || ansi_cp == 949     /* CP949 for Korean */
2273             || ansi_cp == 950 );  /* CP950 for Chinese Traditional */
2274 }
2275 
2276 static inline HKEY create_fonts_NT_registry_key(void)
2277 {
2278     HKEY hkey = 0;
2279 
2280     RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2281                     0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2282     return hkey;
2283 }
2284 
2285 static inline HKEY create_fonts_9x_registry_key(void)
2286 {
2287     HKEY hkey = 0;
2288 
2289     RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2290                     0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2291     return hkey;
2292 }
2293 
2294 static inline HKEY create_config_fonts_registry_key(void)
2295 {
2296     HKEY hkey = 0;
2297 
2298     RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2299                     0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2300     return hkey;
2301 }
2302 
2303 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2304 {
2305     RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2306     RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2307     RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2308     RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2309 }
2310 
2311 static void set_value_key(HKEY hkey, const char *name, const char *value)
2312 {
2313     if (value)
2314         RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2315     else if (name)
2316         RegDeleteValueA(hkey, name);
2317 }
2318 
2319 static void update_font_info(void)
2320 {
2321     char buf[40], cpbuf[40];
2322     DWORD len, type;
2323     HKEY hkey = 0;
2324     UINT i, ansi_cp = 0, oem_cp = 0;
2325     BOOL done = FALSE;
2326 
2327     if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2328         return;
2329 
2330     GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2331                    (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2332     GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2333                    (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2334     sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2335 
2336     /* Setup Default_Fallback usage for DBCS ANSI codepages */
2337     if (is_dbcs_ansi_cp(ansi_cp))
2338         use_default_fallback = TRUE;
2339 
2340     len = sizeof(buf);
2341     if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2342     {
2343         if (!strcmp( buf, cpbuf ))  /* already set correctly */
2344         {
2345             RegCloseKey(hkey);
2346             return;
2347         }
2348         TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2349     }
2350     else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2351 
2352     RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2353     RegCloseKey(hkey);
2354 
2355     for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2356     {
2357         HKEY hkey;
2358 
2359         if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2360             nls_update_font_list[i].oem_cp == oem_cp)
2361         {
2362             hkey = create_config_fonts_registry_key();
2363             RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2364             RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2365             RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2366             RegCloseKey(hkey);
2367 
2368             hkey = create_fonts_NT_registry_key();
2369             add_font_list(hkey, &nls_update_font_list[i]);
2370             RegCloseKey(hkey);
2371 
2372             hkey = create_fonts_9x_registry_key();
2373             add_font_list(hkey, &nls_update_font_list[i]);
2374             RegCloseKey(hkey);
2375 
2376             if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2377             {
2378                 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2379                                strlen(nls_update_font_list[i].shelldlg)+1);
2380                 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2381                                strlen(nls_update_font_list[i].tmsrmn)+1);
2382 
2383                 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2384                 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2385                 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2386                 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2387                 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2388                 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2389                 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2390                 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2391 
2392                 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2393                 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2394                 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2395 
2396                 RegCloseKey(hkey);
2397             }
2398             done = TRUE;
2399         }
2400         else
2401         {
2402             /* Delete the FontSubstitutes from other locales */
2403             if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2404             {
2405                 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2406                 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2407                 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2408                 RegCloseKey(hkey);
2409             }
2410         }
2411     }
2412     if (!done)
2413         FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2414 }
2415 
2416 
2417 static BOOL init_freetype(void)
2418 {
2419     ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2420     if(!ft_handle) {
2421         WINE_MESSAGE(
2422       "Wine cannot find the FreeType font library.  To enable Wine to\n"
2423       "use TrueType fonts please install a version of FreeType greater than\n"
2424       "or equal to 2.0.5.\n"
2425       "http://www.freetype.org\n");
2426         return FALSE;
2427     }
2428 
2429 #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;}
2430 
2431     LOAD_FUNCPTR(FT_Vector_Unit)
2432     LOAD_FUNCPTR(FT_Done_Face)
2433     LOAD_FUNCPTR(FT_Get_Char_Index)
2434     LOAD_FUNCPTR(FT_Get_Module)
2435     LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2436     LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2437     LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2438     LOAD_FUNCPTR(FT_Init_FreeType)
2439     LOAD_FUNCPTR(FT_Load_Glyph)
2440     LOAD_FUNCPTR(FT_Matrix_Multiply)
2441 #ifndef FT_MULFIX_INLINED
2442     LOAD_FUNCPTR(FT_MulFix)
2443 #endif
2444     LOAD_FUNCPTR(FT_New_Face)
2445     LOAD_FUNCPTR(FT_New_Memory_Face)
2446     LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2447     LOAD_FUNCPTR(FT_Outline_Transform)
2448     LOAD_FUNCPTR(FT_Outline_Translate)
2449     LOAD_FUNCPTR(FT_Select_Charmap)
2450     LOAD_FUNCPTR(FT_Set_Charmap)
2451     LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2452     LOAD_FUNCPTR(FT_Vector_Transform)
2453 
2454 #undef LOAD_FUNCPTR
2455     /* Don't warn if these ones are missing */
2456     pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2457     pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2458     pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2459     pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2460     pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2461 #ifdef HAVE_FREETYPE_FTWINFNT_H
2462     pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2463 #endif
2464       if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2465          !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2466         /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2467            <= 2.0.3 has FT_Sqrt64 */
2468           goto sym_not_found;
2469       }
2470 
2471     if(pFT_Init_FreeType(&library) != 0) {
2472         ERR("Can't init FreeType library\n");
2473         wine_dlclose(ft_handle, NULL, 0);
2474         ft_handle = NULL;
2475         return FALSE;
2476     }
2477     FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2478     if (pFT_Library_Version)
2479         pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2480 
2481     if (FT_Version.major<=0)
2482     {
2483         FT_Version.major=2;
2484         FT_Version.minor=0;
2485         FT_Version.patch=5;
2486     }
2487     TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2488     FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2489                        ((FT_Version.minor <<  8) & 0x00ff00) |
2490                        ((FT_Version.patch      ) & 0x0000ff);
2491 
2492     return TRUE;
2493 
2494 sym_not_found:
2495     WINE_MESSAGE(
2496       "Wine cannot find certain functions that it needs inside the FreeType\n"
2497       "font library.  To enable Wine to use TrueType fonts please upgrade\n"
2498       "FreeType to at least version 2.0.5.\n"
2499       "http://www.freetype.org\n");
2500     wine_dlclose(ft_handle, NULL, 0);
2501     ft_handle = NULL;
2502     return FALSE;
2503 }
2504 
2505 /*************************************************************
2506  *    WineEngInit
2507  *
2508  * Initialize FreeType library and create a list of available faces
2509  */
2510 BOOL WineEngInit(void)
2511 {
2512     static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2513     static const WCHAR pathW[] = {'P','a','t','h',0};
2514     HKEY hkey;
2515     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2516     LPVOID data;
2517     WCHAR windowsdir[MAX_PATH];
2518     char *unixname;
2519     HANDLE font_mutex;
2520     const char *data_dir;
2521 
2522     TRACE("\n");
2523 
2524     /* update locale dependent font info in registry */
2525     update_font_info();
2526 
2527     if(!init_freetype()) return FALSE;
2528 
2529     if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2530         ERR("Failed to create font mutex\n");
2531         return FALSE;
2532     }
2533     WaitForSingleObject(font_mutex, INFINITE);
2534 
2535     delete_external_font_keys();
2536 
2537     /* load the system bitmap fonts */
2538     load_system_fonts();
2539 
2540     /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2541     GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2542     strcatW(windowsdir, fontsW);
2543     if((unixname = wine_get_unix_file_name(windowsdir)))
2544     {
2545         ReadFontDir(unixname, FALSE);
2546         HeapFree(GetProcessHeap(), 0, unixname);
2547     }
2548 
2549     /* load the system truetype fonts */
2550     data_dir = wine_get_data_dir();
2551     if (!data_dir) data_dir = wine_get_build_dir();
2552     if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2553         strcpy(unixname, data_dir);
2554         strcat(unixname, "/fonts/");
2555         ReadFontDir(unixname, TRUE);
2556         HeapFree(GetProcessHeap(), 0, unixname);
2557     }
2558 
2559     /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2560        for any fonts not installed in %WINDOWSDIR%\Fonts.  They will have their
2561        full path as the entry.  Also look for any .fon fonts, since ReadFontDir
2562        will skip these. */
2563     if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2564                    is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2565                    &hkey) == ERROR_SUCCESS) {
2566         LPWSTR valueW;
2567         RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2568                          &valuelen, &datalen, NULL, NULL);
2569 
2570         valuelen++; /* returned value doesn't include room for '\0' */
2571         valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2572         data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2573         if (valueW && data)
2574         {
2575             dlen = datalen * sizeof(WCHAR);
2576             vlen = valuelen;
2577             while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2578                                 &dlen) == ERROR_SUCCESS) {
2579                 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2580                 {
2581                     if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2582                     {
2583                         AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2584                         HeapFree(GetProcessHeap(), 0, unixname);
2585                     }
2586                 }
2587                 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2588                 {
2589                     WCHAR pathW[MAX_PATH];
2590                     static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2591                     BOOL added = FALSE;
2592 
2593                     sprintfW(pathW, fmtW, windowsdir, data);
2594                     if((unixname = wine_get_unix_file_name(pathW)))
2595                     {
2596                         added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2597                         HeapFree(GetProcessHeap(), 0, unixname);
2598                     }
2599                     if (!added)
2600                         load_font_from_data_dir(data);
2601                 }
2602                 /* reset dlen and vlen */
2603                 dlen = datalen;
2604                 vlen = valuelen;
2605             }
2606         }
2607         HeapFree(GetProcessHeap(), 0, data);
2608         HeapFree(GetProcessHeap(), 0, valueW);
2609         RegCloseKey(hkey);
2610     }
2611 
2612     load_fontconfig_fonts();
2613 
2614     /* then look in any directories that we've specified in the config file */
2615     /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2616     if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2617     {
2618         DWORD len;
2619         LPWSTR valueW;
2620         LPSTR valueA, ptr;
2621 
2622         if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2623         {
2624             len += sizeof(WCHAR);
2625             valueW = HeapAlloc( GetProcessHeap(), 0, len );
2626             if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2627             {
2628                 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2629                 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2630                 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2631                 TRACE( "got font path %s\n", debugstr_a(valueA) );
2632                 ptr = valueA;
2633                 while (ptr)
2634                 {
2635                     LPSTR next = strchr( ptr, ':' );
2636                     if (next) *next++ = 0;
2637                     ReadFontDir( ptr, TRUE );
2638                     ptr = next;
2639                 }
2640                 HeapFree( GetProcessHeap(), 0, valueA );
2641             }
2642             HeapFree( GetProcessHeap(), 0, valueW );
2643         }
2644         RegCloseKey(hkey);
2645     }
2646 
2647     DumpFontList();
2648     LoadSubstList();
2649     DumpSubstList();
2650     LoadReplaceList();
2651     update_reg_entries();
2652 
2653     init_system_links();
2654     
2655     ReleaseMutex(font_mutex);
2656     return TRUE;
2657 }
2658 
2659 
2660 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2661 {
2662     TT_OS2 *pOS2;
2663     TT_HoriHeader *pHori;
2664 
2665     LONG ppem;
2666 
2667     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2668     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2669 
2670     if(height == 0) height = 16;
2671 
2672     /* Calc. height of EM square:
2673      *
2674      * For +ve lfHeight we have
2675      * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2676      * Re-arranging gives:
2677      * ppem = units_per_em * lfheight / (winAscent + winDescent)
2678      *
2679      * For -ve lfHeight we have
2680      * |lfHeight| = ppem
2681      * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2682      * with il = winAscent + winDescent - units_per_em]
2683      *
2684      */
2685 
2686     if(height > 0) {
2687         if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2688             ppem = MulDiv(ft_face->units_per_EM, height,
2689                           pHori->Ascender - pHori->Descender);
2690         else
2691             ppem = MulDiv(ft_face->units_per_EM, height,
2692                           pOS2->usWinAscent + pOS2->usWinDescent);
2693     }
2694     else
2695         ppem = -height;
2696 
2697     return ppem;
2698 }
2699 
2700 static struct font_mapping *map_font_file( const char *name )
2701 {
2702     struct font_mapping *mapping;
2703     struct stat st;
2704     int fd;
2705 
2706     if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2707     if (fstat( fd, &st ) == -1) goto error;
2708 
2709     LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2710     {
2711         if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2712         {
2713             mapping->refcount++;
2714             close( fd );
2715             return mapping;
2716         }
2717     }
2718     if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2719         goto error;
2720 
2721     mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2722     close( fd );
2723 
2724     if (mapping->data == MAP_FAILED)
2725     {
2726         HeapFree( GetProcessHeap(), 0, mapping );
2727         return NULL;
2728     }
2729     mapping->refcount = 1;
2730     mapping->dev = st.st_dev;
2731     mapping->ino = st.st_ino;
2732     mapping->size = st.st_size;
2733     list_add_tail( &mappings_list, &mapping->entry );
2734     return mapping;
2735 
2736 error:
2737     close( fd );
2738     return NULL;
2739 }
2740 
2741 static void unmap_font_file( struct font_mapping *mapping )
2742 {
2743     if (!--mapping->refcount)
2744     {
2745         list_remove( &mapping->entry );
2746         munmap( mapping->data, mapping->size );
2747         HeapFree( GetProcessHeap(), 0, mapping );
2748     }
2749 }
2750 
2751 static LONG load_VDMX(GdiFont*, LONG);
2752 
2753 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2754 {
2755     FT_Error err;
2756     FT_Face ft_face;
2757     void *data_ptr;
2758     DWORD data_size;
2759 
2760     TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2761 
2762     if (face->file)
2763     {
2764         if (!(font->mapping = map_font_file( face->file )))
2765         {
2766             WARN("failed to map %s\n", debugstr_a(face->file));
2767             return 0;
2768         }
2769         data_ptr = font->mapping->data;
2770         data_size = font->mapping->size;
2771     }
2772     else
2773     {
2774         data_ptr = face->font_data_ptr;
2775         data_size = face->font_data_size;
2776     }
2777 
2778     err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2779     if(err) {
2780         ERR("FT_New_Face rets %d\n", err);
2781         return 0;
2782     }
2783 
2784     /* set it here, as load_VDMX needs it */
2785     font->ft_face = ft_face;
2786 
2787     if(FT_IS_SCALABLE(ft_face)) {
2788         /* load the VDMX table if we have one */
2789         font->ppem = load_VDMX(font, height);
2790         if(font->ppem == 0)
2791             font->ppem = calc_ppem_for_height(ft_face, height);
2792         TRACE("height %d => ppem %d\n", height, font->ppem);
2793 
2794         if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2795             WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2796     } else {
2797         font->ppem = height;
2798         if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2799             WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2800     }
2801     return ft_face;
2802 }
2803 
2804 
2805 static int get_nearest_charset(Face *face, int *cp)
2806 {
2807   /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2808      a single face with the requested charset.  The idea is to check if
2809      the selected font supports the current ANSI codepage, if it does
2810      return the corresponding charset, else return the first charset */
2811 
2812     CHARSETINFO csi;
2813     int acp = GetACP(), i;
2814     DWORD fs0;
2815 
2816     *cp = acp;
2817     if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2818         if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2819             return csi.ciCharset;
2820 
2821     for(i = 0; i < 32; i++) {
2822         fs0 = 1L << i;
2823         if(face->fs.fsCsb[0] & fs0) {
2824             if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2825                 *cp = csi.ciACP;
2826                 return csi.ciCharset;
2827             }
2828             else
2829                 FIXME("TCI failing on %x\n", fs0);
2830         }
2831     }
2832 
2833     FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2834           face->fs.fsCsb[0], face->file);
2835     *cp = acp;
2836     return DEFAULT_CHARSET;
2837 }
2838 
2839 static GdiFont *alloc_font(void)
2840 {
2841     GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2842     ret->gmsize = 1;
2843     ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2844     ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2845     ret->potm = NULL;
2846     ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2847     ret->total_kern_pairs = (DWORD)-1;
2848     ret->kern_pairs = NULL;
2849     list_init(&ret->hfontlist);
2850     list_init(&ret->child_fonts);
2851     return ret;
2852 }
2853 
2854 static void free_font(GdiFont *font)
2855 {
2856     struct list *cursor, *cursor2;
2857     int i;
2858 
2859     LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2860     {
2861         CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2862         struct list *first_hfont;
2863         HFONTLIST *hfontlist;
2864         list_remove(cursor);
2865         if(child->font)
2866         {
2867             first_hfont = list_head(&child->font->hfontlist);
2868             hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2869             DeleteObject(hfontlist->hfont);
2870             HeapFree(GetProcessHeap(), 0, hfontlist);
2871             free_font(child->font);
2872         }
2873         HeapFree(GetProcessHeap(), 0, child);
2874     }
2875 
2876     if (font->ft_face) pFT_Done_Face(font->ft_face);
2877     if (font->mapping) unmap_font_file( font->mapping );
2878     HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2879     HeapFree(GetProcessHeap(), 0, font->potm);
2880     HeapFree(GetProcessHeap(), 0, font->name);
2881     for (i = 0; i < font->gmsize; i++)
2882         HeapFree(GetProcessHeap(),0,font->gm[i]);
2883     HeapFree(GetProcessHeap(), 0, font->gm);
2884     HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2885     HeapFree(GetProcessHeap(), 0, font);
2886 }
2887 
2888 
2889 /*************************************************************
2890  * load_VDMX
2891  *
2892  * load the vdmx entry for the specified height
2893  */
2894 
2895 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2896           ( ( (FT_ULong)_x4 << 24 ) |     \
2897             ( (FT_ULong)_x3 << 16 ) |     \
2898             ( (FT_ULong)_x2 <<  8 ) |     \
2899               (FT_ULong)_x1         )
2900 
2901 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2902 
2903 typedef struct {
2904     BYTE bCharSet;
2905     BYTE xRatio;
2906     BYTE yStartRatio;
2907     BYTE yEndRatio;
2908 } Ratios;
2909 
2910 typedef struct {
2911     WORD recs;
2912     BYTE startsz;
2913     BYTE endsz;
2914 } VDMX_group;
2915 
2916 static LONG load_VDMX(GdiFont *font, LONG height)
2917 {
2918     WORD hdr[3], tmp;
2919     VDMX_group group;
2920     BYTE devXRatio, devYRatio;
2921     USHORT numRecs, numRatios;
2922     DWORD result, offset = -1;
2923     LONG ppem = 0;
2924     int i;
2925 
2926     result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2927 
2928     if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2929         return ppem;
2930 
2931     /* FIXME: need the real device aspect ratio */
2932     devXRatio = 1;
2933     devYRatio = 1;
2934 
2935     numRecs = GET_BE_WORD(hdr[1]);
2936     numRatios = GET_BE_WORD(hdr[2]);
2937 
2938     TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2939     for(i = 0; i < numRatios; i++) {
2940         Ratios ratio;
2941 
2942         offset = (3 * 2) + (i * sizeof(Ratios));
2943         WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2944         offset = -1;
2945 
2946         TRACE("Ratios[%d] %d  %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2947 
2948         if((ratio.xRatio == 0 &&
2949             ratio.yStartRatio == 0 &&
2950             ratio.yEndRatio == 0) ||
2951            (devXRatio == ratio.xRatio &&
2952             devYRatio >= ratio.yStartRatio &&
2953             devYRatio <= ratio.yEndRatio))
2954             {
2955                 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2956                 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2957                 offset = GET_BE_WORD(tmp);
2958                 break;
2959             }
2960     }
2961 
2962     if(offset == -1) {
2963         FIXME("No suitable ratio found\n");
2964         return ppem;
2965     }
2966 
2967     if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2968         USHORT recs;
2969         BYTE startsz, endsz;
2970         WORD *vTable;
2971 
2972         recs = GET_BE_WORD(group.recs);
2973         startsz = group.startsz;
2974         endsz = group.endsz;
2975 
2976         TRACE("recs=%d  startsz=%d  endsz=%d\n", recs, startsz, endsz);
2977 
2978         vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2979         result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2980         if(result == GDI_ERROR) {
2981             FIXME("Failed to retrieve vTable\n");
2982             goto end;
2983         }
2984 
2985         if(height > 0) {
2986             for(i = 0; i < recs; i++) {
2987                 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2988                 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2989                 ppem = GET_BE_WORD(vTable[i * 3]);
2990 
2991                 if(yMax + -yMin == height) {
2992                     font->yMax = yMax;
2993                     font->yMin = yMin;
2994                     TRACE("ppem %d found; height=%d  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
2995                     break;
2996                 }
2997                 if(yMax + -yMin > height) {
2998                     if(--i < 0) {
2999                         ppem = 0;
3000                         goto end; /* failed */
3001                     }
3002                     font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3003                     font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3004                     ppem = GET_BE_WORD(vTable[i * 3]);
3005                     TRACE("ppem %d found; height=%d  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
3006                     break;
3007                 }
3008             }
3009             if(!font->yMax) {
3010                 ppem = 0;
3011                 TRACE("ppem not found for height %d\n", height);
3012             }
3013         } else {
3014             ppem = -height;
3015             if(ppem < startsz || ppem > endsz)
3016                 goto end;
3017 
3018             for(i = 0; i < recs; i++) {
3019                 USHORT yPelHeight;
3020                 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3021 
3022                 if(yPelHeight > ppem)
3023                     break; /* failed */
3024 
3025                 if(yPelHeight == ppem) {
3026                     font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3027                     font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3028                     TRACE("ppem %d found; yMax=%d  yMin=%d\n", ppem, font->yMax, font->yMin);
3029                     break;
3030                 }
3031             }
3032         }
3033         end:
3034         HeapFree(GetProcessHeap(), 0, vTable);
3035     }
3036 
3037     return ppem;
3038 }
3039 
3040 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3041 {
3042     if(font->font_desc.hash != fd->hash) return TRUE;
3043     if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3044     if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3045     if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3046     return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3047 }
3048 
3049 static void calc_hash(FONT_DESC *pfd)
3050 {
3051     DWORD hash = 0, *ptr, two_chars;
3052     WORD *pwc;
3053     unsigned int i;
3054 
3055     for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3056         hash ^= *ptr;
3057     for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3058         hash ^= *ptr;
3059     for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3060         two_chars = *ptr;
3061         pwc = (WCHAR *)&two_chars;
3062         if(!*pwc) break;
3063         *pwc = toupperW(*pwc);
3064         pwc++;
3065         *pwc = toupperW(*pwc);
3066         hash ^= two_chars;
3067         if(!*pwc) break;
3068     }
3069     hash ^= !pfd->can_use_bitmap;
3070     pfd->hash = hash;
3071     return;
3072 }
3073 
3074 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3075 {
3076     GdiFont *ret;
3077     FONT_DESC fd;
3078     HFONTLIST *hflist;
3079     struct list *font_elem_ptr, *hfontlist_elem_ptr;
3080 
3081     fd.lf = *plf;
3082     fd.matrix = *pmat;
3083     fd.can_use_bitmap = can_use_bitmap;
3084     calc_hash(&fd);
3085 
3086     /* try the in-use list */
3087     LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3088         ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3089         if(!fontcmp(ret, &fd)) {
3090             if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3091             LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3092                 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3093                 if(hflist->hfont == hfont)
3094                     return ret;
3095             }
3096             hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3097             hflist->hfont = hfont;
3098             list_add_head(&ret->hfontlist, &hflist->entry);
3099             return ret;
3100         }
3101     }
3102  
3103     /* then the unused list */
3104     font_elem_ptr = list_head(&unused_gdi_font_list);
3105     while(font_elem_ptr) {
3106         ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3107         font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3108         if(!fontcmp(ret, &fd)) {
3109             if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3110             assert(list_empty(&ret->hfontlist));
3111             TRACE("Found %p in unused list\n", ret);
3112             list_remove(&ret->entry);
3113             list_add_head(&gdi_font_list, &ret->entry);
3114             hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3115             hflist->hfont = hfont;
3116             list_add_head(&ret->hfontlist, &hflist->entry);
3117             return ret;
3118         }
3119     }
3120     return NULL;
3121 }
3122 
3123 static void add_to_cache(GdiFont *font)
3124 {
3125     static DWORD cache_num = 1;
3126 
3127     font->cache_num = cache_num++;
3128     list_add_head(&gdi_font_list, &font->entry);
3129 }
3130 
3131 /*************************************************************
3132  * create_child_font_list
3133  */
3134 static BOOL create_child_font_list(GdiFont *font)
3135 {
3136     BOOL ret = FALSE;
3137     SYSTEM_LINKS *font_link;
3138     CHILD_FONT *font_link_entry, *new_child;
3139 
3140     LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3141     {
3142         if(!strcmpW(font_link->font_name, font->name))
3143         {
3144             TRACE("found entry in system list\n");
3145             LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3146             {
3147                 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3148                 new_child->face = font_link_entry->face;
3149                 new_child->font = NULL;
3150                 list_add_tail(&font->child_fonts, &new_child->entry);
3151                 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3152             }
3153             ret = TRUE;
3154             break;
3155         }
3156     }
3157     /*
3158      * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3159      * Sans Serif.  This is how asian windows get default fallbacks for fonts
3160      */
3161     if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3162         font->charset != OEM_CHARSET &&
3163         strcmpW(font->name,szDefaultFallbackLink) != 0)
3164         LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3165         {
3166             if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3167             {
3168                 TRACE("found entry in default fallback list\n");
3169                 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3170                 {
3171                     new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3172                     new_child->face = font_link_entry->face;
3173                     new_child->font = NULL;
3174                     list_add_tail(&font->child_fonts, &new_child->entry);
3175                     TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3176                 }
3177                 ret = TRUE;
3178                 break;
3179             }
3180         }
3181 
3182     return ret;
3183 }
3184 
3185 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3186 {
3187     FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3188 
3189     if (pFT_Set_Charmap)
3190     {
3191         FT_Int i;
3192         FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3193 
3194         cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3195 
3196         for (i = 0; i < ft_face->num_charmaps; i++)
3197         {
3198             if (ft_face->charmaps[i]->encoding == encoding)
3199             {
3200                 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3201                        ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3202 
3203                 switch (ft_face->charmaps[i]->platform_id)
3204                 {
3205                     default:
3206                         cmap_def = ft_face->charmaps[i];
3207                         break;
3208                     case 0: /* Apple Unicode */
3209                         cmap0 = ft_face->charmaps[i];
3210                         break;
3211                     case 1: /* Macintosh */
3212                         cmap1 = ft_face->charmaps[i];
3213                         break;
3214                     case 2: /* ISO */
3215                         cmap2 = ft_face->charmaps[i];
3216                         break;
3217                     case 3: /* Microsoft */
3218                         cmap3 = ft_face->charmaps[i];
3219                         break;
3220                 }
3221             }
3222 
3223             if (cmap3) /* prefer Microsoft cmap table */
3224                 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3225             else if (cmap1)
3226                 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3227             else if (cmap2)
3228                 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3229             else if (cmap0)
3230                 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3231             else if (cmap_def)
3232                 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3233         }
3234         return ft_err == FT_Err_Ok;
3235     }
3236 
3237     return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3238 }
3239 
3240 /*************************************************************
3241  * WineEngCreateFontInstance
3242  *
3243  */
3244 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3245 {
3246     GdiFont *ret;
3247     Face *face, *best, *best_bitmap;
3248     Family *family, *last_resort_family;
3249     struct list *family_elem_ptr, *face_elem_ptr;
3250     INT height, width = 0;
3251     unsigned int score = 0, new_score;
3252     signed int diff = 0, newdiff;
3253     BOOL bd, it, can_use_bitmap;
3254     LOGFONTW lf;
3255     CHARSETINFO csi;
3256     HFONTLIST *hflist;
3257     FMAT2 dcmat;
3258     FontSubst *psub = NULL;
3259 
3260     EnterCriticalSection( &freetype_cs );
3261 
3262     LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3263     {
3264         struct list *first_hfont = list_head(&ret->hfontlist);
3265         hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3266         if(hflist->hfont == hfont)
3267         {
3268             LeaveCriticalSection( &freetype_cs );
3269             return ret;
3270         }
3271     }
3272 
3273     if (!GetObjectW( hfont, sizeof(lf), &lf ))
3274     {
3275         LeaveCriticalSection( &freetype_cs );
3276         return NULL;
3277     }
3278     lf.lfWidth = abs(lf.lfWidth);
3279 
3280     can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3281 
3282     TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3283           debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3284           lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3285           lf.lfEscapement);
3286 
3287     if(dc->GraphicsMode == GM_ADVANCED)
3288         memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3289     else
3290     {
3291         /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3292            font scaling abilities. */
3293         dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3294         dcmat.eM21 = dcmat.eM12 = 0;
3295     }
3296 
3297     TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3298                                         dcmat.eM21, dcmat.eM22);
3299 
3300     /* check the cache first */
3301     if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3302         TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3303         LeaveCriticalSection( &freetype_cs );
3304         return ret;
3305     }
3306 
3307     TRACE("not in cache\n");
3308     if(list_empty(&font_list)) /* No fonts installed */
3309     {
3310         TRACE("No fonts installed\n");
3311         LeaveCriticalSection( &freetype_cs );
3312         return NULL;
3313     }
3314     if(!have_installed_roman_font)
3315     {
3316         TRACE("No roman font installed\n");
3317         LeaveCriticalSection( &freetype_cs );
3318         return NULL;
3319     }
3320 
3321     ret = alloc_font();
3322 
3323     ret->font_desc.matrix = dcmat;
3324     ret->font_desc.lf = lf;
3325     ret->font_desc.can_use_bitmap = can_use_bitmap;
3326     calc_hash(&ret->font_desc);
3327     hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3328     hflist->hfont = hfont;
3329     list_add_head(&ret->hfontlist, &hflist->entry);
3330 
3331     /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3332        SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3333        original value lfCharSet.  Note this is a special case for
3334        Symbol and doesn't happen at least for "Wingdings*" */
3335