~ [ 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 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
183 #endif
184 
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
198 #endif
199 
200 #undef MAKE_FUNCPTR
201 
202 #ifndef FT_MAKE_TAG
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204         ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205           ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
206 #endif
207 
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
210 #endif
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
213 #endif
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
216 #endif
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
219 #endif
220 
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
223 #else
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
225 #endif
226 
227 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
228 typedef struct {
229     FT_Short height;
230     FT_Short width;
231     FT_Pos size;
232     FT_Pos x_ppem;
233     FT_Pos y_ppem;
234     FT_Short internal_leading;
235 } Bitmap_Size;
236 
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238    So to let this compile on older versions of FreeType we'll define the
239    new structure here. */
240 typedef struct {
241     FT_Short height, width;
242     FT_Pos size, x_ppem, y_ppem;
243 } My_FT_Bitmap_Size;
244 
245 struct enum_data
246 {
247     ENUMLOGFONTEXW elf;
248     NEWTEXTMETRICEXW ntm;
249     DWORD type;
250 };
251 
252 typedef struct tagFace {
253     struct list entry;
254     WCHAR *StyleName;
255     char *file;
256     void *font_data_ptr;
257     DWORD font_data_size;
258     FT_Long face_index;
259     FONTSIGNATURE fs;
260     FONTSIGNATURE fs_links;
261     DWORD ntmFlags;
262     FT_Fixed font_version;
263     BOOL scalable;
264     Bitmap_Size size;     /* set if face is a bitmap */
265     BOOL external; /* TRUE if we should manually add this font to the registry */
266     struct tagFamily *family;
267     /* Cached data for Enum */
268     struct enum_data *cached_enum_data;
269 } Face;
270 
271 typedef struct tagFamily {
272     struct list entry;
273     const WCHAR *FamilyName;
274     struct list faces;
275 } Family;
276 
277 typedef struct {
278     GLYPHMETRICS gm;
279     INT adv; /* These three hold to widths of the unrotated chars */
280     INT lsb;
281     INT bbx;
282     BOOL init;
283 } GM;
284 
285 typedef struct {
286     FLOAT eM11, eM12;
287     FLOAT eM21, eM22;
288 } FMAT2;
289 
290 typedef struct {
291     DWORD hash;
292     LOGFONTW lf;
293     FMAT2 matrix;
294     BOOL can_use_bitmap;
295 } FONT_DESC;
296 
297 typedef struct tagHFONTLIST {
298     struct list entry;
299     HFONT hfont;
300 } HFONTLIST;
301 
302 typedef struct {
303     struct list entry;
304     Face *face;
305     GdiFont *font;
306 } CHILD_FONT;
307 
308 struct tagGdiFont {
309     struct list entry;
310     GM **gm;
311     DWORD gmsize;
312     struct list hfontlist;
313     OUTLINETEXTMETRICW *potm;
314     DWORD total_kern_pairs;
315     KERNINGPAIR *kern_pairs;
316     struct list child_fonts;
317 
318     /* the following members can be accessed without locking, they are never modified after creation */
319     FT_Face ft_face;
320     struct font_mapping *mapping;
321     LPWSTR name;
322     int charset;
323     int codepage;
324     BOOL fake_italic;
325     BOOL fake_bold;
326     BYTE underline;
327     BYTE strikeout;
328     INT orientation;
329     FONT_DESC font_desc;
330     LONG aveWidth, ppem;
331     float scale_y;
332     SHORT yMax;
333     SHORT yMin;
334     DWORD ntmFlags;
335     FONTSIGNATURE fs;
336     GdiFont *base_font;
337     VOID *GSUB_Table;
338 };
339 
340 typedef struct {
341     struct list entry;
342     const WCHAR *font_name;
343     struct list links;
344 } SYSTEM_LINKS;
345 
346 #define GM_BLOCK_SIZE 128
347 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
348 
349 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
350 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
351 #define UNUSED_CACHE_SIZE 10
352 static struct list child_font_list = LIST_INIT(child_font_list);
353 static struct list system_links = LIST_INIT(system_links);
354 
355 static struct list font_subst_list = LIST_INIT(font_subst_list);
356 
357 static struct list font_list = LIST_INIT(font_list);
358 
359 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
360 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
361 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
362 
363 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
364 
365 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
366 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
367                                            'W','i','n','d','o','w','s','\\',
368                                            'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
369                                            'F','o','n','t','s','\0'};
370 
371 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
372                                            'W','i','n','d','o','w','s',' ','N','T','\\',
373                                            'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
374                                            'F','o','n','t','s','\0'};
375 
376 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
377 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
378 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
379 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
380 
381 static const WCHAR * const SystemFontValues[4] = {
382     System_Value,
383     OEMFont_Value,
384     FixedSys_Value,
385     NULL
386 };
387 
388 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
389                                                'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
390 
391 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
392 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
393 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
394 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
395 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
396                                     'E','u','r','o','p','e','a','n','\0'};
397 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
398 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
399 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
400 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
401 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
402 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
403 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
404 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
405 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
406 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
407 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
408 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
409 
410 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
411     WesternW, /*00*/
412     Central_EuropeanW,
413     CyrillicW,
414     GreekW,
415     TurkishW,
416     HebrewW,
417     ArabicW,
418     BalticW,
419     VietnameseW, /*08*/
420     NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
421     ThaiW,
422     JapaneseW,
423     CHINESE_GB2312W,
424     HangulW,
425     CHINESE_BIG5W,
426     Hangul_Johab_W,
427     NULL, NULL, /*23*/
428     NULL, NULL, NULL, NULL, NULL, NULL, NULL,
429     SymbolW /*31*/
430 };
431 
432 typedef struct {
433     WCHAR *name;
434     INT charset;
435 } NameCs;
436 
437 typedef struct tagFontSubst {
438     struct list entry;
439     NameCs from;
440     NameCs to;
441 } FontSubst;
442 
443 struct font_mapping
444 {
445     struct list entry;
446     int         refcount;
447     dev_t       dev;
448     ino_t       ino;
449     void       *data;
450     size_t      size;
451 };
452 
453 static struct list mappings_list = LIST_INIT( mappings_list );
454 
455 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
456 
457 static CRITICAL_SECTION freetype_cs;
458 static CRITICAL_SECTION_DEBUG critsect_debug =
459 {
460     0, 0, &freetype_cs,
461     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
462       0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
463 };
464 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
465 
466 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
467 
468 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
469 static BOOL use_default_fallback = FALSE;
470 
471 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
472 
473 /****************************************
474  *   Notes on .fon files
475  *
476  * The fonts System, FixedSys and Terminal are special.  There are typically multiple
477  * versions installed for different resolutions and codepages.  Windows stores which one to use
478  * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
479  *    Key            Meaning
480  *  FIXEDFON.FON    FixedSys
481  *  FONTS.FON       System
482  *  OEMFONT.FON     Terminal
483  *  LogPixels       Current dpi set by the display control panel applet
484  *                  (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
485  *                  also has a LogPixels value that appears to mirror this)
486  *
487  * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
488  * (vgaoem.fon would be your oemfont.fon if you have a US setup).
489  * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
490  * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
491  * so that makes sense.
492  *
493  * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
494  * to be mapped into the registry on Windows 2000 at least).
495  * I have
496  * woafont=app850.fon
497  * ega80woa.fon=ega80850.fon
498  * ega40woa.fon=ega40850.fon
499  * cga80woa.fon=cga80850.fon
500  * cga40woa.fon=cga40850.fon
501  */
502 
503 /* These are all structures needed for the GSUB table */
504 
505 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
506 #define TATEGAKI_LOWER_BOUND  0x02F1
507 
508 typedef struct {
509     DWORD version;
510     WORD ScriptList;
511     WORD FeatureList;
512     WORD LookupList;
513 } GSUB_Header;
514 
515 typedef struct {
516     CHAR ScriptTag[4];
517     WORD Script;
518 } GSUB_ScriptRecord;
519 
520 typedef struct {
521     WORD ScriptCount;
522     GSUB_ScriptRecord ScriptRecord[1];
523 } GSUB_ScriptList;
524 
525 typedef struct {
526     CHAR LangSysTag[4];
527     WORD LangSys;
528 } GSUB_LangSysRecord;
529 
530 typedef struct {
531     WORD DefaultLangSys;
532     WORD LangSysCount;
533     GSUB_LangSysRecord LangSysRecord[1];
534 } GSUB_Script;
535 
536 typedef struct {
537     WORD LookupOrder; /* Reserved */
538     WORD ReqFeatureIndex;
539     WORD FeatureCount;
540     WORD FeatureIndex[1];
541 } GSUB_LangSys;
542 
543 typedef struct {
544     CHAR FeatureTag[4];
545     WORD Feature;
546 } GSUB_FeatureRecord;
547 
548 typedef struct {
549     WORD FeatureCount;
550     GSUB_FeatureRecord FeatureRecord[1];
551 } GSUB_FeatureList;
552 
553 typedef struct {
554     WORD FeatureParams; /* Reserved */
555     WORD LookupCount;
556     WORD LookupListIndex[1];
557 } GSUB_Feature;
558 
559 typedef struct {
560     WORD LookupCount;
561     WORD Lookup[1];
562 } GSUB_LookupList;
563 
564 typedef struct {
565     WORD LookupType;
566     WORD LookupFlag;
567     WORD SubTableCount;
568     WORD SubTable[1];
569 } GSUB_LookupTable;
570 
571 typedef struct {
572     WORD CoverageFormat;
573     WORD GlyphCount;
574     WORD GlyphArray[1];
575 } GSUB_CoverageFormat1;
576 
577 typedef struct {
578     WORD Start;
579     WORD End;
580     WORD StartCoverageIndex;
581 } GSUB_RangeRecord;
582 
583 typedef struct {
584     WORD CoverageFormat;
585     WORD RangeCount;
586     GSUB_RangeRecord RangeRecord[1];
587 } GSUB_CoverageFormat2;
588 
589 typedef struct {
590     WORD SubstFormat; /* = 1 */
591     WORD Coverage;
592     WORD DeltaGlyphID;
593 } GSUB_SingleSubstFormat1;
594 
595 typedef struct {
596     WORD SubstFormat; /* = 2 */
597     WORD Coverage;
598     WORD GlyphCount;
599     WORD Substitute[1];
600 }GSUB_SingleSubstFormat2;
601 
602 #ifdef HAVE_CARBON_CARBON_H
603 static char *find_cache_dir(void)
604 {
605     FSRef ref;
606     OSErr err;
607     static char cached_path[MAX_PATH];
608     static const char *wine = "/Wine", *fonts = "/Fonts";
609 
610     if(*cached_path) return cached_path;
611 
612     err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
613     if(err != noErr)
614     {
615         WARN("can't create cached data folder\n");
616         return NULL;
617     }
618     err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
619     if(err != noErr)
620     {
621         WARN("can't create cached data path\n");
622         *cached_path = '\0';
623         return NULL;
624     }
625     if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
626     {
627         ERR("Could not create full path\n");
628         *cached_path = '\0';
629         return NULL;
630     }
631     strcat(cached_path, wine);
632 
633     if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
634     {
635         WARN("Couldn't mkdir %s\n", cached_path);
636         *cached_path = '\0';
637         return NULL;
638     }
639     strcat(cached_path, fonts);
640     if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
641     {
642         WARN("Couldn't mkdir %s\n", cached_path);
643         *cached_path = '\0';
644         return NULL;
645     }
646     return cached_path;
647 }
648 
649 /******************************************************************
650  *            expand_mac_font
651  *
652  * Extracts individual TrueType font files from a Mac suitcase font
653  * and saves them into the user's caches directory (see
654  * find_cache_dir()).
655  * Returns a NULL terminated array of filenames.
656  *
657  * We do this because they are apps that try to read ttf files
658  * themselves and they don't like Mac suitcase files.
659  */
660 static char **expand_mac_font(const char *path)
661 {
662     FSRef ref;
663     SInt16 res_ref;
664     OSStatus s;
665     unsigned int idx;
666     const char *out_dir;
667     const char *filename;
668     int output_len;
669     struct {
670         char **array;
671         unsigned int size, max_size;
672     } ret;
673 
674     TRACE("path %s\n", path);
675 
676     s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
677     if(s != noErr)
678     {
679         WARN("failed to get ref\n");
680         return NULL;
681     }
682 
683     s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
684     if(s != noErr)
685     {
686         TRACE("no data fork, so trying resource fork\n");
687         res_ref = FSOpenResFile(&ref, fsRdPerm);
688         if(res_ref == -1)
689         {
690             TRACE("unable to open resource fork\n");
691             return NULL;
692         }
693     }
694 
695     ret.size = 0;
696     ret.max_size = 10;
697     ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
698     if(!ret.array)
699     {
700         CloseResFile(res_ref);
701         return NULL;
702     }
703 
704     out_dir = find_cache_dir();
705 
706     filename = strrchr(path, '/');
707     if(!filename) filename = path;
708     else filename++;
709 
710     /* output filename has the form out_dir/filename_%04x.ttf */
711     output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
712 
713     UseResFile(res_ref);
714     idx = 1;
715     while(1)
716     {
717         FamRec *fam_rec;
718         unsigned short *num_faces_ptr, num_faces, face;
719         AsscEntry *assoc;
720         Handle fond;
721         ResType fond_res = FT_MAKE_TAG('F','O','N','D');
722 
723         fond = Get1IndResource(fond_res, idx);
724         if(!fond) break;
725         TRACE("got fond resource %d\n", idx);
726         HLock(fond);
727 
728         fam_rec = *(FamRec**)fond;
729         num_faces_ptr = (unsigned short *)(fam_rec + 1);
730         num_faces = GET_BE_WORD(*num_faces_ptr);
731         num_faces++;
732         assoc = (AsscEntry*)(num_faces_ptr + 1);
733         TRACE("num faces %04x\n", num_faces);
734         for(face = 0; face < num_faces; face++, assoc++)
735         {
736             Handle sfnt;
737             ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
738             unsigned short size, font_id;
739             char *output;
740 
741             size = GET_BE_WORD(assoc->fontSize);
742             font_id = GET_BE_WORD(assoc->fontID);
743             if(size != 0)
744             {
745                 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
746                 continue;
747             }
748 
749             TRACE("trying to load sfnt id %04x\n", font_id);
750             sfnt = GetResource(sfnt_res, font_id);
751             if(!sfnt)
752             {
753                 TRACE("can't get sfnt resource %04x\n", font_id);
754                 continue;
755             }
756 
757             output = HeapAlloc(GetProcessHeap(), 0, output_len);
758             if(output)
759             {
760                 int fd;
761 
762                 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
763 
764                 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
765                 if(fd != -1 || errno == EEXIST)
766                 {
767                     if(fd != -1)
768                     {
769                         unsigned char *sfnt_data;
770 
771                         HLock(sfnt);
772                         sfnt_data = *(unsigned char**)sfnt;
773                         write(fd, sfnt_data, GetHandleSize(sfnt));
774                         HUnlock(sfnt);
775                         close(fd);
776                     }
777                     if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
778                     {
779                         ret.max_size *= 2;
780                         ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
781                     }
782                     ret.array[ret.size++] = output;
783                 }
784                 else
785                 {
786                     WARN("unable to create %s\n", output);
787                     HeapFree(GetProcessHeap(), 0, output);
788                 }
789             }
790             ReleaseResource(sfnt);
791         }
792         HUnlock(fond);
793         ReleaseResource(fond);
794         idx++;
795     }
796     CloseResFile(res_ref);
797 
798     return ret.array;
799 }
800 
801 #endif /* HAVE_CARBON_CARBON_H */
802 
803 static inline BOOL is_win9x(void)
804 {
805     return GetVersion() & 0x80000000;
806 }
807 /* 
808    This function builds an FT_Fixed from a float. It puts the integer part
809    in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
810    It fails if the integer part of the float number is greater than SHORT_MAX.
811 */
812 static inline FT_Fixed FT_FixedFromFloat(float f)
813 {
814         short value = f;
815         unsigned short fract = (f - value) * 0xFFFF;
816         return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
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(strcmpiW(face->StyleName, RegularW))
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     LOAD_FUNCPTR(FT_MulFix)
2442     LOAD_FUNCPTR(FT_New_Face)
2443     LOAD_FUNCPTR(FT_New_Memory_Face)
2444     LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2445     LOAD_FUNCPTR(FT_Outline_Transform)
2446     LOAD_FUNCPTR(FT_Outline_Translate)
2447     LOAD_FUNCPTR(FT_Select_Charmap)
2448     LOAD_FUNCPTR(FT_Set_Charmap)
2449     LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2450     LOAD_FUNCPTR(FT_Vector_Transform)
2451 
2452 #undef LOAD_FUNCPTR
2453     /* Don't warn if these ones are missing */
2454     pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2455     pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2456     pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2457     pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2458     pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2459 #ifdef HAVE_FREETYPE_FTWINFNT_H
2460     pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2461 #endif
2462       if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2463          !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2464         /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2465            <= 2.0.3 has FT_Sqrt64 */
2466           goto sym_not_found;
2467       }
2468 
2469     if(pFT_Init_FreeType(&library) != 0) {
2470         ERR("Can't init FreeType library\n");
2471         wine_dlclose(ft_handle, NULL, 0);
2472         ft_handle = NULL;
2473         return FALSE;
2474     }
2475     FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2476     if (pFT_Library_Version)
2477         pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2478 
2479     if (FT_Version.major<=0)
2480     {
2481         FT_Version.major=2;
2482         FT_Version.minor=0;
2483         FT_Version.patch=5;
2484     }
2485     TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2486     FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2487                        ((FT_Version.minor <<  8) & 0x00ff00) |
2488                        ((FT_Version.patch      ) & 0x0000ff);
2489 
2490     return TRUE;
2491 
2492 sym_not_found:
2493     WINE_MESSAGE(
2494       "Wine cannot find certain functions that it needs inside the FreeType\n"
2495       "font library.  To enable Wine to use TrueType fonts please upgrade\n"
2496       "FreeType to at least version 2.0.5.\n"
2497       "http://www.freetype.org\n");
2498     wine_dlclose(ft_handle, NULL, 0);
2499     ft_handle = NULL;
2500     return FALSE;
2501 }
2502 
2503 /*************************************************************
2504  *    WineEngInit
2505  *
2506  * Initialize FreeType library and create a list of available faces
2507  */
2508 BOOL WineEngInit(void)
2509 {
2510     static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2511     static const WCHAR pathW[] = {'P','a','t','h',0};
2512     HKEY hkey;
2513     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2514     LPVOID data;
2515     WCHAR windowsdir[MAX_PATH];
2516     char *unixname;
2517     HANDLE font_mutex;
2518     const char *data_dir;
2519 
2520     TRACE("\n");
2521 
2522     /* update locale dependent font info in registry */
2523     update_font_info();
2524 
2525     if(!init_freetype()) return FALSE;
2526 
2527     if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2528         ERR("Failed to create font mutex\n");
2529         return FALSE;
2530     }
2531     WaitForSingleObject(font_mutex, INFINITE);
2532 
2533     delete_external_font_keys();
2534 
2535     /* load the system bitmap fonts */
2536     load_system_fonts();
2537 
2538     /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2539     GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2540     strcatW(windowsdir, fontsW);
2541     if((unixname = wine_get_unix_file_name(windowsdir)))
2542     {
2543         ReadFontDir(unixname, FALSE);
2544         HeapFree(GetProcessHeap(), 0, unixname);
2545     }
2546 
2547     /* load the system truetype fonts */
2548     data_dir = wine_get_data_dir();
2549     if (!data_dir) data_dir = wine_get_build_dir();
2550     if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2551         strcpy(unixname, data_dir);
2552         strcat(unixname, "/fonts/");
2553         ReadFontDir(unixname, TRUE);
2554         HeapFree(GetProcessHeap(), 0, unixname);
2555     }
2556 
2557     /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2558        for any fonts not installed in %WINDOWSDIR%\Fonts.  They will have their
2559        full path as the entry.  Also look for any .fon fonts, since ReadFontDir
2560        will skip these. */
2561     if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2562                    is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2563                    &hkey) == ERROR_SUCCESS) {
2564         LPWSTR valueW;
2565         RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2566                          &valuelen, &datalen, NULL, NULL);
2567 
2568         valuelen++; /* returned value doesn't include room for '\0' */
2569         valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2570         data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2571         if (valueW && data)
2572         {
2573             dlen = datalen * sizeof(WCHAR);
2574             vlen = valuelen;
2575             while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2576                                 &dlen) == ERROR_SUCCESS) {
2577                 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2578                 {
2579                     if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2580                     {
2581                         AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2582                         HeapFree(GetProcessHeap(), 0, unixname);
2583                     }
2584                 }
2585                 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2586                 {
2587                     WCHAR pathW[MAX_PATH];
2588                     static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2589                     BOOL added = FALSE;
2590 
2591                     sprintfW(pathW, fmtW, windowsdir, data);
2592                     if((unixname = wine_get_unix_file_name(pathW)))
2593                     {
2594                         added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2595                         HeapFree(GetProcessHeap(), 0, unixname);
2596                     }
2597                     if (!added)
2598                         load_font_from_data_dir(data);
2599                 }
2600                 /* reset dlen and vlen */
2601                 dlen = datalen;
2602                 vlen = valuelen;
2603             }
2604         }
2605         HeapFree(GetProcessHeap(), 0, data);
2606         HeapFree(GetProcessHeap(), 0, valueW);
2607         RegCloseKey(hkey);
2608     }
2609 
2610     load_fontconfig_fonts();
2611 
2612     /* then look in any directories that we've specified in the config file */
2613     /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2614     if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2615     {
2616         DWORD len;
2617         LPWSTR valueW;
2618         LPSTR valueA, ptr;
2619 
2620         if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2621         {
2622             len += sizeof(WCHAR);
2623             valueW = HeapAlloc( GetProcessHeap(), 0, len );
2624             if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2625             {
2626                 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2627                 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2628                 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2629                 TRACE( "got font path %s\n", debugstr_a(valueA) );
2630                 ptr = valueA;
2631                 while (ptr)
2632                 {
2633                     LPSTR next = strchr( ptr, ':' );
2634                     if (next) *next++ = 0;
2635                     ReadFontDir( ptr, TRUE );
2636                     ptr = next;
2637                 }
2638                 HeapFree( GetProcessHeap(), 0, valueA );
2639             }
2640             HeapFree( GetProcessHeap(), 0, valueW );
2641         }
2642         RegCloseKey(hkey);
2643     }
2644 
2645     DumpFontList();
2646     LoadSubstList();
2647     DumpSubstList();
2648     LoadReplaceList();
2649     update_reg_entries();
2650 
2651     init_system_links();
2652     
2653     ReleaseMutex(font_mutex);
2654     return TRUE;
2655 }
2656 
2657 
2658 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2659 {
2660     TT_OS2 *pOS2;
2661     TT_HoriHeader *pHori;
2662 
2663     LONG ppem;
2664 
2665     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2666     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2667 
2668     if(height == 0) height = 16;
2669 
2670     /* Calc. height of EM square:
2671      *
2672      * For +ve lfHeight we have
2673      * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2674      * Re-arranging gives:
2675      * ppem = units_per_em * lfheight / (winAscent + winDescent)
2676      *
2677      * For -ve lfHeight we have
2678      * |lfHeight| = ppem
2679      * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2680      * with il = winAscent + winDescent - units_per_em]
2681      *
2682      */
2683 
2684     if(height > 0) {
2685         if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2686             ppem = ft_face->units_per_EM * height /
2687                 (pHori->Ascender - pHori->Descender);
2688         else
2689             ppem = ft_face->units_per_EM * height /
2690                 (pOS2->usWinAscent + pOS2->usWinDescent);
2691     }
2692     else
2693         ppem = -height;
2694 
2695     return ppem;
2696 }
2697 
2698 static struct font_mapping *map_font_file( const char *name )
2699 {
2700     struct font_mapping *mapping;
2701     struct stat st;
2702     int fd;
2703 
2704     if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2705     if (fstat( fd, &st ) == -1) goto error;
2706 
2707     LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2708     {
2709         if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2710         {
2711             mapping->refcount++;
2712             close( fd );
2713             return mapping;
2714         }
2715     }
2716     if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2717         goto error;
2718 
2719     mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2720     close( fd );
2721 
2722     if (mapping->data == MAP_FAILED)
2723     {
2724         HeapFree( GetProcessHeap(), 0, mapping );
2725         return NULL;
2726     }
2727     mapping->refcount = 1;
2728     mapping->dev = st.st_dev;
2729     mapping->ino = st.st_ino;
2730     mapping->size = st.st_size;
2731     list_add_tail( &mappings_list, &mapping->entry );
2732     return mapping;
2733 
2734 error:
2735     close( fd );
2736     return NULL;
2737 }
2738 
2739 static void unmap_font_file( struct font_mapping *mapping )
2740 {
2741     if (!--mapping->refcount)
2742     {
2743         list_remove( &mapping->entry );
2744         munmap( mapping->data, mapping->size );
2745         HeapFree( GetProcessHeap(), 0, mapping );
2746     }
2747 }
2748 
2749 static LONG load_VDMX(GdiFont*, LONG);
2750 
2751 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2752 {
2753     FT_Error err;
2754     FT_Face ft_face;
2755     void *data_ptr;
2756     DWORD data_size;
2757 
2758     TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2759 
2760     if (face->file)
2761     {
2762         if (!(font->mapping = map_font_file( face->file )))
2763         {
2764             WARN("failed to map %s\n", debugstr_a(face->file));
2765             return 0;
2766         }
2767         data_ptr = font->mapping->data;
2768         data_size = font->mapping->size;
2769     }
2770     else
2771     {
2772         data_ptr = face->font_data_ptr;
2773         data_size = face->font_data_size;
2774     }
2775 
2776     err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2777     if(err) {
2778         ERR("FT_New_Face rets %d\n", err);
2779         return 0;
2780     }
2781 
2782     /* set it here, as load_VDMX needs it */
2783     font->ft_face = ft_face;
2784 
2785     if(FT_IS_SCALABLE(ft_face)) {
2786         /* load the VDMX table if we have one */
2787         font->ppem = load_VDMX(font, height);
2788         if(font->ppem == 0)
2789             font->ppem = calc_ppem_for_height(ft_face, height);
2790 
2791         if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2792             WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2793     } else {
2794         font->ppem = height;
2795         if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2796             WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2797     }
2798     return ft_face;
2799 }
2800 
2801 
2802 static int get_nearest_charset(Face *face, int *cp)
2803 {
2804   /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2805      a single face with the requested charset.  The idea is to check if
2806      the selected font supports the current ANSI codepage, if it does
2807      return the corresponding charset, else return the first charset */
2808 
2809     CHARSETINFO csi;
2810     int acp = GetACP(), i;
2811     DWORD fs0;
2812 
2813     *cp = acp;
2814     if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2815         if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2816             return csi.ciCharset;
2817 
2818     for(i = 0; i < 32; i++) {
2819         fs0 = 1L << i;
2820         if(face->fs.fsCsb[0] & fs0) {
2821             if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2822                 *cp = csi.ciACP;
2823                 return csi.ciCharset;
2824             }
2825             else
2826                 FIXME("TCI failing on %x\n", fs0);
2827         }
2828     }
2829 
2830     FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2831           face->fs.fsCsb[0], face->file);
2832     *cp = acp;
2833     return DEFAULT_CHARSET;
2834 }
2835 
2836 static GdiFont *alloc_font(void)
2837 {
2838     GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2839     ret->gmsize = 1;
2840     ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2841     ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2842     ret->potm = NULL;
2843     ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2844     ret->total_kern_pairs = (DWORD)-1;
2845     ret->kern_pairs = NULL;
2846     list_init(&ret->hfontlist);
2847     list_init(&ret->child_fonts);
2848     return ret;
2849 }
2850 
2851 static void free_font(GdiFont *font)
2852 {
2853     struct list *cursor, *cursor2;
2854     int i;
2855 
2856     LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2857     {
2858         CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2859         struct list *first_hfont;
2860         HFONTLIST *hfontlist;
2861         list_remove(cursor);
2862         if(child->font)
2863         {
2864             first_hfont = list_head(&child->font->hfontlist);
2865             hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2866             DeleteObject(hfontlist->hfont);
2867             HeapFree(GetProcessHeap(), 0, hfontlist);
2868             free_font(child->font);
2869         }
2870         HeapFree(GetProcessHeap(), 0, child);
2871     }
2872 
2873     if (font->ft_face) pFT_Done_Face(font->ft_face);
2874     if (font->mapping) unmap_font_file( font->mapping );
2875     HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2876     HeapFree(GetProcessHeap(), 0, font->potm);
2877     HeapFree(GetProcessHeap(), 0, font->name);
2878     for (i = 0; i < font->gmsize; i++)
2879         HeapFree(GetProcessHeap(),0,font->gm[i]);
2880     HeapFree(GetProcessHeap(), 0, font->gm);
2881     HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2882     HeapFree(GetProcessHeap(), 0, font);
2883 }
2884 
2885 
2886 /*************************************************************
2887  * load_VDMX
2888  *
2889  * load the vdmx entry for the specified height
2890  */
2891 
2892 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2893           ( ( (FT_ULong)_x4 << 24 ) |     \
2894             ( (FT_ULong)_x3 << 16 ) |     \
2895             ( (FT_ULong)_x2 <<  8 ) |     \
2896               (FT_ULong)_x1         )
2897 
2898 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2899 
2900 typedef struct {
2901     BYTE bCharSet;
2902     BYTE xRatio;
2903     BYTE yStartRatio;
2904     BYTE yEndRatio;
2905 } Ratios;
2906 
2907 typedef struct {
2908     WORD recs;
2909     BYTE startsz;
2910     BYTE endsz;
2911 } VDMX_group;
2912 
2913 static LONG load_VDMX(GdiFont *font, LONG height)
2914 {
2915     WORD hdr[3], tmp;
2916     VDMX_group group;
2917     BYTE devXRatio, devYRatio;
2918     USHORT numRecs, numRatios;
2919     DWORD result, offset = -1;
2920     LONG ppem = 0;
2921     int i;
2922 
2923     result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2924 
2925     if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2926         return ppem;
2927 
2928     /* FIXME: need the real device aspect ratio */
2929     devXRatio = 1;
2930     devYRatio = 1;
2931 
2932     numRecs = GET_BE_WORD(hdr[1]);
2933     numRatios = GET_BE_WORD(hdr[2]);
2934 
2935     TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2936     for(i = 0; i < numRatios; i++) {
2937         Ratios ratio;
2938 
2939         offset = (3 * 2) + (i * sizeof(Ratios));
2940         WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2941         offset = -1;
2942 
2943         TRACE("Ratios[%d] %d  %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2944 
2945         if((ratio.xRatio == 0 &&
2946             ratio.yStartRatio == 0 &&
2947             ratio.yEndRatio == 0) ||
2948            (devXRatio == ratio.xRatio &&
2949             devYRatio >= ratio.yStartRatio &&
2950             devYRatio <= ratio.yEndRatio))
2951             {
2952                 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2953                 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2954                 offset = GET_BE_WORD(tmp);
2955                 break;
2956             }
2957     }
2958 
2959     if(offset == -1) {
2960         FIXME("No suitable ratio found\n");
2961         return ppem;
2962     }
2963 
2964     if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2965         USHORT recs;
2966         BYTE startsz, endsz;
2967         WORD *vTable;
2968 
2969         recs = GET_BE_WORD(group.recs);
2970         startsz = group.startsz;
2971         endsz = group.endsz;
2972 
2973         TRACE("recs=%d  startsz=%d  endsz=%d\n", recs, startsz, endsz);
2974 
2975         vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2976         result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2977         if(result == GDI_ERROR) {
2978             FIXME("Failed to retrieve vTable\n");
2979             goto end;
2980         }
2981 
2982         if(height > 0) {
2983             for(i = 0; i < recs; i++) {
2984                 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2985                 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2986                 ppem = GET_BE_WORD(vTable[i * 3]);
2987 
2988                 if(yMax + -yMin == height) {
2989                     font->yMax = yMax;
2990                     font->yMin = yMin;
2991                     TRACE("ppem %d found; height=%d  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
2992                     break;
2993                 }
2994                 if(yMax + -yMin > height) {
2995                     if(--i < 0) {
2996                         ppem = 0;
2997                         goto end; /* failed */
2998                     }
2999                     font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3000                     font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3001                     ppem = GET_BE_WORD(vTable[i * 3]);
3002                     TRACE("ppem %d found; height=%d  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
3003                     break;
3004                 }
3005             }
3006             if(!font->yMax) {
3007                 ppem = 0;
3008                 TRACE("ppem not found for height %d\n", height);
3009             }
3010         } else {
3011             ppem = -height;
3012             if(ppem < startsz || ppem > endsz)
3013                 goto end;
3014 
3015             for(i = 0; i < recs; i++) {
3016                 USHORT yPelHeight;
3017                 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3018 
3019                 if(yPelHeight > ppem)
3020                     break; /* failed */
3021 
3022                 if(yPelHeight == ppem) {
3023                     font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3024                     font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3025                     TRACE("ppem %d found; yMax=%d  yMin=%d\n", ppem, font->yMax, font->yMin);
3026                     break;
3027                 }
3028             }
3029         }
3030         end:
3031         HeapFree(GetProcessHeap(), 0, vTable);
3032     }
3033 
3034     return ppem;
3035 }
3036 
3037 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3038 {
3039     if(font->font_desc.hash != fd->hash) return TRUE;
3040     if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3041     if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3042     if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3043     return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3044 }
3045 
3046 static void calc_hash(FONT_DESC *pfd)
3047 {
3048     DWORD hash = 0, *ptr, two_chars;
3049     WORD *pwc;
3050     unsigned int i;
3051 
3052     for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3053         hash ^= *ptr;
3054     for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3055         hash ^= *ptr;
3056     for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3057         two_chars = *ptr;
3058         pwc = (WCHAR *)&two_chars;
3059         if(!*pwc) break;
3060         *pwc = toupperW(*pwc);
3061         pwc++;
3062         *pwc = toupperW(*pwc);
3063         hash ^= two_chars;
3064         if(!*pwc) break;
3065     }
3066     hash ^= !pfd->can_use_bitmap;
3067     pfd->hash = hash;
3068     return;
3069 }
3070 
3071 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const XFORM *pxf, BOOL can_use_bitmap)
3072 {
3073     GdiFont *ret;
3074     FONT_DESC fd;
3075     HFONTLIST *hflist;
3076     struct list *font_elem_ptr, *hfontlist_elem_ptr;
3077 
3078     fd.lf = *plf;
3079     memcpy(&fd.matrix, pxf, sizeof(FMAT2));
3080     fd.can_use_bitmap = can_use_bitmap;
3081     calc_hash(&fd);
3082 
3083     /* try the in-use list */
3084     LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3085         ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3086         if(!fontcmp(ret, &fd)) {
3087             if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3088             LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3089                 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3090                 if(hflist->hfont == hfont)
3091                     return ret;
3092             }
3093             hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3094             hflist->hfont = hfont;
3095             list_add_head(&ret->hfontlist, &hflist->entry);
3096             return ret;
3097         }
3098     }
3099  
3100     /* then the unused list */
3101     font_elem_ptr = list_head(&unused_gdi_font_list);
3102     while(font_elem_ptr) {
3103         ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3104         font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3105         if(!fontcmp(ret, &fd)) {
3106             if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3107             assert(list_empty(&ret->hfontlist));
3108             TRACE("Found %p in unused list\n", ret);
3109             list_remove(&ret->entry);
3110             list_add_head(&gdi_font_list, &ret->entry);
3111             hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3112             hflist->hfont = hfont;
3113             list_add_head(&ret->hfontlist, &hflist->entry);
3114             return ret;
3115         }
3116     }
3117     return NULL;
3118 }
3119 
3120     
3121 /*************************************************************
3122  * create_child_font_list
3123  */
3124 static BOOL create_child_font_list(GdiFont *font)
3125 {
3126     BOOL ret = FALSE;
3127     SYSTEM_LINKS *font_link;
3128     CHILD_FONT *font_link_entry, *new_child;
3129 
3130     LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3131     {
3132         if(!strcmpW(font_link->font_name, font->name))
3133         {
3134             TRACE("found entry in system list\n");
3135             LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3136             {
3137                 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3138                 new_child->face = font_link_entry->face;
3139                 new_child->font = NULL;
3140                 list_add_tail(&font->child_fonts, &new_child->entry);
3141                 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3142             }
3143             ret = TRUE;
3144             break;
3145         }
3146     }
3147     /*
3148      * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3149      * Sans Serif.  This is how asian windows get default fallbacks for fonts
3150      */
3151     if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3152         font->charset != OEM_CHARSET &&
3153         strcmpW(font->name,szDefaultFallbackLink) != 0)
3154         LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3155         {
3156             if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3157             {
3158                 TRACE("found entry in default fallback list\n");
3159                 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3160                 {
3161                     new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3162                     new_child->face = font_link_entry->face;
3163                     new_child->font = NULL;
3164                     list_add_tail(&font->child_fonts, &new_child->entry);
3165                     TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3166                 }
3167                 ret = TRUE;
3168                 break;
3169             }
3170         }
3171 
3172     return ret;
3173 }
3174 
3175 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3176 {
3177     FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3178 
3179     if (pFT_Set_Charmap)
3180     {
3181         FT_Int i;
3182         FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3183 
3184         cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3185 
3186         for (i = 0; i < ft_face->num_charmaps; i++)
3187         {
3188             if (ft_face->charmaps[i]->encoding == encoding)
3189             {
3190                 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3191                        ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3192 
3193                 switch (ft_face->charmaps[i]->platform_id)
3194                 {
3195                     default:
3196                         cmap_def = ft_face->charmaps[i];
3197                         break;
3198                     case 0: /* Apple Unicode */
3199                         cmap0 = ft_face->charmaps[i];
3200                         break;
3201                     case 1: /* Macintosh */
3202                         cmap1 = ft_face->charmaps[i];
3203                         break;
3204                     case 2: /* ISO */
3205                         cmap2 = ft_face->charmaps[i];
3206                         break;
3207                     case 3: /* Microsoft */
3208                         cmap3 = ft_face->charmaps[i];
3209                         break;
3210                 }
3211             }
3212 
3213             if (cmap3) /* prefer Microsoft cmap table */
3214                 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3215             else if (cmap1)
3216                 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3217             else if (cmap2)
3218                 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3219             else if (cmap0)
3220                 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3221             else if (cmap_def)
3222                 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3223         }
3224         return ft_err == FT_Err_Ok;
3225     }
3226 
3227     return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3228 }
3229 
3230 /*************************************************************
3231  * WineEngCreateFontInstance
3232  *
3233  */
3234 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3235 {
3236     GdiFont *ret;
3237     Face *face, *best, *best_bitmap;
3238     Family *family, *last_resort_family;
3239     struct list *family_elem_ptr, *face_elem_ptr;
3240     INT height, width = 0;
3241     unsigned int score = 0, new_score;
3242     signed int diff = 0, newdiff;
3243     BOOL bd, it, can_use_bitmap;
3244     LOGFONTW lf;
3245     CHARSETINFO csi;
3246     HFONTLIST *hflist;
3247     FontSubst *psub = NULL;
3248 
3249     EnterCriticalSection( &freetype_cs );
3250 
3251     LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3252     {
3253         struct list *first_hfont = list_head(&ret->hfontlist);
3254         hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3255         if(hflist->hfont == hfont)
3256         {
3257             LeaveCriticalSection( &freetype_cs );
3258             return ret;
3259         }
3260     }
3261 
3262     if (!GetObjectW( hfont, sizeof(lf), &lf ))
3263     {
3264         LeaveCriticalSection( &freetype_cs );
3265         return NULL;
3266     }
3267     lf.lfWidth = abs(lf.lfWidth);
3268 
3269     can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3270 
3271     TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3272           debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3273           lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3274           lf.lfEscapement);
3275 
3276     /* check the cache first */
3277     if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3278         TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3279         LeaveCriticalSection( &freetype_cs );
3280         return ret;
3281     }
3282 
3283     TRACE("not in cache\n");
3284     if(list_empty(&font_list)) /* No fonts installed */
3285     {
3286         TRACE("No fonts installed\n");
3287         LeaveCriticalSection( &freetype_cs );
3288         return NULL;
3289     }
3290     if(!have_installed_roman_font)
3291     {
3292         TRACE("No roman font installed\n");
3293         LeaveCriticalSection( &freetype_cs );
3294         return NULL;
3295     }
3296 
3297     ret = alloc_font();
3298 
3299      memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3300      ret->font_desc.lf = lf;
3301      ret->font_desc.can_use_bitmap = can_use_bitmap;
3302      calc_hash(&ret->font_desc);
3303      hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3304      hflist->hfont = hfont;
3305      list_add_head(&ret->hfontlist, &hflist->entry);
3306 
3307 
3308     /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3309        SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3310        original value lfCharSet.  Note this is a special case for
3311        Symbol and doesn't happen at least for "Wingdings*" */
3312 
3313     if(!strcmpiW(lf.lfFaceName, SymbolW))
3314         lf.lfCharSet = SYMBOL_CHARSET;
3315 
3316     if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3317         switch(lf.lfCharSet) {
3318         case DEFAULT_CHARSET:
3319             csi.fs.fsCsb[0] = 0;
3320             break;
3321         default:
3322             FIXME("Untranslated charset %d\n", lf.lfCharSet);
3323             csi.fs.fsCsb[0] = 0;
3324             break;
3325         }
3326     }
3327 
3328     family = NULL;
3329     if(lf.lfFaceName[0] != '\0') {
3330         SYSTEM_LINKS *font_link;
3331         CHILD_FONT *font_link_entry;