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