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