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