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