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