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