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
1030 /*****************************************************************
1031 * get_name_table_entry
1032 *
1033 * Supply the platform, encoding, language and name ids in req
1034 * and if the name exists the function will fill in the string
1035 * and string_len members. The string is owned by FreeType so
1036 * don't free it. Returns TRUE if the name is found else FALSE.
1037 */
1038 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1039 {
1040 FT_SfntName name;
1041 FT_UInt num_names, name_index;
1042
1043 if(FT_IS_SFNT(ft_face))
1044 {
1045 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1046
1047 for(name_index = 0; name_index < num_names; name_index++)
1048 {
1049 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1050 {
1051 if((name.platform_id == req->platform_id) &&
1052 (name.encoding_id == req->encoding_id) &&
1053 (name.language_id == req->language_id) &&
1054 (name.name_id == req->name_id))
1055 {
1056 req->string = name.string;
1057 req->string_len = name.string_len;
1058 return TRUE;
1059 }
1060 }
1061 }
1062 }
1063 req->string = NULL;
1064 req->string_len = 0;
1065 return FALSE;
1066 }
1067
1068 static WCHAR *get_familyname(FT_Face ft_face)
1069 {
1070 WCHAR *family = NULL;
1071 FT_SfntName name;
1072
1073 name.platform_id = TT_PLATFORM_MICROSOFT;
1074 name.encoding_id = TT_MS_ID_UNICODE_CS;
1075 name.language_id = GetUserDefaultLCID();
1076 name.name_id = TT_NAME_ID_FONT_FAMILY;
1077
1078 if(get_name_table_entry(ft_face, &name))
1079 {
1080 int i;
1081
1082 /* String is not nul terminated and string_len is a byte length. */
1083 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1084 for(i = 0; i < name.string_len / 2; i++)
1085 {
1086 WORD *tmp = (WORD *)&name.string[i * 2];
1087 family[i] = GET_BE_WORD(*tmp);
1088 }
1089 family[i] = 0;
1090 TRACE("Got localised name %s\n", debugstr_w(family));
1091 }
1092
1093 return family;
1094 }
1095
1096
1097 /*****************************************************************
1098 * load_sfnt_table
1099 *
1100 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1101 * of FreeType that don't export this function.
1102 *
1103 */
1104 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1105 {
1106
1107 FT_Error err;
1108
1109 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1110 if(pFT_Load_Sfnt_Table)
1111 {
1112 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1113 }
1114 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1115 else /* Do it the hard way */
1116 {
1117 TT_Face tt_face = (TT_Face) ft_face;
1118 SFNT_Interface *sfnt;
1119 if (FT_Version.major==2 && FT_Version.minor==0)
1120 {
1121 /* 2.0.x */
1122 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1123 }
1124 else
1125 {
1126 /* A field was added in the middle of the structure in 2.1.x */
1127 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1128 }
1129 err = sfnt->load_any(tt_face, table, offset, buf, len);
1130 }
1131 #else
1132 else
1133 {
1134 static int msg;
1135 if(!msg)
1136 {
1137 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1138 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1139 "Please upgrade your freetype library.\n");
1140 msg++;
1141 }
1142 err = FT_Err_Unimplemented_Feature;
1143 }
1144 #endif
1145 return err;
1146 }
1147
1148 static inline int TestStyles(DWORD flags, DWORD styles)
1149 {
1150 return (flags & styles) == styles;
1151 }
1152
1153 static int StyleOrdering(Face *face)
1154 {
1155 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1156 return 3;
1157 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1158 return 2;
1159 if (TestStyles(face->ntmFlags, NTM_BOLD))
1160 return 1;
1161 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1162 return 0;
1163
1164 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1165 debugstr_w(face->family->FamilyName),
1166 debugstr_w(face->StyleName),
1167 face->ntmFlags);
1168
1169 return 9999;
1170 }
1171
1172 /* Add a style of face to a font family using an ordering of the list such
1173 that regular fonts come before bold and italic, and single styles come
1174 before compound styles. */
1175 static void AddFaceToFamily(Face *face, Family *family)
1176 {
1177 struct list *entry;
1178
1179 LIST_FOR_EACH( entry, &family->faces )
1180 {
1181 Face *ent = LIST_ENTRY(entry, Face, entry);
1182 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1183 }
1184 list_add_before( entry, &face->entry );
1185 }
1186
1187 #define ADDFONT_EXTERNAL_FONT 0x01
1188 #define ADDFONT_FORCE_BITMAP 0x02
1189 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1190 {
1191 FT_Face ft_face;
1192 TT_OS2 *pOS2;
1193 TT_Header *pHeader = NULL;
1194 WCHAR *english_family, *localised_family, *StyleW;
1195 DWORD len;
1196 Family *family;
1197 Face *face;
1198 struct list *family_elem_ptr, *face_elem_ptr;
1199 FT_Error err;
1200 FT_Long face_index = 0, num_faces;
1201 #ifdef HAVE_FREETYPE_FTWINFNT_H
1202 FT_WinFNT_HeaderRec winfnt_header;
1203 #endif
1204 int i, bitmap_num, internal_leading;
1205 FONTSIGNATURE fs;
1206
1207 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1208 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1209
1210 #ifdef HAVE_CARBON_CARBON_H
1211 if(file && !fake_family)
1212 {
1213 char **mac_list = expand_mac_font(file);
1214 if(mac_list)
1215 {
1216 BOOL had_one = FALSE;
1217 char **cursor;
1218 for(cursor = mac_list; *cursor; cursor++)
1219 {
1220 had_one = TRUE;
1221 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1222 HeapFree(GetProcessHeap(), 0, *cursor);
1223 }
1224 HeapFree(GetProcessHeap(), 0, mac_list);
1225 if(had_one)
1226 return 1;
1227 }
1228 }
1229 #endif /* HAVE_CARBON_CARBON_H */
1230
1231 do {
1232 char *family_name = fake_family;
1233
1234 if (file)
1235 {
1236 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1237 err = pFT_New_Face(library, file, face_index, &ft_face);
1238 } else
1239 {
1240 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1241 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1242 }
1243
1244 if(err != 0) {
1245 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1246 return 0;
1247 }
1248
1249 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*/
1250 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1251 pFT_Done_Face(ft_face);
1252 return 0;
1253 }
1254
1255 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1256 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1257 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1258 pFT_Done_Face(ft_face);
1259 return 0;
1260 }
1261
1262 if(FT_IS_SFNT(ft_face))
1263 {
1264 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1265 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1266 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1267 {
1268 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1269 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1270 pFT_Done_Face(ft_face);
1271 return 0;
1272 }
1273
1274 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1275 we don't want to load these. */
1276 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1277 {
1278 FT_ULong len = 0;
1279
1280 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1281 {
1282 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1283 pFT_Done_Face(ft_face);
1284 return 0;
1285 }
1286 }
1287 }
1288
1289 if(!ft_face->family_name || !ft_face->style_name) {
1290 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1291 pFT_Done_Face(ft_face);
1292 return 0;
1293 }
1294
1295 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1296 {
1297 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1298 pFT_Done_Face(ft_face);
1299 return 0;
1300 }
1301
1302 if (target_family)
1303 {
1304 localised_family = get_familyname(ft_face);
1305 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1306 {
1307 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1308 HeapFree(GetProcessHeap(), 0, localised_family);
1309 num_faces = ft_face->num_faces;
1310 pFT_Done_Face(ft_face);
1311 continue;
1312 }
1313 HeapFree(GetProcessHeap(), 0, localised_family);
1314 }
1315
1316 if(!family_name)
1317 family_name = ft_face->family_name;
1318
1319 bitmap_num = 0;
1320 do {
1321 My_FT_Bitmap_Size *size = NULL;
1322 FT_ULong tmp_size;
1323
1324 if(!FT_IS_SCALABLE(ft_face))
1325 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1326
1327 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1328 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1329 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1330
1331 localised_family = NULL;
1332 if(!fake_family) {
1333 localised_family = get_familyname(ft_face);
1334 if(localised_family && !strcmpW(localised_family, english_family)) {
1335 HeapFree(GetProcessHeap(), 0, localised_family);
1336 localised_family = NULL;
1337 }
1338 }
1339
1340 family = NULL;
1341 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1342 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1343 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1344 break;
1345 family = NULL;
1346 }
1347 if(!family) {
1348 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1349 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1350 list_init(&family->faces);
1351 list_add_tail(&font_list, &family->entry);
1352
1353 if(localised_family) {
1354 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1355 subst->from.name = strdupW(english_family);
1356 subst->from.charset = -1;
1357 subst->to.name = strdupW(localised_family);
1358 subst->to.charset = -1;
1359 add_font_subst(&font_subst_list, subst, 0);
1360 }
1361 }
1362 HeapFree(GetProcessHeap(), 0, localised_family);
1363 HeapFree(GetProcessHeap(), 0, english_family);
1364
1365 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1366 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1367 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1368
1369 internal_leading = 0;
1370 memset(&fs, 0, sizeof(fs));
1371
1372 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1373 if(pOS2) {
1374 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1375 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1376 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1377 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1378 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1379 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1380 if(pOS2->version == 0) {
1381 FT_UInt dummy;
1382
1383 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1384 fs.fsCsb[0] |= FS_LATIN1;
1385 else
1386 fs.fsCsb[0] |= FS_SYMBOL;
1387 }
1388 }
1389 #ifdef HAVE_FREETYPE_FTWINFNT_H
1390 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1391 CHARSETINFO csi;
1392 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1393 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1394 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1395 fs = csi.fs;
1396 internal_leading = winfnt_header.internal_leading;
1397 }
1398 #endif
1399
1400 face_elem_ptr = list_head(&family->faces);
1401 while(face_elem_ptr) {
1402 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1403 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1404 if(!strcmpW(face->StyleName, StyleW) &&
1405 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1406 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1407 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1408 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1409
1410 if(fake_family) {
1411 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1412 HeapFree(GetProcessHeap(), 0, StyleW);
1413 pFT_Done_Face(ft_face);
1414 return 1;
1415 }
1416 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1417 TRACE("Original font is newer so skipping this one\n");
1418 HeapFree(GetProcessHeap(), 0, StyleW);
1419 pFT_Done_Face(ft_face);
1420 return 1;
1421 } else {
1422 TRACE("Replacing original with this one\n");
1423 list_remove(&face->entry);
1424 HeapFree(GetProcessHeap(), 0, face->file);
1425 HeapFree(GetProcessHeap(), 0, face->StyleName);
1426 HeapFree(GetProcessHeap(), 0, face);
1427 break;
1428 }
1429 }
1430 }
1431 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1432 face->cached_enum_data = NULL;
1433 face->StyleName = StyleW;
1434 if (file)
1435 {
1436 face->file = strdupA(file);
1437 face->font_data_ptr = NULL;
1438 face->font_data_size = 0;
1439 }
1440 else
1441 {
1442 face->file = NULL;
1443 face->font_data_ptr = font_data_ptr;
1444 face->font_data_size = font_data_size;
1445 }
1446 face->face_index = face_index;
1447 face->ntmFlags = 0;
1448 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1449 face->ntmFlags |= NTM_ITALIC;
1450 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1451 face->ntmFlags |= NTM_BOLD;
1452 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1453 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1454 face->family = family;
1455 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1456 face->fs = fs;
1457 memset(&face->fs_links, 0, sizeof(face->fs_links));
1458
1459 if(FT_IS_SCALABLE(ft_face)) {
1460 memset(&face->size, 0, sizeof(face->size));
1461 face->scalable = TRUE;
1462 } else {
1463 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1464 size->height, size->width, size->size >> 6,
1465 size->x_ppem >> 6, size->y_ppem >> 6);
1466 face->size.height = size->height;
1467 face->size.width = size->width;
1468 face->size.size = size->size;
1469 face->size.x_ppem = size->x_ppem;
1470 face->size.y_ppem = size->y_ppem;
1471 face->size.internal_leading = internal_leading;
1472 face->scalable = FALSE;
1473 }
1474
1475 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1476 tmp_size = 0;
1477 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1478 {
1479 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1480 face->ntmFlags |= NTM_PS_OPENTYPE;
1481 }
1482
1483 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1484 face->fs.fsCsb[0], face->fs.fsCsb[1],
1485 face->fs.fsUsb[0], face->fs.fsUsb[1],
1486 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1487
1488
1489 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1490 for(i = 0; i < ft_face->num_charmaps; i++) {
1491 switch(ft_face->charmaps[i]->encoding) {
1492 case FT_ENCODING_UNICODE:
1493 case FT_ENCODING_APPLE_ROMAN:
1494 face->fs.fsCsb[0] |= FS_LATIN1;
1495 break;
1496 case FT_ENCODING_MS_SYMBOL:
1497 face->fs.fsCsb[0] |= FS_SYMBOL;
1498 break;
1499 default:
1500 break;
1501 }
1502 }
1503 }
1504
1505 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1506 have_installed_roman_font = TRUE;
1507
1508 AddFaceToFamily(face, family);
1509
1510 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1511
1512 num_faces = ft_face->num_faces;
1513 pFT_Done_Face(ft_face);
1514 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1515 debugstr_w(StyleW));
1516 } while(num_faces > ++face_index);
1517 return num_faces;
1518 }
1519
1520 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1521 {
1522 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1523 }
1524
1525 static void DumpFontList(void)
1526 {
1527 Family *family;
1528 Face *face;
1529 struct list *family_elem_ptr, *face_elem_ptr;
1530
1531 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1532 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1533 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1534 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1535 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1536 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1537 if(!face->scalable)
1538 TRACE(" %d", face->size.height);
1539 TRACE("\n");
1540 }
1541 }
1542 return;
1543 }
1544
1545 /***********************************************************
1546 * The replacement list is a way to map an entire font
1547 * family onto another family. For example adding
1548 *
1549 * [HKCU\Software\Wine\Fonts\Replacements]
1550 * "Wingdings"="Winedings"
1551 *
1552 * would enumerate the Winedings font both as Winedings and
1553 * Wingdings. However if a real Wingdings font is present the
1554 * replacement does not take place.
1555 *
1556 */
1557 static void LoadReplaceList(void)
1558 {
1559 HKEY hkey;
1560 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1561 LPWSTR value;
1562 LPVOID data;
1563 Family *family;
1564 Face *face;
1565 struct list *family_elem_ptr, *face_elem_ptr;
1566 CHAR familyA[400];
1567
1568 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1569 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1570 {
1571 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1572 &valuelen, &datalen, NULL, NULL);
1573
1574 valuelen++; /* returned value doesn't include room for '\0' */
1575 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1576 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1577
1578 dlen = datalen;
1579 vlen = valuelen;
1580 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1581 &dlen) == ERROR_SUCCESS) {
1582 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1583 /* "NewName"="Oldname" */
1584 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1585
1586 /* Find the old family and hence all of the font files
1587 in that family */
1588 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1589 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1590 if(!strcmpiW(family->FamilyName, data)) {
1591 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1592 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1593 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1594 debugstr_w(face->StyleName), familyA);
1595 /* Now add a new entry with the new family name */
1596 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1597 }
1598 break;
1599 }
1600 }
1601 /* reset dlen and vlen */
1602 dlen = datalen;
1603 vlen = valuelen;
1604 }
1605 HeapFree(GetProcessHeap(), 0, data);
1606 HeapFree(GetProcessHeap(), 0, value);
1607 RegCloseKey(hkey);
1608 }
1609 }
1610
1611 /*************************************************************
1612 * init_system_links
1613 */
1614 static BOOL init_system_links(void)
1615 {
1616 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1617 'W','i','n','d','o','w','s',' ','N','T','\\',
1618 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1619 'S','y','s','t','e','m','L','i','n','k',0};
1620 HKEY hkey;
1621 BOOL ret = FALSE;
1622 DWORD type, max_val, max_data, val_len, data_len, index;
1623 WCHAR *value, *data;
1624 WCHAR *entry, *next;
1625 SYSTEM_LINKS *font_link, *system_font_link;
1626 CHILD_FONT *child_font;
1627 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1628 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1629 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1630 FONTSIGNATURE fs;
1631 Family *family;
1632 Face *face;
1633 FontSubst *psub;
1634
1635 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1636 {
1637 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1638 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1639 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1640 val_len = max_val + 1;
1641 data_len = max_data;
1642 index = 0;
1643 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1644 {
1645 TRACE("%s:\n", debugstr_w(value));
1646
1647 memset(&fs, 0, sizeof(fs));
1648 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1649 psub = get_font_subst(&font_subst_list, value, -1);
1650 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1651 list_init(&font_link->links);
1652 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1653 {
1654 WCHAR *face_name;
1655 CHILD_FONT *child_font;
1656
1657 TRACE("\t%s\n", debugstr_w(entry));
1658
1659 next = entry + strlenW(entry) + 1;
1660
1661 face_name = strchrW(entry, ',');
1662 if(face_name)
1663 {
1664 *face_name++ = 0;
1665 while(isspaceW(*face_name))
1666 face_name++;
1667
1668 psub = get_font_subst(&font_subst_list, face_name, -1);
1669 if(psub)
1670 face_name = psub->to.name;
1671 }
1672 face = find_face_from_filename(entry, face_name);
1673 if(!face)
1674 {
1675 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1676 continue;
1677 }
1678
1679 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1680 child_font->face = face;
1681 child_font->font = NULL;
1682 fs.fsCsb[0] |= face->fs.fsCsb[0];
1683 fs.fsCsb[1] |= face->fs.fsCsb[1];
1684 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1685 list_add_tail(&font_link->links, &child_font->entry);
1686 }
1687 family = find_family_from_name(font_link->font_name);
1688 if(family)
1689 {
1690 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1691 {
1692 face->fs_links = fs;
1693 }
1694 }
1695 list_add_tail(&system_links, &font_link->entry);
1696 val_len = max_val + 1;
1697 data_len = max_data;
1698 }
1699
1700 HeapFree(GetProcessHeap(), 0, value);
1701 HeapFree(GetProcessHeap(), 0, data);
1702 RegCloseKey(hkey);
1703 }
1704
1705 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1706 that Tahoma has */
1707
1708 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1709 system_font_link->font_name = strdupW(System);
1710 list_init(&system_font_link->links);
1711
1712 face = find_face_from_filename(tahoma_ttf, Tahoma);
1713 if(face)
1714 {
1715 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1716 child_font->face = face;
1717 child_font->font = NULL;
1718 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1719 list_add_tail(&system_font_link->links, &child_font->entry);
1720 }
1721 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1722 {
1723 if(!strcmpiW(font_link->font_name, Tahoma))
1724 {
1725 CHILD_FONT *font_link_entry;
1726 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1727 {
1728 CHILD_FONT *new_child;
1729 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1730 new_child->face = font_link_entry->face;
1731 new_child->font = NULL;
1732 list_add_tail(&system_font_link->links, &new_child->entry);
1733 }
1734 break;
1735 }
1736 }
1737 list_add_tail(&system_links, &system_font_link->entry);
1738 return ret;
1739 }
1740
1741 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1742 {
1743 DIR *dir;
1744 struct dirent *dent;
1745 char path[MAX_PATH];
1746
1747 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1748
1749 dir = opendir(dirname);
1750 if(!dir) {
1751 WARN("Can't open directory %s\n", debugstr_a(dirname));
1752 return FALSE;
1753 }
1754 while((dent = readdir(dir)) != NULL) {
1755 struct stat statbuf;
1756
1757 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1758 continue;
1759
1760 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1761
1762 sprintf(path, "%s/%s", dirname, dent->d_name);
1763
1764 if(stat(path, &statbuf) == -1)
1765 {
1766 WARN("Can't stat %s\n", debugstr_a(path));
1767 continue;
1768 }
1769 if(S_ISDIR(statbuf.st_mode))
1770 ReadFontDir(path, external_fonts);
1771 else
1772 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1773 }
1774 closedir(dir);
1775 return TRUE;
1776 }
1777
1778 static void load_fontconfig_fonts(void)
1779 {
1780 #ifdef SONAME_LIBFONTCONFIG
1781 void *fc_handle = NULL;
1782 FcConfig *config;
1783 FcPattern *pat;
1784 FcObjectSet *os;
1785 FcFontSet *fontset;
1786 int i, len;
1787 char *file;
1788 const char *ext;
1789
1790 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1791 if(!fc_handle) {
1792 TRACE("Wine cannot find the fontconfig library (%s).\n",
1793 SONAME_LIBFONTCONFIG);
1794 return;
1795 }
1796 #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;}
1797 LOAD_FUNCPTR(FcConfigGetCurrent);
1798 LOAD_FUNCPTR(FcFontList);
1799 LOAD_FUNCPTR(FcFontSetDestroy);
1800 LOAD_FUNCPTR(FcInit);
1801 LOAD_FUNCPTR(FcObjectSetAdd);
1802 LOAD_FUNCPTR(FcObjectSetCreate);
1803 LOAD_FUNCPTR(FcObjectSetDestroy);
1804 LOAD_FUNCPTR(FcPatternCreate);
1805 LOAD_FUNCPTR(FcPatternDestroy);
1806 LOAD_FUNCPTR(FcPatternGetBool);
1807 LOAD_FUNCPTR(FcPatternGetString);
1808 #undef LOAD_FUNCPTR
1809
1810 if(!pFcInit()) return;
1811
1812 config = pFcConfigGetCurrent();
1813 pat = pFcPatternCreate();
1814 os = pFcObjectSetCreate();
1815 pFcObjectSetAdd(os, FC_FILE);
1816 pFcObjectSetAdd(os, FC_SCALABLE);
1817 fontset = pFcFontList(config, pat, os);
1818 if(!fontset) return;
1819 for(i = 0; i < fontset->nfont; i++) {
1820 FcBool scalable;
1821
1822 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1823 continue;
1824 TRACE("fontconfig: %s\n", file);
1825
1826 /* We're just interested in OT/TT fonts for now, so this hack just
1827 picks up the scalable fonts without extensions .pf[ab] to save time
1828 loading every other font */
1829
1830 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1831 {
1832 TRACE("not scalable\n");
1833 continue;
1834 }
1835
1836 len = strlen( file );
1837 if(len < 4) continue;
1838 ext = &file[ len - 3 ];
1839 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1840 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1841 }
1842 pFcFontSetDestroy(fontset);
1843 pFcObjectSetDestroy(os);
1844 pFcPatternDestroy(pat);
1845 sym_not_found:
1846 #endif
1847 return;
1848 }
1849
1850 static BOOL load_font_from_data_dir(LPCWSTR file)
1851 {
1852 BOOL ret = FALSE;
1853 const char *data_dir = wine_get_data_dir();
1854
1855 if (!data_dir) data_dir = wine_get_build_dir();
1856
1857 if (data_dir)
1858 {
1859 INT len;
1860 char *unix_name;
1861
1862 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1863
1864 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1865
1866 strcpy(unix_name, data_dir);
1867 strcat(unix_name, "/fonts/");
1868
1869 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1870
1871 EnterCriticalSection( &freetype_cs );
1872 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1873 LeaveCriticalSection( &freetype_cs );
1874 HeapFree(GetProcessHeap(), 0, unix_name);
1875 }
1876 return ret;
1877 }
1878
1879 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1880 {
1881 static const WCHAR slashW[] = {'\\','\0'};
1882 BOOL ret = FALSE;
1883 WCHAR windowsdir[MAX_PATH];
1884 char *unixname;
1885
1886 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1887 strcatW(windowsdir, fontsW);
1888 strcatW(windowsdir, slashW);
1889 strcatW(windowsdir, file);
1890 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1891 EnterCriticalSection( &freetype_cs );
1892 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1893 LeaveCriticalSection( &freetype_cs );
1894 HeapFree(GetProcessHeap(), 0, unixname);
1895 }
1896 return ret;
1897 }
1898
1899 static void load_system_fonts(void)
1900 {
1901 HKEY hkey;
1902 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1903 const WCHAR * const *value;
1904 DWORD dlen, type;
1905 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1906 char *unixname;
1907
1908 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1909 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1910 strcatW(windowsdir, fontsW);
1911 for(value = SystemFontValues; *value; value++) {
1912 dlen = sizeof(data);
1913 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1914 type == REG_SZ) {
1915 BOOL added = FALSE;
1916
1917 sprintfW(pathW, fmtW, windowsdir, data);
1918 if((unixname = wine_get_unix_file_name(pathW))) {
1919 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1920 HeapFree(GetProcessHeap(), 0, unixname);
1921 }
1922 if (!added)
1923 load_font_from_data_dir(data);
1924 }
1925 }
1926 RegCloseKey(hkey);
1927 }
1928 }
1929
1930 /*************************************************************
1931 *
1932 * This adds registry entries for any externally loaded fonts
1933 * (fonts from fontconfig or FontDirs). It also deletes entries
1934 * of no longer existing fonts.
1935 *
1936 */
1937 static void update_reg_entries(void)
1938 {
1939 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1940 LPWSTR valueW;
1941 DWORD len, len_fam;
1942 Family *family;
1943 Face *face;
1944 struct list *family_elem_ptr, *face_elem_ptr;
1945 WCHAR *file;
1946 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1947 static const WCHAR spaceW[] = {' ', '\0'};
1948 char *path;
1949
1950 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1951 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1952 ERR("Can't create Windows font reg key\n");
1953 goto end;
1954 }
1955
1956 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1957 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1958 ERR("Can't create Windows font reg key\n");
1959 goto end;
1960 }
1961
1962 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1963 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1964 ERR("Can't create external font reg key\n");
1965 goto end;
1966 }
1967
1968 /* enumerate the fonts and add external ones to the two keys */
1969
1970 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1971 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1972 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1973 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1974 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1975 if(!face->external) continue;
1976 len = len_fam;
1977 if (!(face->ntmFlags & NTM_REGULAR))
1978 len = len_fam + strlenW(face->StyleName) + 1;
1979 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1980 strcpyW(valueW, family->FamilyName);
1981 if(len != len_fam) {
1982 strcatW(valueW, spaceW);
1983 strcatW(valueW, face->StyleName);
1984 }
1985 strcatW(valueW, TrueType);
1986
1987 file = wine_get_dos_file_name(face->file);
1988 if(file)
1989 len = strlenW(file) + 1;
1990 else
1991 {
1992 if((path = strrchr(face->file, '/')) == NULL)
1993 path = face->file;
1994 else
1995 path++;
1996 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1997
1998 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1999 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2000 }
2001 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2002 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2003 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2004
2005 HeapFree(GetProcessHeap(), 0, file);
2006 HeapFree(GetProcessHeap(), 0, valueW);
2007 }
2008 }
2009 end:
2010 if(external_key) RegCloseKey(external_key);
2011 if(win9x_key) RegCloseKey(win9x_key);
2012 if(winnt_key) RegCloseKey(winnt_key);
2013 return;
2014 }
2015
2016 static void delete_external_font_keys(void)
2017 {
2018 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2019 DWORD dlen, vlen, datalen, valuelen, i, type;
2020 LPWSTR valueW;
2021 LPVOID data;
2022
2023 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2024 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2025 ERR("Can't create Windows font reg key\n");
2026 goto end;
2027 }
2028
2029 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2030 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2031 ERR("Can't create Windows font reg key\n");
2032 goto end;
2033 }
2034
2035 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2036 ERR("Can't create external font reg key\n");
2037 goto end;
2038 }
2039
2040 /* Delete all external fonts added last time */
2041
2042 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2043 &valuelen, &datalen, NULL, NULL);
2044 valuelen++; /* returned value doesn't include room for '\0' */
2045 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2046 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2047
2048 dlen = datalen * sizeof(WCHAR);
2049 vlen = valuelen;
2050 i = 0;
2051 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2052 &dlen) == ERROR_SUCCESS) {
2053
2054 RegDeleteValueW(winnt_key, valueW);
2055 RegDeleteValueW(win9x_key, valueW);
2056 /* reset dlen and vlen */
2057 dlen = datalen;
2058 vlen = valuelen;
2059 }
2060 HeapFree(GetProcessHeap(), 0, data);
2061 HeapFree(GetProcessHeap(), 0, valueW);
2062
2063 /* Delete the old external fonts key */
2064 RegCloseKey(external_key);
2065 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2066
2067 end:
2068 if(win9x_key) RegCloseKey(win9x_key);
2069 if(winnt_key) RegCloseKey(winnt_key);
2070 }
2071
2072 /*************************************************************
2073 * WineEngAddFontResourceEx
2074 *
2075 */
2076 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2077 {
2078 INT ret = 0;
2079 if (ft_handle) /* do it only if we have freetype up and running */
2080 {
2081 char *unixname;
2082
2083 if(flags)
2084 FIXME("Ignoring flags %x\n", flags);
2085
2086 if((unixname = wine_get_unix_file_name(file)))
2087 {
2088 EnterCriticalSection( &freetype_cs );
2089 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2090 LeaveCriticalSection( &freetype_cs );
2091 HeapFree(GetProcessHeap(), 0, unixname);
2092 }
2093 if (!ret && !strchrW(file, '\\')) {
2094 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2095 ret = load_font_from_winfonts_dir(file);
2096 if (!ret) {
2097 /* Try in datadir/fonts (or builddir/fonts),
2098 * needed for Magic the Gathering Online
2099 */
2100 ret = load_font_from_data_dir(file);
2101 }
2102 }
2103 }
2104 return ret;
2105 }
2106
2107 /*************************************************************
2108 * WineEngAddFontMemResourceEx
2109 *
2110 */
2111 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2112 {
2113 if (ft_handle) /* do it only if we have freetype up and running */
2114 {
2115 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2116
2117 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2118 memcpy(pFontCopy, pbFont, cbFont);
2119
2120 EnterCriticalSection( &freetype_cs );
2121 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2122 LeaveCriticalSection( &freetype_cs );
2123
2124 if (*pcFonts == 0)
2125 {
2126 TRACE("AddFontToList failed\n");
2127 HeapFree(GetProcessHeap(), 0, pFontCopy);
2128 return NULL;
2129 }
2130 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2131 * For now return something unique but quite random
2132 */
2133 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2134 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2135 }
2136
2137 *pcFonts = 0;
2138 return 0;
2139 }
2140
2141 /*************************************************************
2142 * WineEngRemoveFontResourceEx
2143 *
2144 */
2145 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2146 {
2147 FIXME(":stub\n");
2148 return TRUE;
2149 }
2150
2151 static const struct nls_update_font_list
2152 {
2153 UINT ansi_cp, oem_cp;
2154 const char *oem, *fixed, *system;
2155 const char *courier, *serif, *small, *sserif;
2156 /* these are for font substitutes */
2157 const char *shelldlg, *tmsrmn;
2158 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2159 *helv_0, *tmsrmn_0;
2160 const struct subst
2161 {
2162 const char *from, *to;
2163 } arial_0, courier_new_0, times_new_roman_0;
2164 } nls_update_font_list[] =
2165 {
2166 /* Latin 1 (United States) */
2167 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2168 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2169 "Tahoma","Times New Roman",
2170 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2171 { 0 }, { 0 }, { 0 }
2172 },
2173 /* Latin 1 (Multilingual) */
2174 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2175 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2176 "Tahoma","Times New Roman", /* FIXME unverified */
2177 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2178 { 0 }, { 0 }, { 0 }
2179 },
2180 /* Eastern Europe */
2181 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2182 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2183 "Tahoma","Times New Roman", /* FIXME unverified */
2184 "Fixedsys,238", "System,238",
2185 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2186 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2187 { "Arial CE,0", "Arial,238" },
2188 { "Courier New CE,0", "Courier New,238" },
2189 { "Times New Roman CE,0", "Times New Roman,238" }
2190 },
2191 /* Cyrillic */
2192 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2193 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2194 "Tahoma","Times New Roman", /* FIXME unverified */
2195 "Fixedsys,204", "System,204",
2196 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2197 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2198 { "Arial Cyr,0", "Arial,204" },
2199 { "Courier New Cyr,0", "Courier New,204" },
2200 { "Times New Roman Cyr,0", "Times New Roman,204" }
2201 },
2202 /* Greek */
2203 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2204 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2205 "Tahoma","Times New Roman", /* FIXME unverified */
2206 "Fixedsys,161", "System,161",
2207 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2208 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2209 { "Arial Greek,0", "Arial,161" },
2210 { "Courier New Greek,0", "Courier New,161" },
2211 { "Times New Roman Greek,0", "Times New Roman,161" }
2212 },
2213 /* Turkish */
2214 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2215 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2216 "Tahoma","Times New Roman", /* FIXME unverified */
2217 "Fixedsys,162", "System,162",
2218 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2219 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2220 { "Arial Tur,0", "Arial,162" },
2221 { "Courier New Tur,0", "Courier New,162" },
2222 { "Times New Roman Tur,0", "Times New Roman,162" }
2223 },
2224 /* Hebrew */
2225 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2226 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2227 "Tahoma","Times New Roman", /* FIXME unverified */
2228 "Fixedsys,177", "System,177",
2229 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2230 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2231 { 0 }, { 0 }, { 0 }
2232 },
2233 /* Arabic */
2234 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2235 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2236 "Tahoma","Times New Roman", /* FIXME unverified */
2237 "Fixedsys,178", "System,178",
2238 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2239 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2240 { 0 }, { 0 }, { 0 }
2241 },
2242 /* Baltic */
2243 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2244 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2245 "Tahoma","Times New Roman", /* FIXME unverified */
2246 "Fixedsys,186", "System,186",
2247 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2248 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2249 { "Arial Baltic,0", "Arial,186" },
2250 { "Courier New Baltic,0", "Courier New,186" },
2251 { "Times New Roman Baltic,0", "Times New Roman,186" }
2252 },
2253 /* Vietnamese */
2254 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2255 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2256 "Tahoma","Times New Roman", /* FIXME unverified */
2257 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2258 { 0 }, { 0 }, { 0 }
2259 },
2260 /* Thai */
2261 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2262 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2263 "Tahoma","Times New Roman", /* FIXME unverified */
2264 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2265 { 0 }, { 0 }, { 0 }
2266 },
2267 /* Japanese */
2268 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2269 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2270 "MS UI Gothic","MS Serif",
2271 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2272 { 0 }, { 0 }, { 0 }
2273 },
2274 /* Chinese Simplified */
2275 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2276 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2277 "Tahoma", "Times New Roman", /* FIXME unverified */
2278 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2279 { 0 }, { 0 }, { 0 }
2280 },
2281 /* Korean */
2282 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2283 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2284 "Gulim", "Batang",
2285 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2286 { 0 }, { 0 }, { 0 }
2287 },
2288 /* Chinese Traditional */
2289 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2290 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2291 "PMingLiU", "MingLiU",
2292 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2293 { 0 }, { 0 }, { 0 }
2294 }
2295 };
2296
2297 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2298 {
2299 return ( ansi_cp == 932 /* CP932 for Japanese */
2300 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2301 || ansi_cp == 949 /* CP949 for Korean */
2302 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2303 }
2304
2305 static inline HKEY create_fonts_NT_registry_key(void)
2306 {
2307 HKEY hkey = 0;
2308
2309 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2310 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2311 return hkey;
2312 }
2313
2314 static inline HKEY create_fonts_9x_registry_key(void)
2315 {
2316 HKEY hkey = 0;
2317
2318 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2319 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2320 return hkey;
2321 }
2322
2323 static inline HKEY create_config_fonts_registry_key(void)
2324 {
2325 HKEY hkey = 0;
2326
2327 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2328 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2329 return hkey;
2330 }
2331
2332 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2333 {
2334 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2335 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2336 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2337 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2338 }
2339
2340 static void set_value_key(HKEY hkey, const char *name, const char *value)
2341 {
2342 if (value)
2343 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2344 else if (name)
2345 RegDeleteValueA(hkey, name);
2346 }
2347
2348 static void update_font_info(void)
2349 {
2350 char buf[40], cpbuf[40];
2351 DWORD len, type;
2352 HKEY hkey = 0;
2353 UINT i, ansi_cp = 0, oem_cp = 0;
2354 BOOL done = FALSE;
2355
2356 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2357 return;
2358
2359 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2360 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2361 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2362 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2363 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2364
2365 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2366 if (is_dbcs_ansi_cp(ansi_cp))
2367 use_default_fallback = TRUE;
2368
2369 len = sizeof(buf);
2370 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2371 {
2372 if (!strcmp( buf, cpbuf )) /* already set correctly */
2373 {
2374 RegCloseKey(hkey);
2375 return;
2376 }
2377 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2378 }
2379 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2380
2381 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2382 RegCloseKey(hkey);
2383
2384 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2385 {
2386 HKEY hkey;
2387
2388 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2389 nls_update_font_list[i].oem_cp == oem_cp)
2390 {
2391 hkey = create_config_fonts_registry_key();
2392 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2393 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2394 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2395 RegCloseKey(hkey);
2396
2397 hkey = create_fonts_NT_registry_key();
2398 add_font_list(hkey, &nls_update_font_list[i]);
2399 RegCloseKey(hkey);
2400
2401 hkey = create_fonts_9x_registry_key();
2402 add_font_list(hkey, &nls_update_font_list[i]);
2403 RegCloseKey(hkey);
2404
2405 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2406 {
2407 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2408 strlen(nls_update_font_list[i].shelldlg)+1);
2409 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2410 strlen(nls_update_font_list[i].tmsrmn)+1);
2411
2412 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2413 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2414 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2415 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2416 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2417 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2418 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2419 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2420
2421 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2422 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2423 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2424
2425 RegCloseKey(hkey);
2426 }
2427 done = TRUE;
2428 }
2429 else
2430 {
2431 /* Delete the FontSubstitutes from other locales */
2432 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2433 {
2434 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2435 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2436 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2437 RegCloseKey(hkey);
2438 }
2439 }
2440 }
2441 if (!done)
2442 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2443 }
2444
2445
2446 static BOOL init_freetype(void)
2447 {
2448 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2449 if(!ft_handle) {
2450 WINE_MESSAGE(
2451 "Wine cannot find the FreeType font library. To enable Wine to\n"
2452 "use TrueType fonts please install a version of FreeType greater than\n"
2453 "or equal to 2.0.5.\n"
2454 "http://www.freetype.org\n");
2455 return FALSE;
2456 }
2457
2458 #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;}
2459
2460 LOAD_FUNCPTR(FT_Vector_Unit)
2461 LOAD_FUNCPTR(FT_Done_Face)
2462 LOAD_FUNCPTR(FT_Get_Char_Index)
2463 LOAD_FUNCPTR(FT_Get_Module)
2464 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2465 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2466 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2467 LOAD_FUNCPTR(FT_Init_FreeType)
2468 LOAD_FUNCPTR(FT_Load_Glyph)
2469 LOAD_FUNCPTR(FT_Matrix_Multiply)
2470 #ifndef FT_MULFIX_INLINED
2471 LOAD_FUNCPTR(FT_MulFix)
2472 #endif
2473 LOAD_FUNCPTR(FT_New_Face)
2474 LOAD_FUNCPTR(FT_New_Memory_Face)
2475 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2476 LOAD_FUNCPTR(FT_Outline_Transform)
2477 LOAD_FUNCPTR(FT_Outline_Translate)
2478 LOAD_FUNCPTR(FT_Select_Charmap)
2479 LOAD_FUNCPTR(FT_Set_Charmap)
2480 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2481 LOAD_FUNCPTR(FT_Vector_Transform)
2482
2483 #undef LOAD_FUNCPTR
2484 /* Don't warn if these ones are missing */
2485 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2486 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2487 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2488 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2489 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2490 #ifdef HAVE_FREETYPE_FTWINFNT_H
2491 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2492 #endif
2493 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2494 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2495 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2496 <= 2.0.3 has FT_Sqrt64 */
2497 goto sym_not_found;
2498 }
2499
2500 if(pFT_Init_FreeType(&library) != 0) {
2501 ERR("Can't init FreeType library\n");
2502 wine_dlclose(ft_handle, NULL, 0);
2503 ft_handle = NULL;
2504 return FALSE;
2505 }
2506 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2507 if (pFT_Library_Version)
2508 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2509
2510 if (FT_Version.major<=0)
2511 {
2512 FT_Version.major=2;
2513 FT_Version.minor=0;
2514 FT_Version.patch=5;
2515 }
2516 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2517 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2518 ((FT_Version.minor << 8) & 0x00ff00) |
2519 ((FT_Version.patch ) & 0x0000ff);
2520
2521 return TRUE;
2522
2523 sym_not_found:
2524 WINE_MESSAGE(
2525 "Wine cannot find certain functions that it needs inside the FreeType\n"
2526 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2527 "FreeType to at least version 2.0.5.\n"
2528 "http://www.freetype.org\n");
2529 wine_dlclose(ft_handle, NULL, 0);
2530 ft_handle = NULL;
2531 return FALSE;
2532 }
2533
2534 /*************************************************************
2535 * WineEngInit
2536 *
2537 * Initialize FreeType library and create a list of available faces
2538 */
2539 BOOL WineEngInit(void)
2540 {
2541 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2542 static const WCHAR pathW[] = {'P','a','t','h',0};
2543 HKEY hkey;
2544 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2545 LPVOID data;
2546 WCHAR windowsdir[MAX_PATH];
2547 char *unixname;
2548 HANDLE font_mutex;
2549 const char *data_dir;
2550
2551 TRACE("\n");
2552
2553 /* update locale dependent font info in registry */
2554 update_font_info();
2555
2556 if(!init_freetype()) return FALSE;
2557
2558 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2559 ERR("Failed to create font mutex\n");
2560 return FALSE;
2561 }
2562 WaitForSingleObject(font_mutex, INFINITE);
2563
2564 delete_external_font_keys();
2565
2566 /* load the system bitmap fonts */
2567 load_system_fonts();
2568
2569 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2570 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2571 strcatW(windowsdir, fontsW);
2572 if((unixname = wine_get_unix_file_name(windowsdir)))
2573 {
2574 ReadFontDir(unixname, FALSE);
2575 HeapFree(GetProcessHeap(), 0, unixname);
2576 }
2577
2578 /* load the system truetype fonts */
2579 data_dir = wine_get_data_dir();
2580 if (!data_dir) data_dir = wine_get_build_dir();
2581 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2582 strcpy(unixname, data_dir);
2583 strcat(unixname, "/fonts/");
2584 ReadFontDir(unixname, TRUE);
2585 HeapFree(GetProcessHeap(), 0, unixname);
2586 }
2587
2588 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2589 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2590 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2591 will skip these. */
2592 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2593 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2594 &hkey) == ERROR_SUCCESS) {
2595 LPWSTR valueW;
2596 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2597 &valuelen, &datalen, NULL, NULL);
2598
2599 valuelen++; /* returned value doesn't include room for '\0' */
2600 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2601 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2602 if (valueW && data)
2603 {
2604 dlen = datalen * sizeof(WCHAR);
2605 vlen = valuelen;
2606 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2607 &dlen) == ERROR_SUCCESS) {
2608 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2609 {
2610 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2611 {
2612 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2613 HeapFree(GetProcessHeap(), 0, unixname);
2614 }
2615 }
2616 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2617 {
2618 WCHAR pathW[MAX_PATH];
2619 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2620 BOOL added = FALSE;
2621
2622 sprintfW(pathW, fmtW, windowsdir, data);
2623 if((unixname = wine_get_unix_file_name(pathW)))
2624 {
2625 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2626 HeapFree(GetProcessHeap(), 0, unixname);
2627 }
2628 if (!added)
2629 load_font_from_data_dir(data);
2630 }
2631 /* reset dlen and vlen */
2632 dlen = datalen;
2633 vlen = valuelen;
2634 }
2635 }
2636 HeapFree(GetProcessHeap(), 0, data);
2637 HeapFree(GetProcessHeap(), 0, valueW);
2638 RegCloseKey(hkey);
2639 }
2640
2641 load_fontconfig_fonts();
2642
2643 /* then look in any directories that we've specified in the config file */
2644 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2645 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2646 {
2647 DWORD len;
2648 LPWSTR valueW;
2649 LPSTR valueA, ptr;
2650
2651 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2652 {
2653 len += sizeof(WCHAR);
2654 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2655 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2656 {
2657 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2658 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2659 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2660 TRACE( "got font path %s\n", debugstr_a(valueA) );
2661 ptr = valueA;
2662 while (ptr)
2663 {
2664 LPSTR next = strchr( ptr, ':' );
2665 if (next) *next++ = 0;
2666 ReadFontDir( ptr, TRUE );
2667 ptr = next;
2668 }
2669 HeapFree( GetProcessHeap(), 0, valueA );
2670 }
2671 HeapFree( GetProcessHeap(), 0, valueW );
2672 }
2673 RegCloseKey(hkey);
2674 }
2675
2676 DumpFontList();
2677 LoadSubstList();
2678 DumpSubstList();
2679 LoadReplaceList();
2680 update_reg_entries();
2681
2682 init_system_links();
2683
2684 ReleaseMutex(font_mutex);
2685 return TRUE;
2686 }
2687
2688
2689 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2690 {
2691 TT_OS2 *pOS2;
2692 TT_HoriHeader *pHori;
2693
2694 LONG ppem;
2695
2696 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2697 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2698
2699 if(height == 0) height = 16;
2700
2701 /* Calc. height of EM square:
2702 *
2703 * For +ve lfHeight we have
2704 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2705 * Re-arranging gives:
2706 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2707 *
2708 * For -ve lfHeight we have
2709 * |lfHeight| = ppem
2710 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2711 * with il = winAscent + winDescent - units_per_em]
2712 *
2713 */
2714
2715 if(height > 0) {
2716 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2717 ppem = MulDiv(ft_face->units_per_EM, height,
2718 pHori->Ascender - pHori->Descender);
2719 else
2720 ppem = MulDiv(ft_face->units_per_EM, height,
2721 pOS2->usWinAscent + pOS2->usWinDescent);
2722 }
2723 else
2724 ppem = -height;
2725
2726 return ppem;
2727 }
2728
2729 static struct font_mapping *map_font_file( const char *name )
2730 {
2731 struct font_mapping *mapping;
2732 struct stat st;
2733 int fd;
2734
2735 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2736 if (fstat( fd, &st ) == -1) goto error;
2737
2738 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2739 {
2740 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2741 {
2742 mapping->refcount++;
2743 close( fd );
2744 return mapping;
2745 }
2746 }
2747 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2748 goto error;
2749
2750 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2751 close( fd );
2752
2753 if (mapping->data == MAP_FAILED)
2754 {
2755 HeapFree( GetProcessHeap(), 0, mapping );
2756 return NULL;
2757 }
2758 mapping->refcount = 1;
2759 mapping->dev = st.st_dev;
2760 mapping->ino = st.st_ino;
2761 mapping->size = st.st_size;
2762 list_add_tail( &mappings_list, &mapping->entry );
2763 return mapping;
2764
2765 error:
2766 close( fd );
2767 return NULL;
2768 }
2769
2770 static void unmap_font_file( struct font_mapping *mapping )
2771 {
2772 if (!--mapping->refcount)
2773 {
2774 list_remove( &mapping->entry );
2775 munmap( mapping->data, mapping->size );
2776 HeapFree( GetProcessHeap(), 0, mapping );
2777 }
2778 }
2779
2780 static LONG load_VDMX(GdiFont*, LONG);
2781
2782 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2783 {
2784 FT_Error err;
2785 FT_Face ft_face;
2786 void *data_ptr;
2787 DWORD data_size;
2788
2789 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2790
2791 if (face->file)
2792 {
2793 if (!(font->mapping = map_font_file( face->file )))
2794 {
2795 WARN("failed to map %s\n", debugstr_a(face->file));
2796 return 0;
2797 }
2798 data_ptr = font->mapping->data;
2799 data_size = font->mapping->size;
2800 }
2801 else
2802 {
2803 data_ptr = face->font_data_ptr;
2804 data_size = face->font_data_size;
2805 }
2806
2807 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2808 if(err) {
2809 ERR("FT_New_Face rets %d\n", err);
2810 return 0;
2811 }
2812
2813 /* set it here, as load_VDMX needs it */
2814 font->ft_face = ft_face;
2815
2816 if(FT_IS_SCALABLE(ft_face)) {
2817 /* load the VDMX table if we have one */
2818 font->ppem = load_VDMX(font, height);
2819 if(font->ppem == 0)
2820 font->ppem = calc_ppem_for_height(ft_face, height);
2821 TRACE("height %d => ppem %d\n", height, font->ppem);
2822
2823 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2824 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2825 } else {
2826 font->ppem = height;
2827 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2828 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2829 }
2830 return ft_face;
2831 }
2832
2833
2834 static int get_nearest_charset(Face *face, int *cp)
2835 {
2836 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2837 a single face with the requested charset. The idea is to check if
2838 the selected font supports the current ANSI codepage, if it does
2839 return the corresponding charset, else return the first charset */
2840
2841 CHARSETINFO csi;
2842 int acp = GetACP(), i;
2843 DWORD fs0;
2844
2845 *cp = acp;
2846 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2847 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2848 return csi.ciCharset;
2849
2850 for(i = 0; i < 32; i++) {
2851 fs0 = 1L << i;
2852 if(face->fs.fsCsb[0] & fs0) {
2853 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2854 *cp = csi.ciACP;
2855 return csi.ciCharset;
2856 }
2857 else
2858 FIXME("TCI failing on %x\n", fs0);
2859 }
2860 }
2861
2862 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2863 face->fs.fsCsb[0], face->file);
2864 *cp = acp;
2865 return DEFAULT_CHARSET;
2866 }
2867
2868 static GdiFont *alloc_font(void)
2869 {
2870 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2871 ret->gmsize = 1;
2872 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2873 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2874 ret->potm = NULL;
2875 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2876 ret->total_kern_pairs = (DWORD)-1;
2877 ret->kern_pairs = NULL;
2878 list_init(&ret->hfontlist);
2879 list_init(&ret->child_fonts);
2880 return ret;
2881 }
2882
2883 static void free_font(GdiFont *font)
2884 {
2885 struct list *cursor, *cursor2;
2886 int i;
2887
2888 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2889 {
2890 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2891 struct list *first_hfont;
2892 HFONTLIST *hfontlist;
2893 list_remove(cursor);
2894 if(child->font)
2895 {
2896 first_hfont = list_head(&child->font->hfontlist);
2897 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2898 DeleteObject(hfontlist->hfont);
2899 HeapFree(GetProcessHeap(), 0, hfontlist);
2900 free_font(child->font);
2901 }
2902 HeapFree(GetProcessHeap(), 0, child);
2903 }
2904
2905 if (font->ft_face) pFT_Done_Face(font->ft_face);
2906 if (font->mapping) unmap_font_file( font->mapping );
2907 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2908 HeapFree(GetProcessHeap(), 0, font->potm);
2909 HeapFree(GetProcessHeap(), 0, font->name);
2910 for (i = 0; i < font->gmsize; i++)
2911 HeapFree(GetProcessHeap(),0,font->gm[i]);
2912 HeapFree(GetProcessHeap(), 0, font->gm);
2913 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
2914 HeapFree(GetProcessHeap(), 0, font);
2915 }
2916
2917
2918 /*************************************************************
2919 * load_VDMX
2920 *
2921 * load the vdmx entry for the specified height
2922 */
2923
2924 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2925 ( ( (FT_ULong)_x4 << 24 ) | \
2926 ( (FT_ULong)_x3 << 16 ) | \
2927 ( (FT_ULong)_x2 << 8 ) | \
2928 (FT_ULong)_x1 )
2929
2930 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2931
2932 typedef struct {
2933 BYTE bCharSet;
2934 BYTE xRatio;
2935 BYTE yStartRatio;
2936 BYTE yEndRatio;
2937 } Ratios;
2938
2939 typedef struct {
2940 WORD recs;
2941 BYTE startsz;
2942 BYTE endsz;
2943 } VDMX_group;
2944
2945 static LONG load_VDMX(GdiFont *font, LONG height)
2946 {
2947 WORD hdr[3], tmp;
2948 VDMX_group group;
2949 BYTE devXRatio, devYRatio;
2950 USHORT numRecs, numRatios;
2951 DWORD result, offset = -1;
2952 LONG ppem = 0;
2953 int i;
2954
2955 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2956
2957 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2958 return ppem;
2959
2960 /* FIXME: need the real device aspect ratio */
2961 devXRatio = 1;
2962 devYRatio = 1;
2963
2964 numRecs = GET_BE_WORD(hdr[1]);
2965 numRatios = GET_BE_WORD(hdr[2]);
2966
2967 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2968 for(i = 0; i < numRatios; i++) {
2969 Ratios ratio;
2970
2971 offset = (3 * 2) + (i * sizeof(Ratios));
2972 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2973 offset = -1;
2974
2975 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2976
2977 if((ratio.xRatio == 0 &&
2978 ratio.yStartRatio == 0 &&
2979 ratio.yEndRatio == 0) ||
2980 (devXRatio == ratio.xRatio &&
2981 devYRatio >= ratio.yStartRatio &&
2982 devYRatio <= ratio.yEndRatio))
2983 {
2984 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2985 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2986 offset = GET_BE_WORD(tmp);
2987 break;
2988 }
2989 }
2990
2991 if(offset == -1) {
2992 FIXME("No suitable ratio found\n");
2993 return ppem;
2994 }
2995
2996 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2997 USHORT recs;
2998 BYTE startsz, endsz;
2999 WORD *vTable;
3000
3001 recs = GET_BE_WORD(group.recs);
3002 startsz = group.startsz;
3003 endsz = group.endsz;
3004
3005 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3006
3007 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3008 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3009 if(result == GDI_ERROR) {
3010 FIXME("Failed to retrieve vTable\n");
3011 goto end;
3012 }
3013
3014 if(height > 0) {
3015 for(i = 0; i < recs; i++) {
3016 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3017 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3018 ppem = GET_BE_WORD(vTable[i * 3]);
3019
3020 if(yMax + -yMin == height) {
3021 font->yMax = yMax;
3022 font->yMin = yMin;
3023 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3024 break;
3025 }
3026 if(yMax + -yMin > height) {
3027 if(--i < 0) {
3028 ppem = 0;
3029 goto end; /* failed */
3030 }
3031 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3032 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3033 ppem = GET_BE_WORD(vTable[i * 3]);
3034 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3035 break;
3036 }
3037 }
3038 if(!font->yMax) {
3039 ppem = 0;
3040 TRACE("ppem not found for height %d\n", height);
3041 }
3042 } else {
3043 ppem = -height;
3044 if(ppem < startsz || ppem > endsz)
3045 goto end;
3046
3047 for(i = 0; i < recs; i++) {
3048 USHORT yPelHeight;
3049 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3050
3051 if(yPelHeight > ppem)
3052 break; /* failed */
3053
3054 if(yPelHeight == ppem) {
3055 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3056 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3057 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3058 break;
3059 }
3060 }
3061 }
3062 end:
3063 HeapFree(GetProcessHeap(), 0, vTable);
3064 }
3065
3066 return ppem;
3067 }
3068
3069 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3070 {
3071 if(font->font_desc.hash != fd->hash) return TRUE;
3072 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3073 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3074 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3075 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3076 }
3077
3078 static void calc_hash(FONT_DESC *pfd)
3079 {
3080 DWORD hash = 0, *ptr, two_chars;
3081 WORD *pwc;
3082 unsigned int i;
3083
3084 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3085 hash ^= *ptr;
3086 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3087 hash ^= *ptr;
3088 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3089 two_chars = *ptr;
3090 pwc = (WCHAR *)&two_chars;
3091 if(!*pwc) break;
3092 *pwc = toupperW(*pwc);
3093 pwc++;
3094 *pwc = toupperW(*pwc);
3095 hash ^= two_chars;
3096 if(!*pwc) break;
3097 }
3098 hash ^= !pfd->can_use_bitmap;
3099 pfd->hash = hash;
3100 return;
3101 }
3102
3103 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3104 {
3105 GdiFont *ret;
3106 FONT_DESC fd;
3107 HFONTLIST *hflist;
3108 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3109
3110 fd.lf = *plf;
3111 fd.matrix = *pmat;
3112 fd.can_use_bitmap = can_use_bitmap;
3113 calc_hash(&fd);
3114
3115 /* try the in-use list */
3116 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3117 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3118 if(!fontcmp(ret, &fd)) {
3119 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3120 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3121 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3122 if(hflist->hfont == hfont)
3123 return ret;
3124 }
3125 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3126 hflist->hfont = hfont;
3127 list_add_head(&ret->hfontlist, &hflist->entry);
3128 return ret;
3129 }
3130 }
3131
3132 /* then the unused list */
3133 font_elem_ptr = list_head(&unused_gdi_font_list);
3134 while(font_elem_ptr) {
3135 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3136 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3137 if(!fontcmp(ret, &fd)) {
3138 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3139 assert(list_empty(&ret->hfontlist));
3140 TRACE("Found %p in unused list\n", ret);
3141 list_remove(&ret->entry);
3142 list_add_head(&gdi_font_list, &ret->entry);
3143 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3144 hflist->hfont = hfont;
3145 list_add_head(&ret->hfontlist, &hflist->entry);
3146 return ret;
3147 }
3148 }
3149 return NULL;
3150 }
3151
3152 static void add_to_cache(GdiFont *font)
3153 {
3154 static DWORD cache_num = 1;
3155
3156 font->cache_num = cache_num++;
3157 list_add_head(&gdi_font_list, &font->entry);
3158 }
3159
3160 /*************************************************************
3161 * create_child_font_list
3162 */
3163 static BOOL create_child_font_list(GdiFont *font)
3164 {
3165 BOOL ret = FALSE;
3166 SYSTEM_LINKS *font_link;
3167 CHILD_FONT *font_link_entry, *new_child;
3168
3169 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3170 {
3171 if(!strcmpW(font_link->font_name, font->name))
3172 {
3173 TRACE("found entry in system list\n");
3174 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3175 {
3176 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3177 new_child->face = font_link_entry->face;
3178 new_child->font = NULL;
3179 list_add_tail(&font->child_fonts, &new_child->entry);
3180 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3181 }
3182 ret = TRUE;
3183 break;
3184 }
3185 }
3186 /*
3187 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3188 * Sans Serif. This is how asian windows get default fallbacks for fonts
3189 */
3190 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3191 font->charset != OEM_CHARSET &&
3192 strcmpW(font->name,szDefaultFallbackLink) != 0)
3193 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3194 {
3195 if(!strcmpW(font_link->font_name,szDefaultFallbackLink))
3196 {
3197 TRACE("found entry in default fallback list\n");
3198 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3199 {
3200 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3201 new_child->face = font_link_entry->face;
3202 new_child->font = NULL;
3203 list_add_tail(&font->child_fonts, &new_child->entry);
3204 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3205 }
3206 ret = TRUE;
3207 break;
3208 }
3209 }
3210
3211 return ret;
3212 }
3213
3214 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3215 {
3216 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3217
3218 if (pFT_Set_Charmap)
3219 {
3220 FT_Int i;
3221 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3222
3223 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3224
3225 for (i = 0; i < ft_face->num_charmaps; i++)
3226 {
3227 if (ft_face->charmaps[i]->encoding == encoding)
3228 {
3229 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3230 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3231
3232 switch (ft_face->charmaps[i]->platform_id)
3233 {
3234 default:
3235 cmap_def = ft_face->charmaps[i];
3236 break;
3237 case 0: /* Apple Unicode */
3238 cmap0 = ft_face->charmaps[i];
3239 break;
3240 case 1: /* Macintosh */
3241 cmap1 = ft_face->charmaps[i];
3242 break;
3243 case 2: /* ISO */
3244 cmap2 = ft_face->charmaps[i];
3245 break;
3246 case 3: /* Microsoft */
3247 cmap3 = ft_face->charmaps[i];
3248 break;
3249 }
3250 }
3251
3252 if (cmap3) /* prefer Microsoft cmap table */
3253 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3254 else if (cmap1)
3255 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3256 else if (cmap2)
3257 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3258 else if (cmap0)
3259 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3260 else if (cmap_def)
3261 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3262 }
3263 return ft_err == FT_Err_Ok;
3264 }
3265
3266 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3267 }
3268
3269 /*************************************************************
3270 * WineEngCreateFontInstance
3271 *
3272 */
3273 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3274 {
3275 GdiFont *ret;
3276 Face *face, *best, *best_bitmap;
3277 Family *family, *last_resort_family;
3278 struct list *family_elem_ptr, *face_elem_ptr;
3279 INT height, width = 0;
3280 unsigned int score = 0, new_score;
3281 signed int diff = 0, newdiff;
3282 BOOL bd, it, can_use_bitmap;
3283 LOGFONTW lf;
3284 CHARSETINFO csi;
3285 HFONTLIST *hflist;
3286 FMAT2 dcmat;
3287 FontSubst *psub = NULL;
3288
3289 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3290 lf.lfWidth = abs(lf.lfWidth);
3291
3292 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3293
3294 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3295 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3296 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3297 lf.lfEscapement);
3298
3299 if(dc->GraphicsMode == GM_ADVANCED)
3300 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3301 else
3302 {
3303 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3304 font scaling abilities. */
3305 dcmat.eM11 = dcmat.eM22 = fabs(dc->xformWorld2Vport.eM22);
3306 dcmat.eM21 = dcmat.eM12 = 0;
3307 }
3308
3309 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3310 dcmat.eM21, dcmat.eM22);
3311
3312 EnterCriticalSection( &freetype_cs );
3313
3314 /* check the cache first */
3315 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3316 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3317 LeaveCriticalSection( &freetype_cs );
3318 return ret;
3319 }
3320
3321 TRACE("not in cache\n");
3322 if(list_empty(&font_list)) /* No fonts installed */
3323 {
3324 TRACE("No fonts installed\n");
3325 LeaveCriticalSection( &freetype_cs );
3326 return NULL;
3327 }
3328 if(!have_installed_roman_font)
3329 {
3330 TRACE("No roman font installed\n");
3331 LeaveCriticalSection( &freetype_cs );
3332 return NULL;
3333 }
3334
3