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->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 substitute */
2128 const char *shelldlg, *tmsrmn;
2129 } nls_update_font_list[] =
2130 {
2131 /* Latin 1 (United States) */
2132 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2133 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2134 "Tahoma","Times New Roman",
2135 },
2136 /* Latin 1 (Multilingual) */
2137 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2138 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2139 "Tahoma","Times New Roman", /* FIXME unverified */
2140 },
2141 /* Eastern Europe */
2142 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2143 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2144 "Tahoma","Times New Roman", /* FIXME unverified */
2145 },
2146 /* Cyrillic */
2147 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2148 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2149 "Tahoma","Times New Roman", /* FIXME unverified */
2150 },
2151 /* Greek */
2152 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2153 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2154 "Tahoma","Times New Roman", /* FIXME unverified */
2155 },
2156 /* Turkish */
2157 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2158 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2159 "Tahoma","Times New Roman", /* FIXME unverified */
2160 },
2161 /* Hebrew */
2162 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2163 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2164 "Tahoma","Times New Roman", /* FIXME unverified */
2165 },
2166 /* Arabic */
2167 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2168 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2169 "Tahoma","Times New Roman", /* FIXME unverified */
2170 },
2171 /* Baltic */
2172 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2173 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2174 "Tahoma","Times New Roman", /* FIXME unverified */
2175 },
2176 /* Vietnamese */
2177 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2178 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2179 "Tahoma","Times New Roman", /* FIXME unverified */
2180 },
2181 /* Thai */
2182 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2183 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2184 "Tahoma","Times New Roman", /* FIXME unverified */
2185 },
2186 /* Japanese */
2187 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2188 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2189 "MS UI Gothic","MS Serif",
2190 },
2191 /* Chinese Simplified */
2192 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2193 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2194 "Tahoma", "Times New Roman", /* FIXME unverified */
2195 },
2196 /* Korean */
2197 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2198 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2199 "Gulim", "Batang",
2200 },
2201 /* Chinese Traditional */
2202 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2203 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2204 "PMingLiU", "MingLiU",
2205 }
2206 };
2207
2208 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2209 {
2210 return ( ansi_cp == 932 /* CP932 for Japanese */
2211 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2212 || ansi_cp == 949 /* CP949 for Korean */
2213 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2214 }
2215
2216 static inline HKEY create_fonts_NT_registry_key(void)
2217 {
2218 HKEY hkey = 0;
2219
2220 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2221 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2222 return hkey;
2223 }
2224
2225 static inline HKEY create_fonts_9x_registry_key(void)
2226 {
2227 HKEY hkey = 0;
2228
2229 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2230 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2231 return hkey;
2232 }
2233
2234 static inline HKEY create_config_fonts_registry_key(void)
2235 {
2236 HKEY hkey = 0;
2237
2238 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2239 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2240 return hkey;
2241 }
2242
2243 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2244 {
2245 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2246 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2247 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2248 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2249 }
2250
2251 static void update_font_info(void)
2252 {
2253 char buf[40], cpbuf[40];
2254 DWORD len, type;
2255 HKEY hkey = 0;
2256 UINT i, ansi_cp = 0, oem_cp = 0;
2257
2258 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2259 return;
2260
2261 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2262 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2263 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2264 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2265 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2266
2267 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2268 if (is_dbcs_ansi_cp(ansi_cp))
2269 use_default_fallback = TRUE;
2270
2271 len = sizeof(buf);
2272 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2273 {
2274 if (!strcmp( buf, cpbuf )) /* already set correctly */
2275 {
2276 RegCloseKey(hkey);
2277 return;
2278 }
2279 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2280 }
2281 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2282
2283 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2284 RegCloseKey(hkey);
2285
2286 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2287 {
2288 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2289 nls_update_font_list[i].oem_cp == oem_cp)
2290 {
2291 HKEY hkey;
2292
2293 hkey = create_config_fonts_registry_key();
2294 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2295 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2296 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2297 RegCloseKey(hkey);
2298
2299 hkey = create_fonts_NT_registry_key();
2300 add_font_list(hkey, &nls_update_font_list[i]);
2301 RegCloseKey(hkey);
2302
2303 hkey = create_fonts_9x_registry_key();
2304 add_font_list(hkey, &nls_update_font_list[i]);
2305 RegCloseKey(hkey);
2306
2307 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2308 {
2309 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2310 strlen(nls_update_font_list[i].shelldlg)+1);
2311 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2312 strlen(nls_update_font_list[i].tmsrmn)+1);
2313 RegCloseKey(hkey);
2314 }
2315 return;
2316 }
2317 }
2318 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2319 }
2320
2321
2322 static BOOL init_freetype(void)
2323 {
2324 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2325 if(!ft_handle) {
2326 WINE_MESSAGE(
2327 "Wine cannot find the FreeType font library. To enable Wine to\n"
2328 "use TrueType fonts please install a version of FreeType greater than\n"
2329 "or equal to 2.0.5.\n"
2330 "http://www.freetype.org\n");
2331 return FALSE;
2332 }
2333
2334 #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;}
2335
2336 LOAD_FUNCPTR(FT_Vector_Unit)
2337 LOAD_FUNCPTR(FT_Done_Face)
2338 LOAD_FUNCPTR(FT_Get_Char_Index)
2339 LOAD_FUNCPTR(FT_Get_Module)
2340 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2341 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2342 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2343 LOAD_FUNCPTR(FT_Init_FreeType)
2344 LOAD_FUNCPTR(FT_Load_Glyph)
2345 LOAD_FUNCPTR(FT_Matrix_Multiply)
2346 LOAD_FUNCPTR(FT_MulFix)
2347 LOAD_FUNCPTR(FT_New_Face)
2348 LOAD_FUNCPTR(FT_New_Memory_Face)
2349 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2350 LOAD_FUNCPTR(FT_Outline_Transform)
2351 LOAD_FUNCPTR(FT_Outline_Translate)
2352 LOAD_FUNCPTR(FT_Select_Charmap)
2353 LOAD_FUNCPTR(FT_Set_Charmap)
2354 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2355 LOAD_FUNCPTR(FT_Vector_Transform)
2356
2357 #undef LOAD_FUNCPTR
2358 /* Don't warn if these ones are missing */
2359 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2360 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2361 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2362 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2363 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2364 #ifdef HAVE_FREETYPE_FTWINFNT_H
2365 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2366 #endif
2367 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2368 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2369 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2370 <= 2.0.3 has FT_Sqrt64 */
2371 goto sym_not_found;
2372 }
2373
2374 if(pFT_Init_FreeType(&library) != 0) {
2375 ERR("Can't init FreeType library\n");
2376 wine_dlclose(ft_handle, NULL, 0);
2377 ft_handle = NULL;
2378 return FALSE;
2379 }
2380 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2381 if (pFT_Library_Version)
2382 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2383
2384 if (FT_Version.major<=0)
2385 {
2386 FT_Version.major=2;
2387 FT_Version.minor=0;
2388 FT_Version.patch=5;
2389 }
2390 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2391 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2392 ((FT_Version.minor << 8) & 0x00ff00) |
2393 ((FT_Version.patch ) & 0x0000ff);
2394
2395 return TRUE;
2396
2397 sym_not_found:
2398 WINE_MESSAGE(
2399 "Wine cannot find certain functions that it needs inside the FreeType\n"
2400 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2401 "FreeType to at least version 2.0.5.\n"
2402 "http://www.freetype.org\n");
2403 wine_dlclose(ft_handle, NULL, 0);
2404 ft_handle = NULL;
2405 return FALSE;
2406 }
2407
2408 /*************************************************************
2409 * WineEngInit
2410 *
2411 * Initialize FreeType library and create a list of available faces
2412 */
2413 BOOL WineEngInit(void)
2414 {
2415 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2416 static const WCHAR pathW[] = {'P','a','t','h',0};
2417 HKEY hkey;
2418 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2419 LPVOID data;
2420 WCHAR windowsdir[MAX_PATH];
2421 char *unixname;
2422 HANDLE font_mutex;
2423 const char *data_dir;
2424
2425 TRACE("\n");
2426
2427 /* update locale dependent font info in registry */
2428 update_font_info();
2429
2430 if(!init_freetype()) return FALSE;
2431
2432 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2433 ERR("Failed to create font mutex\n");
2434 return FALSE;
2435 }
2436 WaitForSingleObject(font_mutex, INFINITE);
2437
2438 delete_external_font_keys();
2439
2440 /* load the system bitmap fonts */
2441 load_system_fonts();
2442
2443 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2444 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2445 strcatW(windowsdir, fontsW);
2446 if((unixname = wine_get_unix_file_name(windowsdir)))
2447 {
2448 ReadFontDir(unixname, FALSE);
2449 HeapFree(GetProcessHeap(), 0, unixname);
2450 }
2451
2452 /* load the system truetype fonts */
2453 data_dir = wine_get_data_dir();
2454 if (!data_dir) data_dir = wine_get_build_dir();
2455 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2456 strcpy(unixname, data_dir);
2457 strcat(unixname, "/fonts/");
2458 ReadFontDir(unixname, TRUE);
2459 HeapFree(GetProcessHeap(), 0, unixname);
2460 }
2461
2462 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2463 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2464 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2465 will skip these. */
2466 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2467 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2468 &hkey) == ERROR_SUCCESS) {
2469 LPWSTR valueW;
2470 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2471 &valuelen, &datalen, NULL, NULL);
2472
2473 valuelen++; /* returned value doesn't include room for '\0' */
2474 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2475 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2476 if (valueW && data)
2477 {
2478 dlen = datalen * sizeof(WCHAR);
2479 vlen = valuelen;
2480 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2481 &dlen) == ERROR_SUCCESS) {
2482 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2483 {
2484 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2485 {
2486 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2487 HeapFree(GetProcessHeap(), 0, unixname);
2488 }
2489 }
2490 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2491 {
2492 WCHAR pathW[MAX_PATH];
2493 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2494 BOOL added = FALSE;
2495
2496 sprintfW(pathW, fmtW, windowsdir, data);
2497 if((unixname = wine_get_unix_file_name(pathW)))
2498 {
2499 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2500 HeapFree(GetProcessHeap(), 0, unixname);
2501 }
2502 if (!added)
2503 load_font_from_data_dir(data);
2504 }
2505 /* reset dlen and vlen */
2506 dlen = datalen;
2507 vlen = valuelen;
2508 }
2509 }
2510 HeapFree(GetProcessHeap(), 0, data);
2511 HeapFree(GetProcessHeap(), 0, valueW);
2512 RegCloseKey(hkey);
2513 }
2514
2515 load_fontconfig_fonts();
2516
2517 /* then look in any directories that we've specified in the config file */
2518 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2519 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2520 {
2521 DWORD len;
2522 LPWSTR valueW;
2523 LPSTR valueA, ptr;
2524
2525 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2526 {
2527 len += sizeof(WCHAR);
2528 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2529 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2530 {
2531 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2532 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2533 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2534 TRACE( "got font path %s\n", debugstr_a(valueA) );
2535 ptr = valueA;
2536 while (ptr)
2537 {
2538 LPSTR next = strchr( ptr, ':' );
2539 if (next) *next++ = 0;
2540 ReadFontDir( ptr, TRUE );
2541 ptr = next;
2542 }
2543 HeapFree( GetProcessHeap(), 0, valueA );
2544 }
2545 HeapFree( GetProcessHeap(), 0, valueW );
2546 }
2547 RegCloseKey(hkey);
2548 }
2549
2550 DumpFontList();
2551 LoadSubstList();
2552 DumpSubstList();
2553 LoadReplaceList();
2554 update_reg_entries();
2555
2556 init_system_links();
2557
2558 ReleaseMutex(font_mutex);
2559 return TRUE;
2560 }
2561
2562
2563 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2564 {
2565 TT_OS2 *pOS2;
2566 TT_HoriHeader *pHori;
2567
2568 LONG ppem;
2569
2570 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2571 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2572
2573 if(height == 0) height = 16;
2574
2575 /* Calc. height of EM square:
2576 *
2577 * For +ve lfHeight we have
2578 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2579 * Re-arranging gives:
2580 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2581 *
2582 * For -ve lfHeight we have
2583 * |lfHeight| = ppem
2584 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2585 * with il = winAscent + winDescent - units_per_em]
2586 *
2587 */
2588
2589 if(height > 0) {
2590 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2591 ppem = ft_face->units_per_EM * height /
2592 (pHori->Ascender - pHori->Descender);
2593 else
2594 ppem = ft_face->units_per_EM * height /
2595 (pOS2->usWinAscent + pOS2->usWinDescent);
2596 }
2597 else
2598 ppem = -height;
2599
2600 return ppem;
2601 }
2602
2603 static struct font_mapping *map_font_file( const char *name )
2604 {
2605 struct font_mapping *mapping;
2606 struct stat st;
2607 int fd;
2608
2609 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2610 if (fstat( fd, &st ) == -1) goto error;
2611
2612 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2613 {
2614 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2615 {
2616 mapping->refcount++;
2617 close( fd );
2618 return mapping;
2619 }
2620 }
2621 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2622 goto error;
2623
2624 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2625 close( fd );
2626
2627 if (mapping->data == MAP_FAILED)
2628 {
2629 HeapFree( GetProcessHeap(), 0, mapping );
2630 return NULL;
2631 }
2632 mapping->refcount = 1;
2633 mapping->dev = st.st_dev;
2634 mapping->ino = st.st_ino;
2635 mapping->size = st.st_size;
2636 list_add_tail( &mappings_list, &mapping->entry );
2637 return mapping;
2638
2639 error:
2640 close( fd );
2641 return NULL;
2642 }
2643
2644 static void unmap_font_file( struct font_mapping *mapping )
2645 {
2646 if (!--mapping->refcount)
2647 {
2648 list_remove( &mapping->entry );
2649 munmap( mapping->data, mapping->size );
2650 HeapFree( GetProcessHeap(), 0, mapping );
2651 }
2652 }
2653
2654 static LONG load_VDMX(GdiFont*, LONG);
2655
2656 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2657 {
2658 FT_Error err;
2659 FT_Face ft_face;
2660 void *data_ptr;
2661 DWORD data_size;
2662
2663 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2664
2665 if (face->file)
2666 {
2667 if (!(font->mapping = map_font_file( face->file )))
2668 {
2669 WARN("failed to map %s\n", debugstr_a(face->file));
2670 return 0;
2671 }
2672 data_ptr = font->mapping->data;
2673 data_size = font->mapping->size;
2674 }
2675 else
2676 {
2677 data_ptr = face->font_data_ptr;
2678 data_size = face->font_data_size;
2679 }
2680
2681 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2682 if(err) {
2683 ERR("FT_New_Face rets %d\n", err);
2684 return 0;
2685 }
2686
2687 /* set it here, as load_VDMX needs it */
2688 font->ft_face = ft_face;
2689
2690 if(FT_IS_SCALABLE(ft_face)) {
2691 /* load the VDMX table if we have one */
2692 font->ppem = load_VDMX(font, height);
2693 if(font->ppem == 0)
2694 font->ppem = calc_ppem_for_height(ft_face, height);
2695
2696 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2697 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2698 } else {
2699 font->ppem = height;
2700 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2701 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2702 }
2703 return ft_face;
2704 }
2705
2706
2707 static int get_nearest_charset(Face *face, int *cp)
2708 {
2709 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2710 a single face with the requested charset. The idea is to check if
2711 the selected font supports the current ANSI codepage, if it does
2712 return the corresponding charset, else return the first charset */
2713
2714 CHARSETINFO csi;
2715 int acp = GetACP(), i;
2716 DWORD fs0;
2717
2718 *cp = acp;
2719 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2720 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2721 return csi.ciCharset;
2722
2723 for(i = 0; i < 32; i++) {
2724 fs0 = 1L << i;
2725 if(face->fs.fsCsb[0] & fs0) {
2726 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2727 *cp = csi.ciACP;
2728 return csi.ciCharset;
2729 }
2730 else
2731 FIXME("TCI failing on %x\n", fs0);
2732 }
2733 }
2734
2735 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2736 face->fs.fsCsb[0], face->file);
2737 *cp = acp;
2738 return DEFAULT_CHARSET;
2739 }
2740
2741 static GdiFont *alloc_font(void)
2742 {
2743 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2744 ret->gmsize = 1;
2745 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2746 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2747 ret->potm = NULL;
2748 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2749 ret->total_kern_pairs = (DWORD)-1;
2750 ret->kern_pairs = NULL;
2751 list_init(&ret->hfontlist);
2752 list_init(&ret->child_fonts);
2753 return ret;
2754 }
2755
2756 static void free_font(GdiFont *font)
2757 {
2758 struct list *cursor, *cursor2;
2759 int i;
2760
2761 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2762 {
2763 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2764 struct list *first_hfont;
2765 HFONTLIST *hfontlist;
2766 list_remove(cursor);
2767 if(child->font)
2768 {
2769 first_hfont = list_head(&child->font->hfontlist);
2770 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2771 DeleteObject(hfontlist->hfont);
2772 HeapFree(GetProcessHeap(), 0, hfontlist);
2773 free_font(child->font);
2774 }
2775 HeapFree(GetProcessHeap(), 0, child);
2776 }
2777
2778 if (font->ft_face) pFT_Done_Face(font->ft_face);
2779 if (font->mapping) unmap_font_file( font->mapping );
2780 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2781 HeapFree(GetProcessHeap(), 0, font->potm);
2782 HeapFree(GetProcessHeap(), 0, font->name);
2783 for (i = 0; i < font->gmsize; i++)
2784 HeapFree(GetProcessHeap(),0,font->gm[i]);
2785 HeapFree(GetProcessHeap(), 0, font->gm);
2786 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2787 HeapFree(GetProcessHeap(), 0, font);
2788 }
2789
2790
2791 /*************************************************************
2792 * load_VDMX
2793 *
2794 * load the vdmx entry for the specified height
2795 */
2796
2797 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2798 ( ( (FT_ULong)_x4 << 24 ) | \
2799 ( (FT_ULong)_x3 << 16 ) | \
2800 ( (FT_ULong)_x2 << 8 ) | \
2801 (FT_ULong)_x1 )
2802
2803 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2804
2805 typedef struct {
2806 BYTE bCharSet;
2807 BYTE xRatio;
2808 BYTE yStartRatio;
2809 BYTE yEndRatio;
2810 } Ratios;
2811
2812 typedef struct {
2813 WORD recs;
2814 BYTE startsz;
2815 BYTE endsz;
2816 } VDMX_group;
2817
2818 static LONG load_VDMX(GdiFont *font, LONG height)
2819 {
2820 WORD hdr[3], tmp;
2821 VDMX_group group;
2822 BYTE devXRatio, devYRatio;
2823 USHORT numRecs, numRatios;
2824 DWORD result, offset = -1;
2825 LONG ppem = 0;
2826 int i;
2827
2828 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2829
2830 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2831 return ppem;
2832
2833 /* FIXME: need the real device aspect ratio */
2834 devXRatio = 1;
2835 devYRatio = 1;
2836
2837 numRecs = GET_BE_WORD(hdr[1]);
2838 numRatios = GET_BE_WORD(hdr[2]);
2839
2840 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2841 for(i = 0; i < numRatios; i++) {
2842 Ratios ratio;
2843
2844 offset = (3 * 2) + (i * sizeof(Ratios));
2845 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2846 offset = -1;
2847
2848 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2849
2850 if((ratio.xRatio == 0 &&
2851 ratio.yStartRatio == 0 &&
2852 ratio.yEndRatio == 0) ||
2853 (devXRatio == ratio.xRatio &&
2854 devYRatio >= ratio.yStartRatio &&
2855 devYRatio <= ratio.yEndRatio))
2856 {
2857 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2858 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2859 offset = GET_BE_WORD(tmp);
2860 break;
2861 }
2862 }
2863
2864 if(offset == -1) {
2865 FIXME("No suitable ratio found\n");
2866 return ppem;
2867 }
2868
2869 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2870 USHORT recs;
2871 BYTE startsz, endsz;
2872 WORD *vTable;
2873
2874 recs = GET_BE_WORD(group.recs);
2875 startsz = group.startsz;
2876 endsz = group.endsz;
2877
2878 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2879
2880 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2881 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2882 if(result == GDI_ERROR) {
2883 FIXME("Failed to retrieve vTable\n");
2884 goto end;
2885 }
2886
2887 if(height > 0) {
2888 for(i = 0; i < recs; i++) {
2889 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2890 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2891 ppem = GET_BE_WORD(vTable[i * 3]);
2892
2893 if(yMax + -yMin == height) {
2894 font->yMax = yMax;
2895 font->yMin = yMin;
2896 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2897 break;
2898 }
2899 if(yMax + -yMin > height) {
2900 if(--i < 0) {
2901 ppem = 0;
2902 goto end; /* failed */
2903 }
2904 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2905 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2906 ppem = GET_BE_WORD(vTable[i * 3]);
2907 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2908 break;
2909 }
2910 }
2911 if(!font->yMax) {
2912 ppem = 0;
2913 TRACE("ppem not found for height %d\n", height);
2914 }
2915 } else {
2916 ppem = -height;
2917 if(ppem < startsz || ppem > endsz)
2918 goto end;
2919
2920 for(i = 0; i < recs; i++) {
2921 USHORT yPelHeight;
2922 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2923
2924 if(yPelHeight > ppem)
2925 break; /* failed */
2926
2927 if(yPelHeight == ppem) {
2928 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2929 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2930 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2931 break;
2932 }
2933 }
2934 }
2935 end:
2936 HeapFree(GetProcessHeap(), 0, vTable);
2937 }
2938
2939 return ppem;
2940 }
2941
2942 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
2943 {
2944 if(font->font_desc.hash != fd->hash) return TRUE;
2945 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2946 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2947 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2948 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2949 }
2950
2951 static void calc_hash(FONT_DESC *pfd)
2952 {
2953 DWORD hash = 0, *ptr, two_chars;
2954 WORD *pwc;
2955 unsigned int i;
2956
2957 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2958 hash ^= *ptr;
2959 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2960 hash ^= *ptr;
2961 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2962 two_chars = *ptr;
2963 pwc = (WCHAR *)&two_chars;
2964 if(!*pwc) break;
2965 *pwc = toupperW(*pwc);
2966 pwc++;
2967 *pwc = toupperW(*pwc);
2968 hash ^= two_chars;
2969 if(!*pwc) break;
2970 }
2971 hash ^= !pfd->can_use_bitmap;
2972 pfd->hash = hash;
2973 return;
2974 }
2975
2976 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const XFORM *pxf, BOOL can_use_bitmap)
2977 {
2978 GdiFont *ret;
2979 FONT_DESC fd;
2980 HFONTLIST *hflist;
2981 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2982
2983 fd.lf = *plf;
2984 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2985 fd.can_use_bitmap = can_use_bitmap;
2986 calc_hash(&fd);
2987
2988 /* try the in-use list */
2989 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2990 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2991 if(!fontcmp(ret, &fd)) {
2992 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2993 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2994 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2995 if(hflist->hfont == hfont)
2996 return ret;
2997 }
2998 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2999 hflist->hfont = hfont;
3000 list_add_head(&ret->hfontlist, &hflist->entry);
3001 return ret;
3002 }
3003 }
3004
3005 /* then the unused list */
3006 font_elem_ptr = list_head(&unused_gdi_font_list);
3007 while(font_elem_ptr) {
3008 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3009 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3010 if(!fontcmp(ret, &fd)) {
3011 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3012 assert(list_empty(&ret->hfontlist));
3013 TRACE("Found %p in unused list\n", ret);
3014 list_remove(&ret->entry);
3015 list_add_head(&gdi_font_list, &ret->entry);
3016 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3017 hflist->hfont = hfont;
3018 list_add_head(&ret->hfontlist, &hflist->entry);
3019 return ret;
3020 }
3021 }
3022 return NULL;
3023 }
3024
3025
3026 /*************************************************************
3027 * create_child_font_list
3028 */
3029 static BOOL create_child_font_list(GdiFont *font)
3030 {
3031 BOOL ret = FALSE;
3032 SYSTEM_LINKS *font_link;
3033 CHILD_FONT *font_link_entry, *new_child;
3034
3035 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3036 {
3037 if(!strcmpW(font_link->font_name, font->name))
3038 {
3039 TRACE("found entry in system list\n");
3040 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3041 {
3042 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3043 new_child->face = font_link_entry->face;
3044 new_child->font = NULL;
3045 list_add_tail(&font->child_fonts, &new_child->entry);
3046 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3047 }
3048 ret = TRUE;
3049 break;
3050 }
3051 }
3052 /*
3053 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3054 * Sans Serif. This is how asian windows get default fallbacks for fonts
3055 */
3056 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3057 font->charset != OEM_CHARSET &&
3058 strcmpW(font->name,szDefaultFallbackLink) != 0)
3059 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3060 {
3061 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3062 {
3063 TRACE("found entry in default fallback list\n");
3064 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3065 {
3066 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3067 new_child->face = font_link_entry->face;
3068 new_child->font = NULL;
3069 list_add_tail(&font->child_fonts, &new_child->entry);
3070 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3071 }
3072 ret = TRUE;
3073 break;
3074 }
3075 }
3076
3077 return ret;
3078 }
3079
3080 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3081 {
3082 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3083
3084 if (pFT_Set_Charmap)
3085 {
3086 FT_Int i;
3087 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3088
3089 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3090
3091 for (i = 0; i < ft_face->num_charmaps; i++)
3092 {
3093 if (ft_face->charmaps[i]->encoding == encoding)
3094 {
3095 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3096 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3097
3098 switch (ft_face->charmaps[i]->platform_id)
3099 {
3100 default:
3101 cmap_def = ft_face->charmaps[i];
3102 break;
3103 case 0: /* Apple Unicode */
3104 cmap0 = ft_face->charmaps[i];
3105 break;
3106 case 1: /* Macintosh */
3107 cmap1 = ft_face->charmaps[i];
3108 break;
3109 case 2: /* ISO */
3110 cmap2 = ft_face->charmaps[i];
3111 break;
3112 case 3: /* Microsoft */
3113 cmap3 = ft_face->charmaps[i];
3114 break;
3115 }
3116 }
3117
3118 if (cmap3) /* prefer Microsoft cmap table */
3119 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3120 else if (cmap1)
3121 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3122 else if (cmap2)
3123 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3124 else if (cmap0)
3125 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3126 else if (cmap_def)
3127 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3128 }
3129 return ft_err == FT_Err_Ok;
3130 }
3131
3132 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3133 }
3134
3135 /*************************************************************
3136 * WineEngCreateFontInstance
3137 *
3138 */
3139 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3140 {
3141 GdiFont *ret;
3142 Face *face, *best, *best_bitmap;
3143 Family *family, *last_resort_family;
3144 struct list *family_elem_ptr, *face_elem_ptr;
3145 INT height, width = 0;
3146 unsigned int score = 0, new_score;
3147 signed int diff = 0, newdiff;
3148 BOOL bd, it, can_use_bitmap;
3149 LOGFONTW lf;
3150 CHARSETINFO csi;
3151 HFONTLIST *hflist;
3152
3153 EnterCriticalSection( &freetype_cs );
3154
3155 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
3156 {
3157 struct list *first_hfont = list_head(&ret->hfontlist);
3158 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3159 if(hflist->hfont == hfont)
3160 {
3161 LeaveCriticalSection( &freetype_cs );
3162 return ret;
3163 }
3164 }
3165
3166 if (!GetObjectW( hfont, sizeof(lf), &lf ))
3167 {
3168 LeaveCriticalSection( &freetype_cs );
3169 return NULL;
3170 }
3171 lf.lfWidth = abs(lf.lfWidth);
3172
3173 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3174
3175 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3176 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3177 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3178 lf.lfEscapement);
3179
3180 /* check the cache first */
3181 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
3182 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3183 LeaveCriticalSection( &freetype_cs );
3184 return ret;
3185 }
3186
3187 TRACE("not in cache\n");
3188 if(list_empty(&font_list)) /* No fonts installed */
3189 {
3190 TRACE("No fonts installed\n");
3191 LeaveCriticalSection( &freetype_cs );
3192 return NULL;
3193 }
3194 if(!have_installed_roman_font)
3195 {
3196 TRACE("No roman font installed\n");
3197 LeaveCriticalSection( &freetype_cs );
3198 return NULL;
3199 }
3200
3201 ret = alloc_font();
3202
3203 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
3204 ret->font_desc.lf = lf;
3205 ret->font_desc.can_use_bitmap = can_use_bitmap;
3206 calc_hash(&ret->font_desc);
3207 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3208 hflist->hfont = hfont;
3209 list_add_head(&ret->hfontlist, &hflist->entry);
3210
3211
3212 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3213 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3214 original value lfCharSet. Note this is a special case for
3215 Symbol and doesn't happen at least for "Wingdings*" */
3216
3217 if(!strcmpiW(lf.lfFaceName, SymbolW))
3218 lf.lfCharSet = SYMBOL_CHARSET;
3219
3220 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3221 switch(lf.lfCharSet) {
3222 case DEFAULT_CHARSET:
3223 csi.fs.fsCsb[0] = 0;
3224 break;
3225 default:
3226 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3227 csi.fs.fsCsb[0] = 0;
3228 break;
3229 }
3230 }
3231
3232 family = NULL;
3233 if(lf.lfFaceName[0] != '\0') {
3234 FontSubst *psub;
3235 SYSTEM_LINKS *font_link;
3236 CHILD_FONT *font_link_entry;
3237 LPWSTR FaceName = lf.lfFaceName;
3238
3239 /*
3240 * Check for a leading '@' this signals that the font is being
3241 * requested in tategaki mode (vertical writing substitution) but
3242 * does not affect the fontface that is to be selected.
3243 */
3244 if (lf.lfFaceName[0]=='@')
3245 FaceName = &lf.lfFaceName[1];
3246
3247 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3248
3249 if(psub) {
3250 TRACE("substituting %s -> %s\n", debugstr_w(FaceName),
3251 debugstr_w(psub->to.name));
3252 strcpyW(FaceName, psub->to.name);
3253 }
3254
3255 /* We want a match on name and charset or just name if
3256 charset was DEFAULT_CHARSET. If the latter then
3257 we fixup the returned charset later in get_nearest_charset
3258 where we'll either use the charset of the current ansi codepage
3259 or if that's unavailable the first charset that the font supports.
3260 */
3261 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3262 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3263 if(!strcmpiW(family->FamilyName, FaceName)) {
3264 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3265 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3266 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3267 if(face->scalable || can_use_bitmap)
3268 goto found;
3269 }
3270 }
3271 }
3272
3273 /*
3274 * Try check the SystemLink list first for a replacement font.
3275 * We may find good replacements there.
3276 */
3277 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3278 {
3279 if(!strcmpiW(font_link->font_name, FaceName))
3280 {
3281 TRACE("found entry in system list\n");
3282 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3283 {
3284 face = font_link_entry->face;
3285 family = face->family;
3286 if(csi.fs.fsCsb[0] &
3287 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3288 {
3289 if(face->scalable || can_use_bitmap)
3290 goto found;
3291 }
3292 }
3293 }
3294 }
3295 }
3296
3297 /* If requested charset was DEFAULT_CHARSET then try using charset
3298 corresponding to the current ansi codepage */
3299 if (!csi.fs.fsCsb[0] || lf.lfWeight == FW_DONTCARE)
3300 {
3301 INT acp = GetACP();
3302 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3303 FIXME("TCI failed on codepage %d\n", acp);
3304 csi.fs.fsCsb[0] = 0;
3305 } else
3306 lf.lfCharSet = csi.ciCharset;
3307 }
3308
3309 /* Face families are in the top 4 bits of lfPitchAndFamily,
3310 so mask with 0xF0 before testing */
3311
3312 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3313 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3314 strcpyW(lf.lfFaceName, defFixed);
3315 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3316 strcpyW(lf.lfFaceName, defSerif);
3317 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3318 strcpyW(lf.lfFaceName, defSans);
3319 else
3320 strcpyW(lf.lfFaceName, defSans);
3321 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3322 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3323 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3324 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3325 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3326 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3327 if(face->scalable || can_use_bitmap)
3328 goto found;
3329 }
3330 }
3331 }
3332
3333 last_resort_family = NULL;
3334 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3335 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3336 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3337 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3338 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3339 if(face->scalable)
3340 goto found;
3341 if(can_use_bitmap && !last_resort_family)
3342 last_resort_family = family;
3343 }
3344 }
3345 }
3346
3347 if(last_resort_family) {
3348 family = last_resort_family;
3349 csi.fs.fsCsb[0] = 0;
3350 goto found;
3351 }
3352
3353 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3354 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3355 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3356 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3357 if(face->scalable) {
3358 csi.fs.fsCsb[0] = 0;
3359 WARN("just using first face for now\n");
3360 goto found;
3361 }
3362 if(can_use_bitmap && !last_resort_family)
3363 last_resort_family = family;
3364 }
3365 }
3366 if(!last_resort_family) {
3367 FIXME("can't find a single appropriate font - bailing\n");
3368 free_font(ret);
3369 LeaveCriticalSection( &freetype_cs );
3370 return NULL;
3371 }
3372
3373 WARN("could only find a bitmap font - this will probably look awful!\n");
3374 family = last_resort_family;
3375 csi.fs.fsCsb[0] = 0;
3376
3377 found:
3378 it = lf.lfItalic ? 1 : 0;
3379 bd = lf.lfWeight > 550 ? 1 : 0;
3380
3381 height = GDI_ROUND( (double)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3382 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3383
3384 face = best = best_bitmap = NULL;
3385 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3386 {
3387 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3388 {
3389 BOOL italic, bold;
3390
3391 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3392 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3393 new_score = (italic ^ it) + (bold ^ bd);
3394 if(!best || new_score <= score)
3395 {
3396 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3397 italic, bold, it, bd);
3398 score = new_score;
3399 best = face;
3400 if(best->scalable && score == 0) break;
3401 if(!best->scalable)
3402 {
3403 if(height > 0)
3404 newdiff = height - (signed int)(best->size.height);
3405 else
3406 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3407 if(!best_bitmap || new_score < score ||
3408 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3409 {
3410 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3411 diff = newdiff;
3412 best_bitmap = best;
3413 if(score == 0 && diff == 0) break;
3414 }
3415 }
3416 }
3417 }
3418 }
3419 if(best)
3420 face = best->scalable ? best : best_bitmap;
3421 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3422 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3423
3424 ret->fs = face->fs;
3425
3426 if(csi.fs.fsCsb[0]) {
3427 ret->charset = lf.lfCharSet;
3428 ret->codepage = csi.ciACP;
3429 }
3430 else
3431 ret->charset = get_nearest_charset(face, &ret->codepage);
3432
3433 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3434 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3435
3436 ret->aveWidth = height ? lf.lfWidth : 0;
3437
3438 if(!face->scalable) {
3439 /* Windows uses integer scaling factors for bitmap fonts */
3440 INT scale, scaled_height;
3441
3442 if (height != 0) height = diff;
3443 height += face->size.height;
3444
3445 scale = (height + face->size.height - 1) / face->size.height;
3446 scaled_height = scale * face->size.height;
3447 /* XP allows not more than 10% deviation */
3448 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3449 ret->scale_y = scale;
3450
3451 width = face->size.x_ppem >> 6;
3452 height = face->size.y_ppem >> 6;
3453 }
3454 else
3455 ret->scale_y = 1.0;
3456 TRACE("font scale y: %f\n", ret->scale_y);
3457
3458 ret->ft_face = OpenFontFace(ret, face, width, height);
3459
3460 if (!ret->ft_face)
3461 {
3462 free_font( ret );
3463 LeaveCriticalSection( &freetype_cs );
3464 return 0;
3465 }
3466
3467 ret->ntmFlags = face->ntmFlags;
3468
3469 if (ret->charset ==