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