gdi32: Move the glyph metrics cache out of freetype.c.
[wine.git] / dlls / gdi32 / freetype.c
blob8251b257a3dbdeb26fc1b5b59ea492b2b583e1e6
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
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.
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.
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
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef GetCurrentProcess
65 #undef AnimatePalette
66 #undef EqualRgn
67 #undef FillRgn
68 #undef FrameRgn
69 #undef GetPixel
70 #undef InvertRgn
71 #undef LineTo
72 #undef OffsetRgn
73 #undef PaintRgn
74 #undef Polygon
75 #undef ResizePalette
76 #undef SetRectRgn
77 #endif /* HAVE_CARBON_CARBON_H */
79 #ifdef HAVE_FT2BUILD_H
80 #include <ft2build.h>
81 #include FT_FREETYPE_H
82 #include FT_GLYPH_H
83 #include FT_TYPES_H
84 #include FT_TRUETYPE_TABLES_H
85 #include FT_SFNT_NAMES_H
86 #include FT_TRUETYPE_IDS_H
87 #include FT_OUTLINE_H
88 #include FT_TRIGONOMETRY_H
89 #include FT_MODULE_H
90 #include FT_WINFONTS_H
91 #ifdef FT_LCD_FILTER_H
92 #include FT_LCD_FILTER_H
93 #endif
94 #endif /* HAVE_FT2BUILD_H */
96 #include "windef.h"
97 #include "winbase.h"
98 #include "winternl.h"
99 #include "winerror.h"
100 #include "winreg.h"
101 #include "wingdi.h"
102 #include "gdi_private.h"
103 #include "wine/unicode.h"
104 #include "wine/debug.h"
105 #include "wine/list.h"
107 #include "resource.h"
109 WINE_DEFAULT_DEBUG_CHANNEL(font);
111 #ifdef HAVE_FREETYPE
113 #ifndef HAVE_FT_TRUETYPEENGINETYPE
114 typedef enum
116 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
117 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
118 FT_TRUETYPE_ENGINE_TYPE_PATENTED
119 } FT_TrueTypeEngineType;
120 #endif
122 static FT_Library library = 0;
123 typedef struct
125 FT_Int major;
126 FT_Int minor;
127 FT_Int patch;
128 } FT_Version_t;
129 static FT_Version_t FT_Version;
130 static DWORD FT_SimpleVersion;
131 #define FT_VERSION_VALUE(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch))
133 static void *ft_handle = NULL;
135 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
136 MAKE_FUNCPTR(FT_Done_Face);
137 MAKE_FUNCPTR(FT_Get_Char_Index);
138 MAKE_FUNCPTR(FT_Get_First_Char);
139 MAKE_FUNCPTR(FT_Get_Next_Char);
140 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
141 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
142 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
143 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
144 MAKE_FUNCPTR(FT_Init_FreeType);
145 MAKE_FUNCPTR(FT_Library_Version);
146 MAKE_FUNCPTR(FT_Load_Glyph);
147 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
148 MAKE_FUNCPTR(FT_Matrix_Multiply);
149 #ifdef FT_MULFIX_INLINED
150 #define pFT_MulFix FT_MULFIX_INLINED
151 #else
152 MAKE_FUNCPTR(FT_MulFix);
153 #endif
154 MAKE_FUNCPTR(FT_New_Face);
155 MAKE_FUNCPTR(FT_New_Memory_Face);
156 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
157 MAKE_FUNCPTR(FT_Outline_Get_CBox);
158 MAKE_FUNCPTR(FT_Outline_Transform);
159 MAKE_FUNCPTR(FT_Outline_Translate);
160 MAKE_FUNCPTR(FT_Render_Glyph);
161 MAKE_FUNCPTR(FT_Set_Charmap);
162 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
163 MAKE_FUNCPTR(FT_Vector_Length);
164 MAKE_FUNCPTR(FT_Vector_Transform);
165 MAKE_FUNCPTR(FT_Vector_Unit);
166 static FT_Error (*pFT_Outline_Embolden)(FT_Outline *, FT_Pos);
167 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
168 #ifdef FT_LCD_FILTER_H
169 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
170 #endif
171 static FT_Error (*pFT_Property_Set)(FT_Library, const FT_String *, const FT_String *, const void *);
173 #ifdef SONAME_LIBFONTCONFIG
174 #include <fontconfig/fontconfig.h>
175 MAKE_FUNCPTR(FcConfigSubstitute);
176 MAKE_FUNCPTR(FcDefaultSubstitute);
177 MAKE_FUNCPTR(FcFontList);
178 MAKE_FUNCPTR(FcFontMatch);
179 MAKE_FUNCPTR(FcFontSetDestroy);
180 MAKE_FUNCPTR(FcInit);
181 MAKE_FUNCPTR(FcPatternAddString);
182 MAKE_FUNCPTR(FcPatternCreate);
183 MAKE_FUNCPTR(FcPatternDestroy);
184 MAKE_FUNCPTR(FcPatternGetBool);
185 MAKE_FUNCPTR(FcPatternGetInteger);
186 MAKE_FUNCPTR(FcPatternGetString);
187 #ifndef FC_NAMELANG
188 #define FC_NAMELANG "namelang"
189 #endif
190 #ifndef FC_PRGNAME
191 #define FC_PRGNAME "prgname"
192 #endif
193 #endif /* SONAME_LIBFONTCONFIG */
195 #undef MAKE_FUNCPTR
197 #ifndef FT_MAKE_TAG
198 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
199 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
200 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
201 #endif
203 #ifndef ft_encoding_none
204 #define FT_ENCODING_NONE ft_encoding_none
205 #endif
206 #ifndef ft_encoding_ms_symbol
207 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
208 #endif
209 #ifndef ft_encoding_unicode
210 #define FT_ENCODING_UNICODE ft_encoding_unicode
211 #endif
212 #ifndef ft_encoding_apple_roman
213 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
214 #endif
216 #ifdef WORDS_BIGENDIAN
217 #define GET_BE_WORD(x) (x)
218 #define GET_BE_DWORD(x) (x)
219 #else
220 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
221 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
222 #endif
224 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
225 ( ( (FT_ULong)_x4 << 24 ) | \
226 ( (FT_ULong)_x3 << 16 ) | \
227 ( (FT_ULong)_x2 << 8 ) | \
228 (FT_ULong)_x1 )
230 #define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p')
231 #define MS_GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
232 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
233 #define MS_TTCF_TAG MS_MAKE_TAG('t', 't', 'c', 'f')
234 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
236 /* 'gasp' flags */
237 #define GASP_GRIDFIT 0x01
238 #define GASP_DOGRAY 0x02
240 #ifndef WINE_FONT_DIR
241 #define WINE_FONT_DIR "fonts"
242 #endif
244 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
245 typedef struct {
246 FT_Short height;
247 FT_Short width;
248 FT_Pos size;
249 FT_Pos x_ppem;
250 FT_Pos y_ppem;
251 FT_Short internal_leading;
252 } Bitmap_Size;
254 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
255 So to let this compile on older versions of FreeType we'll define the
256 new structure here. */
257 typedef struct {
258 FT_Short height, width;
259 FT_Pos size, x_ppem, y_ppem;
260 } My_FT_Bitmap_Size;
262 struct enum_data
264 ENUMLOGFONTEXW elf;
265 NEWTEXTMETRICEXW ntm;
266 DWORD type;
269 typedef struct tagFace {
270 struct list entry;
271 unsigned int refcount;
272 WCHAR *style_name;
273 WCHAR *full_name;
274 WCHAR *file;
275 void *font_data_ptr;
276 DWORD font_data_size;
277 FT_Long face_index;
278 FONTSIGNATURE fs;
279 DWORD ntmFlags;
280 FT_Fixed font_version;
281 BOOL scalable;
282 Bitmap_Size size; /* set if face is a bitmap */
283 DWORD flags; /* ADDFONT flags */
284 struct tagFamily *family;
285 /* Cached data for Enum */
286 struct enum_data *cached_enum_data;
287 } Face;
289 #define FS_DBCS_MASK (FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB)
291 #define ADDFONT_EXTERNAL_FONT 0x01
292 #define ADDFONT_ALLOW_BITMAP 0x02
293 #define ADDFONT_ADD_TO_CACHE 0x04
294 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
295 #define ADDFONT_VERTICAL_FONT 0x10
296 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
298 typedef struct tagFamily {
299 struct list entry;
300 unsigned int refcount;
301 WCHAR family_name[LF_FACESIZE];
302 WCHAR second_name[LF_FACESIZE];
303 struct list faces;
304 struct list *replacement;
305 } Family;
307 typedef struct tagGdiFont GdiFont;
309 typedef struct {
310 struct list entry;
311 Face *face;
312 GdiFont *font;
313 } CHILD_FONT;
315 struct tagGdiFont {
316 struct gdi_font *gdi_font;
317 OUTLINETEXTMETRICW *potm;
318 DWORD total_kern_pairs;
319 KERNINGPAIR *kern_pairs;
320 struct list child_fonts;
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 GdiFont *base_font;
326 VOID *GSUB_Table;
327 const VOID *vert_feature;
328 ULONG ttc_item_offset; /* 0 if font is not a part of TrueType collection */
331 static inline GdiFont *get_font_ptr( struct gdi_font *font ) { return font->private; }
333 typedef struct {
334 struct list entry;
335 const WCHAR *font_name;
336 FONTSIGNATURE fs;
337 struct list links;
338 } SYSTEM_LINKS;
340 struct enum_charset_element {
341 DWORD mask;
342 DWORD charset;
343 WCHAR name[LF_FACESIZE];
346 struct enum_charset_list {
347 DWORD total;
348 struct enum_charset_element element[32];
351 static struct list system_links = LIST_INIT(system_links);
353 static struct list font_subst_list = LIST_INIT(font_subst_list);
355 static struct list font_list = LIST_INIT(font_list);
357 static const struct font_backend_funcs font_funcs;
359 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
360 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
361 'W','i','n','d','o','w','s','\\',
362 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
363 'F','o','n','t','s','\0'};
365 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
366 'W','i','n','d','o','w','s',' ','N','T','\\',
367 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
368 'F','o','n','t','s','\0'};
370 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
371 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
372 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
373 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
375 static const WCHAR * const SystemFontValues[] = {
376 System_Value,
377 OEMFont_Value,
378 FixedSys_Value,
379 NULL
382 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
383 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
385 /* Interesting and well-known (frequently-assumed!) font names */
386 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
387 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
388 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
389 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
390 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
391 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
392 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
393 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
395 static const WCHAR arial[] = {'A','r','i','a','l',0};
396 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
397 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
398 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
399 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
400 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
401 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
402 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
403 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
404 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
406 static const WCHAR *default_serif_list[] =
408 times_new_roman,
409 liberation_serif,
410 bitstream_vera_serif,
411 NULL
414 static const WCHAR *default_fixed_list[] =
416 courier_new,
417 liberation_mono,
418 bitstream_vera_sans_mono,
419 NULL
422 static const WCHAR *default_sans_list[] =
424 arial,
425 liberation_sans,
426 bitstream_vera_sans,
427 NULL
430 static const WCHAR *default_serif = times_new_roman;
431 static const WCHAR *default_fixed = courier_new;
432 static const WCHAR *default_sans = arial;
434 typedef struct {
435 WCHAR *name;
436 INT charset;
437 } NameCs;
439 typedef struct tagFontSubst {
440 struct list entry;
441 NameCs from;
442 NameCs to;
443 } FontSubst;
445 /* Registry font cache key and value names */
446 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
447 'F','o','n','t','s',0};
448 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
451 struct font_mapping
453 struct list entry;
454 int refcount;
455 dev_t dev;
456 ino_t ino;
457 void *data;
458 size_t size;
461 static struct list mappings_list = LIST_INIT( mappings_list );
463 static UINT default_aa_flags;
464 static HKEY hkey_font_cache;
465 static BOOL antialias_fakes = TRUE;
467 static CRITICAL_SECTION freetype_cs;
468 static CRITICAL_SECTION_DEBUG critsect_debug =
470 0, 0, &freetype_cs,
471 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
472 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
474 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
476 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
478 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
480 static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl);
481 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL *vert);
482 static BOOL get_outline_text_metrics(GdiFont *font);
483 static BOOL get_bitmap_text_metrics(GdiFont *font);
484 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
485 static void remove_face_from_cache( Face *face );
487 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
488 'W','i','n','d','o','w','s',' ','N','T','\\',
489 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
490 'S','y','s','t','e','m','L','i','n','k',0};
492 /****************************************
493 * Notes on .fon files
495 * The fonts System, FixedSys and Terminal are special. There are typically multiple
496 * versions installed for different resolutions and codepages. Windows stores which one to use
497 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
498 * Key Meaning
499 * FIXEDFON.FON FixedSys
500 * FONTS.FON System
501 * OEMFONT.FON Terminal
502 * LogPixels Current dpi set by the display control panel applet
503 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
504 * also has a LogPixels value that appears to mirror this)
506 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
507 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
508 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
509 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
510 * so that makes sense.
512 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
513 * to be mapped into the registry on Windows 2000 at least).
514 * I have
515 * woafont=app850.fon
516 * ega80woa.fon=ega80850.fon
517 * ega40woa.fon=ega40850.fon
518 * cga80woa.fon=cga80850.fon
519 * cga40woa.fon=cga40850.fon
522 /* These are all structures needed for the GSUB table */
525 typedef struct {
526 DWORD version;
527 WORD ScriptList;
528 WORD FeatureList;
529 WORD LookupList;
530 } GSUB_Header;
532 typedef struct {
533 CHAR ScriptTag[4];
534 WORD Script;
535 } GSUB_ScriptRecord;
537 typedef struct {
538 WORD ScriptCount;
539 GSUB_ScriptRecord ScriptRecord[1];
540 } GSUB_ScriptList;
542 typedef struct {
543 CHAR LangSysTag[4];
544 WORD LangSys;
545 } GSUB_LangSysRecord;
547 typedef struct {
548 WORD DefaultLangSys;
549 WORD LangSysCount;
550 GSUB_LangSysRecord LangSysRecord[1];
551 } GSUB_Script;
553 typedef struct {
554 WORD LookupOrder; /* Reserved */
555 WORD ReqFeatureIndex;
556 WORD FeatureCount;
557 WORD FeatureIndex[1];
558 } GSUB_LangSys;
560 typedef struct {
561 CHAR FeatureTag[4];
562 WORD Feature;
563 } GSUB_FeatureRecord;
565 typedef struct {
566 WORD FeatureCount;
567 GSUB_FeatureRecord FeatureRecord[1];
568 } GSUB_FeatureList;
570 typedef struct {
571 WORD FeatureParams; /* Reserved */
572 WORD LookupCount;
573 WORD LookupListIndex[1];
574 } GSUB_Feature;
576 typedef struct {
577 WORD LookupCount;
578 WORD Lookup[1];
579 } GSUB_LookupList;
581 typedef struct {
582 WORD LookupType;
583 WORD LookupFlag;
584 WORD SubTableCount;
585 WORD SubTable[1];
586 } GSUB_LookupTable;
588 typedef struct {
589 WORD CoverageFormat;
590 WORD GlyphCount;
591 WORD GlyphArray[1];
592 } GSUB_CoverageFormat1;
594 typedef struct {
595 WORD Start;
596 WORD End;
597 WORD StartCoverageIndex;
598 } GSUB_RangeRecord;
600 typedef struct {
601 WORD CoverageFormat;
602 WORD RangeCount;
603 GSUB_RangeRecord RangeRecord[1];
604 } GSUB_CoverageFormat2;
606 typedef struct {
607 WORD SubstFormat; /* = 1 */
608 WORD Coverage;
609 WORD DeltaGlyphID;
610 } GSUB_SingleSubstFormat1;
612 typedef struct {
613 WORD SubstFormat; /* = 2 */
614 WORD Coverage;
615 WORD GlyphCount;
616 WORD Substitute[1];
617 }GSUB_SingleSubstFormat2;
619 #ifdef HAVE_CARBON_CARBON_H
620 static char *find_cache_dir(void)
622 FSRef ref;
623 OSErr err;
624 static char cached_path[MAX_PATH];
625 static const char *wine = "/Wine", *fonts = "/Fonts";
627 if(*cached_path) return cached_path;
629 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
630 if(err != noErr)
632 WARN("can't create cached data folder\n");
633 return NULL;
635 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
636 if(err != noErr)
638 WARN("can't create cached data path\n");
639 *cached_path = '\0';
640 return NULL;
642 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
644 ERR("Could not create full path\n");
645 *cached_path = '\0';
646 return NULL;
648 strcat(cached_path, wine);
650 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
652 WARN("Couldn't mkdir %s\n", cached_path);
653 *cached_path = '\0';
654 return NULL;
656 strcat(cached_path, fonts);
657 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
659 WARN("Couldn't mkdir %s\n", cached_path);
660 *cached_path = '\0';
661 return NULL;
663 return cached_path;
666 /******************************************************************
667 * expand_mac_font
669 * Extracts individual TrueType font files from a Mac suitcase font
670 * and saves them into the user's caches directory (see
671 * find_cache_dir()).
672 * Returns a NULL terminated array of filenames.
674 * We do this because they are apps that try to read ttf files
675 * themselves and they don't like Mac suitcase files.
677 static char **expand_mac_font(const char *path)
679 FSRef ref;
680 ResFileRefNum res_ref;
681 OSStatus s;
682 unsigned int idx;
683 const char *out_dir;
684 const char *filename;
685 int output_len;
686 struct {
687 char **array;
688 unsigned int size, max_size;
689 } ret;
691 TRACE("path %s\n", path);
693 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
694 if(s != noErr)
696 WARN("failed to get ref\n");
697 return NULL;
700 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
701 if(s != noErr)
703 TRACE("no data fork, so trying resource fork\n");
704 res_ref = FSOpenResFile(&ref, fsRdPerm);
705 if(res_ref == -1)
707 TRACE("unable to open resource fork\n");
708 return NULL;
712 ret.size = 0;
713 ret.max_size = 10;
714 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
715 if(!ret.array)
717 CloseResFile(res_ref);
718 return NULL;
721 out_dir = find_cache_dir();
723 filename = strrchr(path, '/');
724 if(!filename) filename = path;
725 else filename++;
727 /* output filename has the form out_dir/filename_%04x.ttf */
728 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
730 UseResFile(res_ref);
731 idx = 1;
732 while(1)
734 FamRec *fam_rec;
735 unsigned short *num_faces_ptr, num_faces, face;
736 AsscEntry *assoc;
737 Handle fond;
738 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
740 fond = Get1IndResource(fond_res, idx);
741 if(!fond) break;
742 TRACE("got fond resource %d\n", idx);
743 HLock(fond);
745 fam_rec = *(FamRec**)fond;
746 num_faces_ptr = (unsigned short *)(fam_rec + 1);
747 num_faces = GET_BE_WORD(*num_faces_ptr);
748 num_faces++;
749 assoc = (AsscEntry*)(num_faces_ptr + 1);
750 TRACE("num faces %04x\n", num_faces);
751 for(face = 0; face < num_faces; face++, assoc++)
753 Handle sfnt;
754 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
755 unsigned short size, font_id;
756 char *output;
758 size = GET_BE_WORD(assoc->fontSize);
759 font_id = GET_BE_WORD(assoc->fontID);
760 if(size != 0)
762 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
763 continue;
766 TRACE("trying to load sfnt id %04x\n", font_id);
767 sfnt = GetResource(sfnt_res, font_id);
768 if(!sfnt)
770 TRACE("can't get sfnt resource %04x\n", font_id);
771 continue;
774 output = HeapAlloc(GetProcessHeap(), 0, output_len);
775 if(output)
777 int fd;
779 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
781 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
782 if(fd != -1 || errno == EEXIST)
784 if(fd != -1)
786 unsigned char *sfnt_data;
788 HLock(sfnt);
789 sfnt_data = *(unsigned char**)sfnt;
790 write(fd, sfnt_data, GetHandleSize(sfnt));
791 HUnlock(sfnt);
792 close(fd);
794 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
796 ret.max_size *= 2;
797 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
799 ret.array[ret.size++] = output;
801 else
803 WARN("unable to create %s\n", output);
804 HeapFree(GetProcessHeap(), 0, output);
807 ReleaseResource(sfnt);
809 HUnlock(fond);
810 ReleaseResource(fond);
811 idx++;
813 CloseResFile(res_ref);
815 return ret.array;
818 #endif /* HAVE_CARBON_CARBON_H */
820 static inline BOOL is_win9x(void)
822 return GetVersion() & 0x80000000;
825 This function builds an FT_Fixed from a double. It fails if the absolute
826 value of the float number is greater than 32768.
828 static inline FT_Fixed FT_FixedFromFloat(double f)
830 return f * 0x10000;
834 This function builds an FT_Fixed from a FIXED. It simply put f.value
835 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
837 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
839 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
842 static BOOL is_hinting_enabled(void)
844 static int enabled = -1;
846 if (enabled == -1)
848 /* Use the >= 2.2.0 function if available */
849 if (pFT_Get_TrueType_Engine_Type)
851 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
852 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
854 else enabled = FALSE;
855 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
857 return enabled;
860 static BOOL is_subpixel_rendering_enabled( void )
862 static int enabled = -1;
863 if (enabled == -1)
865 /* FreeType >= 2.8.1 offers LCD-optimezed rendering without lcd filters. */
866 if (FT_SimpleVersion >= FT_VERSION_VALUE(2, 8, 1))
867 enabled = TRUE;
868 #ifdef FT_LCD_FILTER_H
869 else if (pFT_Library_SetLcdFilter &&
870 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature)
871 enabled = TRUE;
872 #endif
873 else enabled = FALSE;
875 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
877 return enabled;
881 static const struct list *get_face_list_from_family(const Family *family)
883 if (!list_empty(&family->faces))
884 return &family->faces;
885 else
886 return family->replacement;
889 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
891 Family *family;
892 Face *face;
893 const WCHAR *file;
895 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
897 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
899 const struct list *face_list;
900 if (face_name && strncmpiW( face_name, family->family_name, LF_FACESIZE - 1 )) continue;
901 face_list = get_face_list_from_family(family);
902 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
904 if (!face->file)
905 continue;
906 file = strrchrW(face->file, '\\');
907 if(!file)
908 file = face->file;
909 else
910 file++;
911 if(strcmpiW(file, file_name)) continue;
912 face->refcount++;
913 return face;
916 return NULL;
919 static Family *find_family_from_name(const WCHAR *name)
921 Family *family;
923 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
924 if (!strncmpiW( family->family_name, name, LF_FACESIZE - 1 )) return family;
926 return NULL;
929 static Family *find_family_from_any_name(const WCHAR *name)
931 Family *family;
933 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
935 if (!strncmpiW( family->family_name, name, LF_FACESIZE - 1 )) return family;
936 if (!strncmpiW( family->second_name, name, LF_FACESIZE - 1 )) return family;
939 return NULL;
942 static void DumpSubstList(void)
944 FontSubst *psub;
946 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
948 if(psub->from.charset != -1 || psub->to.charset != -1)
949 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
950 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
951 else
952 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
953 debugstr_w(psub->to.name));
957 static LPWSTR strdupW(LPCWSTR p)
959 LPWSTR ret;
960 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
961 ret = HeapAlloc(GetProcessHeap(), 0, len);
962 memcpy(ret, p, len);
963 return ret;
966 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
967 INT from_charset)
969 FontSubst *element;
971 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
973 if(!strcmpiW(element->from.name, from_name) &&
974 (element->from.charset == from_charset ||
975 element->from.charset == -1))
976 return element;
979 return NULL;
982 #define ADD_FONT_SUBST_FORCE 1
984 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
986 FontSubst *from_exist, *to_exist;
988 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
990 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
992 list_remove(&from_exist->entry);
993 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
994 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
995 HeapFree(GetProcessHeap(), 0, from_exist);
996 from_exist = NULL;
999 if(!from_exist)
1001 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1003 if(to_exist)
1005 HeapFree(GetProcessHeap(), 0, subst->to.name);
1006 subst->to.name = strdupW(to_exist->to.name);
1009 list_add_tail(subst_list, &subst->entry);
1011 return TRUE;
1014 HeapFree(GetProcessHeap(), 0, subst->from.name);
1015 HeapFree(GetProcessHeap(), 0, subst->to.name);
1016 HeapFree(GetProcessHeap(), 0, subst);
1017 return FALSE;
1020 static WCHAR *towstr(UINT cp, const char *str)
1022 int len;
1023 WCHAR *wstr;
1025 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1026 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1027 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1028 return wstr;
1031 static void split_subst_info(NameCs *nc, LPSTR str)
1033 CHAR *p = strrchr(str, ',');
1035 nc->charset = -1;
1036 if(p && *(p+1)) {
1037 nc->charset = strtol(p+1, NULL, 10);
1038 *p = '\0';
1040 nc->name = towstr(CP_ACP, str);
1043 static void LoadSubstList(void)
1045 FontSubst *psub;
1046 HKEY hkey;
1047 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1048 LPSTR value;
1049 LPVOID data;
1051 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1052 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1053 &hkey) == ERROR_SUCCESS) {
1055 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1056 &valuelen, &datalen, NULL, NULL);
1058 valuelen++; /* returned value doesn't include room for '\0' */
1059 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1060 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1062 dlen = datalen;
1063 vlen = valuelen;
1064 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1065 &dlen) == ERROR_SUCCESS) {
1066 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1068 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1069 split_subst_info(&psub->from, value);
1070 split_subst_info(&psub->to, data);
1072 /* Win 2000 doesn't allow mapping between different charsets
1073 or mapping of DEFAULT_CHARSET */
1074 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1075 psub->to.charset == DEFAULT_CHARSET) {
1076 HeapFree(GetProcessHeap(), 0, psub->to.name);
1077 HeapFree(GetProcessHeap(), 0, psub->from.name);
1078 HeapFree(GetProcessHeap(), 0, psub);
1079 } else {
1080 add_font_subst(&font_subst_list, psub, 0);
1082 /* reset dlen and vlen */
1083 dlen = datalen;
1084 vlen = valuelen;
1086 HeapFree(GetProcessHeap(), 0, data);
1087 HeapFree(GetProcessHeap(), 0, value);
1088 RegCloseKey(hkey);
1093 static const LANGID mac_langid_table[] =
1095 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
1096 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
1097 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
1098 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
1099 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
1100 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
1101 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
1102 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
1103 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
1104 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
1105 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
1106 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
1107 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
1108 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
1109 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
1110 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
1111 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
1112 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
1113 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
1114 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1115 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
1116 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
1117 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
1118 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
1119 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
1120 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
1121 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
1122 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
1123 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
1124 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
1125 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
1126 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
1127 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
1128 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1129 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
1130 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
1131 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
1132 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
1133 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
1134 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
1135 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
1136 0, /* TT_MAC_LANGID_YIDDISH */
1137 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
1138 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
1139 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
1140 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
1141 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
1142 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
1143 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
1144 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
1145 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1146 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
1147 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
1148 0, /* TT_MAC_LANGID_MOLDAVIAN */
1149 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
1150 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
1151 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
1152 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
1153 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1154 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
1155 0, /* TT_MAC_LANGID_KURDISH */
1156 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
1157 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
1158 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
1159 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
1160 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
1161 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
1162 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
1163 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
1164 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
1165 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
1166 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
1167 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
1168 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
1169 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
1170 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
1171 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
1172 0, /* TT_MAC_LANGID_BURMESE */
1173 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
1174 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
1175 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
1176 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
1177 0, /* TT_MAC_LANGID_TAGALOG */
1178 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1179 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1180 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
1181 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
1182 0, /* TT_MAC_LANGID_GALLA */
1183 0, /* TT_MAC_LANGID_SOMALI */
1184 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
1185 0, /* TT_MAC_LANGID_RUANDA */
1186 0, /* TT_MAC_LANGID_RUNDI */
1187 0, /* TT_MAC_LANGID_CHEWA */
1188 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
1189 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
1190 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1191 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1192 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
1193 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
1194 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
1195 0, /* TT_MAC_LANGID_LATIN */
1196 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
1197 0, /* TT_MAC_LANGID_GUARANI */
1198 0, /* TT_MAC_LANGID_AYMARA */
1199 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
1200 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
1201 0, /* TT_MAC_LANGID_DZONGKHA */
1202 0, /* TT_MAC_LANGID_JAVANESE */
1203 0, /* TT_MAC_LANGID_SUNDANESE */
1204 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
1205 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
1206 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
1207 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
1208 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1209 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
1210 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
1211 0, /* TT_MAC_LANGID_TONGAN */
1212 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1213 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
1214 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1217 static inline WORD get_mac_code_page( const FT_SfntName *name )
1219 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
1220 return 10000 + name->encoding_id;
1223 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
1225 LANGID name_lang;
1226 int res = 0;
1228 switch (name->platform_id)
1230 case TT_PLATFORM_MICROSOFT:
1231 res += 5; /* prefer the Microsoft name */
1232 switch (name->encoding_id)
1234 case TT_MS_ID_UNICODE_CS:
1235 case TT_MS_ID_SYMBOL_CS:
1236 name_lang = name->language_id;
1237 break;
1238 default:
1239 return 0;
1241 break;
1242 case TT_PLATFORM_MACINTOSH:
1243 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
1244 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
1245 name_lang = mac_langid_table[name->language_id];
1246 break;
1247 case TT_PLATFORM_APPLE_UNICODE:
1248 res += 2; /* prefer Unicode encodings */
1249 switch (name->encoding_id)
1251 case TT_APPLE_ID_DEFAULT:
1252 case TT_APPLE_ID_ISO_10646:
1253 case TT_APPLE_ID_UNICODE_2_0:
1254 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
1255 name_lang = mac_langid_table[name->language_id];
1256 break;
1257 default:
1258 return 0;
1260 break;
1261 default:
1262 return 0;
1264 if (name_lang == lang) res += 30;
1265 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
1266 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
1267 else if (lang == MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL )) res += 5 * (0x100000 - name_lang);
1268 return res;
1271 static WCHAR *copy_name_table_string( const FT_SfntName *name )
1273 WCHAR *ret;
1274 WORD codepage;
1275 int i;
1277 switch (name->platform_id)
1279 case TT_PLATFORM_APPLE_UNICODE:
1280 case TT_PLATFORM_MICROSOFT:
1281 ret = HeapAlloc( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
1282 for (i = 0; i < name->string_len / 2; i++)
1283 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
1284 ret[i] = 0;
1285 return ret;
1286 case TT_PLATFORM_MACINTOSH:
1287 codepage = get_mac_code_page( name );
1288 i = MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, NULL, 0 );
1289 ret = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(WCHAR) );
1290 MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, ret, i );
1291 ret[i] = 0;
1292 return ret;
1294 return NULL;
1297 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
1299 FT_SfntName name;
1300 FT_UInt num_names, name_index;
1301 int res, best_lang = 0, best_index = -1;
1303 if (!FT_IS_SFNT(ft_face)) return NULL;
1305 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
1307 for (name_index = 0; name_index < num_names; name_index++)
1309 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
1310 if (name.name_id != name_id) continue;
1311 res = match_name_table_language( &name, language_id );
1312 if (res > best_lang)
1314 best_lang = res;
1315 best_index = name_index;
1319 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
1321 WCHAR *ret = copy_name_table_string( &name );
1322 TRACE( "name %u found platform %u lang %04x %s\n",
1323 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
1324 return ret;
1326 return NULL;
1329 static WCHAR *ft_face_get_family_name( FT_Face ft_face, LANGID langid )
1331 WCHAR *family_name;
1333 if ((family_name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, langid )))
1334 return family_name;
1336 return towstr( CP_ACP, ft_face->family_name );
1339 static WCHAR *ft_face_get_style_name( FT_Face ft_face, LANGID langid )
1341 WCHAR *style_name;
1343 if ((style_name = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, langid )))
1344 return style_name;
1346 return towstr( CP_ACP, ft_face->style_name );
1349 static WCHAR *ft_face_get_full_name( FT_Face ft_face, LANGID langid )
1351 static const WCHAR space_w[] = {' ',0};
1352 WCHAR *full_name, *style_name;
1353 SIZE_T length;
1355 if ((full_name = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, langid )))
1356 return full_name;
1358 full_name = ft_face_get_family_name( ft_face, langid );
1359 style_name = ft_face_get_style_name( ft_face, langid );
1361 length = strlenW( full_name ) + strlenW( space_w ) + strlenW( style_name ) + 1;
1362 full_name = HeapReAlloc( GetProcessHeap(), 0, full_name, length * sizeof(WCHAR) );
1364 strcatW( full_name, space_w );
1365 strcatW( full_name, style_name );
1366 HeapFree( GetProcessHeap(), 0, style_name );
1368 WARN( "full name not found, using %s instead\n", debugstr_w(full_name) );
1369 return full_name;
1372 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1374 if (strcmpiW( f1->full_name, f2->full_name )) return FALSE;
1375 if (f1->scalable) return TRUE;
1376 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1377 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1380 static void release_family( Family *family )
1382 if (--family->refcount) return;
1383 assert( list_empty( &family->faces ));
1384 list_remove( &family->entry );
1385 HeapFree( GetProcessHeap(), 0, family );
1388 static void release_face( Face *face )
1390 if (--face->refcount) return;
1391 if (face->family)
1393 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1394 list_remove( &face->entry );
1395 release_family( face->family );
1397 HeapFree( GetProcessHeap(), 0, face->file );
1398 HeapFree( GetProcessHeap(), 0, face->style_name );
1399 HeapFree( GetProcessHeap(), 0, face->full_name );
1400 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1401 HeapFree( GetProcessHeap(), 0, face );
1404 static inline int style_order(const Face *face)
1406 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1408 case NTM_REGULAR:
1409 return 0;
1410 case NTM_BOLD:
1411 return 1;
1412 case NTM_ITALIC:
1413 return 2;
1414 case NTM_BOLD | NTM_ITALIC:
1415 return 3;
1416 default:
1417 WARN( "Don't know how to order face %s with flags 0x%08x\n", debugstr_w(face->full_name), face->ntmFlags );
1418 return 9999;
1422 static BOOL insert_face_in_family_list( Face *face, Family *family )
1424 Face *cursor;
1426 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1428 if (faces_equal( face, cursor ))
1430 TRACE( "Already loaded face %s in family %s, original version %lx, new version %lx\n",
1431 debugstr_w(face->full_name), debugstr_w(family->family_name),
1432 cursor->font_version, face->font_version );
1434 if (face->file && !strcmpiW( face->file, cursor->file ))
1436 cursor->refcount++;
1437 TRACE("Font %s already in list, refcount now %d\n",
1438 debugstr_w(face->file), cursor->refcount);
1439 return FALSE;
1441 if (face->font_version <= cursor->font_version)
1443 TRACE("Original font %s is newer so skipping %s\n",
1444 debugstr_w(cursor->file), debugstr_w(face->file));
1445 return FALSE;
1447 else
1449 TRACE("Replacing original %s with %s\n",
1450 debugstr_w(cursor->file), debugstr_w(face->file));
1451 list_add_before( &cursor->entry, &face->entry );
1452 face->family = family;
1453 family->refcount++;
1454 face->refcount++;
1455 release_face( cursor );
1456 return TRUE;
1460 if (style_order( face ) < style_order( cursor )) break;
1463 TRACE( "Adding face %s in family %s from %s\n", debugstr_w(face->full_name),
1464 debugstr_w(family->family_name), debugstr_w(face->file) );
1465 list_add_before( &cursor->entry, &face->entry );
1466 face->family = family;
1467 family->refcount++;
1468 face->refcount++;
1469 return TRUE;
1472 /****************************************************************
1473 * NB This function stores the ptrs to the strings to save copying.
1474 * Don't free them after calling.
1476 static Family *create_family( WCHAR *family_name, WCHAR *second_name )
1478 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1479 family->refcount = 1;
1480 lstrcpynW( family->family_name, family_name, LF_FACESIZE );
1481 if (second_name) lstrcpynW( family->second_name, second_name, LF_FACESIZE );
1482 else family->second_name[0] = 0;
1483 list_init( &family->faces );
1484 family->replacement = &family->faces;
1485 list_add_tail( &font_list, &family->entry );
1487 return family;
1490 struct cached_face
1492 DWORD index;
1493 DWORD flags;
1494 DWORD ntmflags;
1495 DWORD version;
1496 DWORD width;
1497 DWORD height;
1498 DWORD size;
1499 DWORD x_ppem;
1500 DWORD y_ppem;
1501 DWORD internal_leading;
1502 FONTSIGNATURE fs;
1503 WCHAR full_name[1];
1504 /* WCHAR file_name[]; */
1507 static void load_face(HKEY hkey_family, Family *family, void *buffer, DWORD buffer_size, BOOL scalable)
1509 DWORD type, size, needed, index = 0;
1510 Face *face;
1511 HKEY hkey_strike;
1512 WCHAR name[256];
1513 struct cached_face *cached = (struct cached_face *)buffer;
1515 size = sizeof(name);
1516 needed = buffer_size - sizeof(DWORD);
1517 while (!RegEnumValueW( hkey_family, index++, name, &size, NULL, &type, buffer, &needed ))
1519 if (type == REG_BINARY && needed > sizeof(*cached))
1521 ((DWORD *)buffer)[needed / sizeof(DWORD)] = 0;
1523 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1524 face->cached_enum_data = NULL;
1525 face->family = NULL;
1526 face->refcount = 1;
1527 face->style_name = strdupW( name );
1528 face->face_index = cached->index;
1529 face->flags = cached->flags;
1530 face->ntmFlags = cached->ntmflags;
1531 face->font_version = cached->version;
1532 face->size.width = cached->width;
1533 face->size.height = cached->height;
1534 face->size.size = cached->size;
1535 face->size.x_ppem = cached->x_ppem;
1536 face->size.y_ppem = cached->y_ppem;
1537 face->size.internal_leading = cached->internal_leading;
1538 face->fs = cached->fs;
1539 face->full_name = strdupW( cached->full_name );
1540 face->file = strdupW( cached->full_name + strlenW(cached->full_name) + 1 );
1541 face->scalable = scalable;
1542 if (!face->scalable)
1543 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1544 face->size.height, face->size.width, face->size.size >> 6,
1545 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1547 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1548 face->fs.fsCsb[0], face->fs.fsCsb[1],
1549 face->fs.fsUsb[0], face->fs.fsUsb[1],
1550 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1552 if (insert_face_in_family_list(face, family))
1553 TRACE( "Added face %s to family %s\n", debugstr_w(face->full_name), debugstr_w(family->family_name) );
1555 release_face( face );
1557 size = sizeof(name);
1558 needed = buffer_size - sizeof(DWORD);
1561 /* load bitmap strikes */
1563 index = 0;
1564 needed = buffer_size;
1565 while (!RegEnumKeyExW(hkey_family, index++, buffer, &needed, NULL, NULL, NULL, NULL))
1567 if (!RegOpenKeyExW(hkey_family, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1569 load_face(hkey_strike, family, buffer, buffer_size, FALSE);
1570 RegCloseKey(hkey_strike);
1572 needed = buffer_size;
1576 /* move vertical fonts after their horizontal counterpart */
1577 /* assumes that font_list is already sorted by family name */
1578 static void reorder_vertical_fonts(void)
1580 Family *family, *next, *vert_family;
1581 struct list *ptr, *vptr;
1582 struct list vertical_families = LIST_INIT( vertical_families );
1584 LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
1586 if (family->family_name[0] != '@') continue;
1587 list_remove( &family->entry );
1588 list_add_tail( &vertical_families, &family->entry );
1591 ptr = list_head( &font_list );
1592 vptr = list_head( &vertical_families );
1593 while (ptr && vptr)
1595 family = LIST_ENTRY( ptr, Family, entry );
1596 vert_family = LIST_ENTRY( vptr, Family, entry );
1597 if (strcmpiW( family->family_name, vert_family->family_name + 1 ) > 0)
1599 list_remove( vptr );
1600 list_add_before( ptr, vptr );
1601 vptr = list_head( &vertical_families );
1603 else ptr = list_next( &font_list, ptr );
1605 list_move_tail( &font_list, &vertical_families );
1608 static void load_font_list_from_cache(HKEY hkey_font_cache)
1610 DWORD size, family_index = 0;
1611 Family *family;
1612 HKEY hkey_family;
1613 WCHAR buffer[4096];
1615 size = sizeof(buffer);
1616 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1618 WCHAR *second_name = NULL;
1619 WCHAR *family_name = strdupW( buffer );
1621 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1622 TRACE("opened family key %s\n", debugstr_w(family_name));
1623 size = sizeof(buffer);
1624 if (!RegQueryValueExW( hkey_family, NULL, NULL, NULL, (BYTE *)buffer, &size ))
1625 second_name = strdupW( buffer );
1627 family = create_family( family_name, second_name );
1629 if (second_name)
1631 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1632 subst->from.name = strdupW( second_name );
1633 subst->from.charset = -1;
1634 subst->to.name = strdupW(family_name);
1635 subst->to.charset = -1;
1636 add_font_subst(&font_subst_list, subst, 0);
1639 load_face(hkey_family, family, buffer, sizeof(buffer), TRUE);
1641 HeapFree( GetProcessHeap(), 0, family_name );
1642 HeapFree( GetProcessHeap(), 0, second_name );
1644 RegCloseKey(hkey_family);
1645 release_family( family );
1646 size = sizeof(buffer);
1649 reorder_vertical_fonts();
1652 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1654 LONG ret;
1655 HKEY hkey_wine_fonts;
1657 /* We don't want to create the fonts key as volatile, so open this first */
1658 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1659 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1660 if(ret != ERROR_SUCCESS)
1662 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1663 return ret;
1666 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1667 KEY_ALL_ACCESS, NULL, hkey, disposition);
1668 RegCloseKey(hkey_wine_fonts);
1669 return ret;
1672 static void add_face_to_cache(Face *face)
1674 HKEY hkey_family, hkey_face;
1675 DWORD len, buffer[1024];
1676 struct cached_face *cached = (struct cached_face *)buffer;
1678 RegCreateKeyExW( hkey_font_cache, face->family->family_name, 0, NULL, REG_OPTION_VOLATILE,
1679 KEY_ALL_ACCESS, NULL, &hkey_family, NULL );
1680 if (face->family->second_name[0])
1681 RegSetValueExW( hkey_family, NULL, 0, REG_SZ, (BYTE *)face->family->second_name,
1682 (strlenW( face->family->second_name ) + 1) * sizeof(WCHAR) );
1684 if (!face->scalable)
1686 static const WCHAR fmtW[] = {'%','d',0};
1687 WCHAR name[10];
1689 sprintfW( name, fmtW, face->size.y_ppem );
1690 RegCreateKeyExW( hkey_family, name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
1691 NULL, &hkey_face, NULL);
1693 else hkey_face = hkey_family;
1695 memset( cached, 0, sizeof(*cached) );
1696 cached->index = face->face_index;
1697 cached->flags = face->flags;
1698 cached->ntmflags = face->ntmFlags;
1699 cached->version = face->font_version;
1700 cached->fs = face->fs;
1701 if (!face->scalable)
1703 cached->width = face->size.width;
1704 cached->height = face->size.height;
1705 cached->size = face->size.size;
1706 cached->x_ppem = face->size.x_ppem;
1707 cached->y_ppem = face->size.y_ppem;
1708 cached->internal_leading = face->size.internal_leading;
1710 strcpyW( cached->full_name, face->full_name );
1711 len = strlenW( face->full_name ) + 1;
1712 strcpyW( cached->full_name + len, face->file );
1713 len += strlenW( face->file ) + 1;
1715 RegSetValueExW( hkey_face, face->style_name, 0, REG_BINARY, (BYTE *)cached,
1716 offsetof( struct cached_face, full_name[len] ));
1718 if (hkey_face != hkey_family) RegCloseKey(hkey_face);
1719 RegCloseKey(hkey_family);
1722 static void remove_face_from_cache( Face *face )
1724 HKEY hkey_family;
1726 RegOpenKeyExW( hkey_font_cache, face->family->family_name, 0, KEY_ALL_ACCESS, &hkey_family );
1728 if (face->scalable)
1730 RegDeleteValueW( hkey_family, face->style_name );
1732 else
1734 static const WCHAR fmtW[] = {'%','d',0};
1735 WCHAR name[10];
1736 sprintfW( name, fmtW, face->size.y_ppem );
1737 RegDeleteKeyW( hkey_family, name );
1739 RegCloseKey(hkey_family);
1742 static WCHAR *get_vertical_name( WCHAR *name )
1744 SIZE_T length;
1745 if (!name) return NULL;
1746 if (name[0] == '@') return name;
1748 length = strlenW( name ) + 1;
1749 name = HeapReAlloc( GetProcessHeap(), 0, name, (length + 1) * sizeof(WCHAR) );
1750 memmove( name + 1, name, length * sizeof(WCHAR) );
1751 name[0] = '@';
1752 return name;
1755 static Family *get_family( FT_Face ft_face, BOOL vertical )
1757 Family *family;
1758 WCHAR *family_name, *second_name;
1760 family_name = ft_face_get_family_name( ft_face, GetSystemDefaultLCID() );
1761 second_name = ft_face_get_family_name( ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) );
1763 /* try to find another secondary name, preferring the lowest langids */
1764 if (!strcmpiW( family_name, second_name ))
1766 HeapFree( GetProcessHeap(), 0, second_name );
1767 second_name = ft_face_get_family_name( ft_face, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) );
1770 if (!strcmpiW( family_name, second_name ))
1772 HeapFree( GetProcessHeap(), 0, second_name );
1773 second_name = NULL;
1776 if (vertical)
1778 family_name = get_vertical_name( family_name );
1779 second_name = get_vertical_name( second_name );
1782 if ((family = find_family_from_name( family_name ))) family->refcount++;
1783 else if ((family = create_family( family_name, second_name )) && second_name)
1785 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1786 subst->from.name = strdupW( second_name );
1787 subst->from.charset = -1;
1788 subst->to.name = strdupW( family_name );
1789 subst->to.charset = -1;
1790 add_font_subst( &font_subst_list, subst, 0 );
1793 HeapFree( GetProcessHeap(), 0, family_name );
1794 HeapFree( GetProcessHeap(), 0, second_name );
1796 return family;
1799 static inline FT_Fixed get_font_version( FT_Face ft_face )
1801 FT_Fixed version = 0;
1802 TT_Header *header;
1804 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1805 if (header) version = header->Font_Revision;
1807 return version;
1810 static inline DWORD get_ntm_flags( FT_Face ft_face )
1812 DWORD flags = 0;
1813 FT_ULong table_size = 0;
1814 FT_WinFNT_HeaderRec winfnt_header;
1816 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1817 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1819 /* fixup the flag for our fake-bold implementation. */
1820 if (!FT_IS_SCALABLE( ft_face ) &&
1821 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
1822 winfnt_header.weight > FW_NORMAL )
1823 flags |= NTM_BOLD;
1825 if (flags == 0) flags = NTM_REGULAR;
1827 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1828 flags |= NTM_PS_OPENTYPE;
1830 return flags;
1833 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1835 My_FT_Bitmap_Size *size;
1836 FT_WinFNT_HeaderRec winfnt_header;
1838 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1839 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1840 size->height, size->width, size->size >> 6,
1841 size->x_ppem >> 6, size->y_ppem >> 6);
1842 face_size->height = size->height;
1843 face_size->width = size->width;
1844 face_size->size = size->size;
1845 face_size->x_ppem = size->x_ppem;
1846 face_size->y_ppem = size->y_ppem;
1848 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
1849 face_size->internal_leading = winfnt_header.internal_leading;
1850 if (winfnt_header.external_leading > 0 &&
1851 (face_size->height ==
1852 winfnt_header.pixel_height + winfnt_header.external_leading))
1853 face_size->height = winfnt_header.pixel_height;
1857 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1859 TT_OS2 *os2;
1860 CHARSETINFO csi;
1861 FT_WinFNT_HeaderRec winfnt_header;
1862 int i;
1864 memset( fs, 0, sizeof(*fs) );
1866 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1867 if (os2)
1869 fs->fsUsb[0] = os2->ulUnicodeRange1;
1870 fs->fsUsb[1] = os2->ulUnicodeRange2;
1871 fs->fsUsb[2] = os2->ulUnicodeRange3;
1872 fs->fsUsb[3] = os2->ulUnicodeRange4;
1874 if (os2->version == 0)
1876 if (os2->usFirstCharIndex >= 0xf000 && os2->usFirstCharIndex < 0xf100)
1877 fs->fsCsb[0] = FS_SYMBOL;
1878 else
1879 fs->fsCsb[0] = FS_LATIN1;
1881 else
1883 fs->fsCsb[0] = os2->ulCodePageRange1;
1884 fs->fsCsb[1] = os2->ulCodePageRange2;
1887 else
1889 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1891 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1892 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1893 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1894 *fs = csi.fs;
1898 if (fs->fsCsb[0] == 0)
1900 /* let's see if we can find any interesting cmaps */
1901 for (i = 0; i < ft_face->num_charmaps; i++)
1903 switch (ft_face->charmaps[i]->encoding)
1905 case FT_ENCODING_UNICODE:
1906 case FT_ENCODING_APPLE_ROMAN:
1907 fs->fsCsb[0] |= FS_LATIN1;
1908 break;
1909 case FT_ENCODING_MS_SYMBOL:
1910 fs->fsCsb[0] |= FS_SYMBOL;
1911 break;
1912 default:
1913 break;
1919 static Face *create_face( FT_Face ft_face, FT_Long face_index, const WCHAR *filename,
1920 void *font_data_ptr, DWORD font_data_size, DWORD flags )
1922 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1924 face->refcount = 1;
1925 face->style_name = ft_face_get_style_name( ft_face, GetSystemDefaultLangID() );
1926 face->full_name = ft_face_get_full_name( ft_face, GetSystemDefaultLangID() );
1927 if (flags & ADDFONT_VERTICAL_FONT) face->full_name = get_vertical_name( face->full_name );
1929 if (filename)
1931 face->file = strdupW( filename );
1932 face->font_data_ptr = NULL;
1933 face->font_data_size = 0;
1935 else
1937 face->file = NULL;
1938 face->font_data_ptr = font_data_ptr;
1939 face->font_data_size = font_data_size;
1942 face->face_index = face_index;
1943 get_fontsig( ft_face, &face->fs );
1944 face->ntmFlags = get_ntm_flags( ft_face );
1945 face->font_version = get_font_version( ft_face );
1947 if (FT_IS_SCALABLE( ft_face ))
1949 memset( &face->size, 0, sizeof(face->size) );
1950 face->scalable = TRUE;
1952 else
1954 get_bitmap_size( ft_face, &face->size );
1955 face->scalable = FALSE;
1958 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1959 face->flags = flags;
1960 face->family = NULL;
1961 face->cached_enum_data = NULL;
1963 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1964 face->fs.fsCsb[0], face->fs.fsCsb[1],
1965 face->fs.fsUsb[0], face->fs.fsUsb[1],
1966 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1968 return face;
1971 static void AddFaceToList(FT_Face ft_face, const WCHAR *file, void *font_data_ptr, DWORD font_data_size,
1972 FT_Long face_index, DWORD flags )
1974 Face *face;
1975 Family *family;
1977 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
1978 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
1980 if (insert_face_in_family_list( face, family ))
1982 if (flags & ADDFONT_ADD_TO_CACHE)
1983 add_face_to_cache( face );
1984 TRACE( "Added face %s to family %s\n", debugstr_w(face->full_name), debugstr_w(family->family_name) );
1986 release_face( face );
1987 release_family( family );
1990 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1991 FT_Long face_index, BOOL allow_bitmap )
1993 FT_Error err;
1994 TT_OS2 *pOS2;
1995 FT_Face ft_face;
1997 if (file)
1999 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2000 err = pFT_New_Face(library, file, face_index, &ft_face);
2002 else
2004 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2005 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2008 if (err != 0)
2010 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2011 return NULL;
2014 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2015 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < FT_VERSION_VALUE(2, 1, 9))
2017 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2018 goto fail;
2021 if (!FT_IS_SFNT( ft_face ))
2023 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2025 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2026 goto fail;
2029 else
2031 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2032 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2033 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2035 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2036 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2037 goto fail;
2040 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2041 we don't want to load these. */
2042 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2044 FT_ULong len = 0;
2046 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2048 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2049 goto fail;
2054 if (!ft_face->family_name || !ft_face->style_name)
2056 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2057 goto fail;
2060 return ft_face;
2061 fail:
2062 pFT_Done_Face( ft_face );
2063 return NULL;
2066 static INT AddFontToList(const WCHAR *dos_name, const char *unix_name, void *font_data_ptr,
2067 DWORD font_data_size, DWORD flags)
2069 FT_Face ft_face;
2070 FT_Long face_index = 0, num_faces;
2071 INT ret = 0;
2072 WCHAR *filename = NULL;
2074 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2075 assert(unix_name || !(flags & ADDFONT_EXTERNAL_FONT));
2077 #ifdef HAVE_CARBON_CARBON_H
2078 if(unix_name)
2080 char **mac_list = expand_mac_font(unix_name);
2081 if(mac_list)
2083 BOOL had_one = FALSE;
2084 char **cursor;
2085 for(cursor = mac_list; *cursor; cursor++)
2087 had_one = TRUE;
2088 AddFontToList(NULL, *cursor, NULL, 0, flags);
2089 HeapFree(GetProcessHeap(), 0, *cursor);
2091 HeapFree(GetProcessHeap(), 0, mac_list);
2092 if(had_one)
2093 return 1;
2096 #endif /* HAVE_CARBON_CARBON_H */
2098 if (!dos_name && unix_name) dos_name = filename = wine_get_dos_file_name( unix_name );
2100 do {
2101 FONTSIGNATURE fs;
2103 ft_face = new_ft_face( unix_name, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2104 if (!ft_face) break;
2106 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2108 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name));
2109 pFT_Done_Face(ft_face);
2110 break;
2113 AddFaceToList(ft_face, dos_name, font_data_ptr, font_data_size, face_index, flags);
2114 ++ret;
2116 get_fontsig(ft_face, &fs);
2117 if (fs.fsCsb[0] & FS_DBCS_MASK)
2119 AddFaceToList(ft_face, dos_name, font_data_ptr, font_data_size, face_index,
2120 flags | ADDFONT_VERTICAL_FONT);
2121 ++ret;
2124 num_faces = ft_face->num_faces;
2125 pFT_Done_Face(ft_face);
2126 } while(num_faces > ++face_index);
2127 HeapFree( GetProcessHeap(), 0, filename );
2128 return ret;
2131 static int add_font_resource( const WCHAR *file, DWORD flags )
2133 int ret = 0;
2134 char *unixname = wine_get_unix_file_name( file );
2136 if (unixname)
2138 ret = AddFontToList( file, unixname, NULL, 0, flags );
2139 HeapFree( GetProcessHeap(), 0, unixname );
2141 return ret;
2144 static int remove_font_resource( const WCHAR *file, DWORD flags )
2146 Family *family, *family_next;
2147 Face *face, *face_next;
2148 int count = 0;
2150 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2152 family->refcount++;
2153 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2155 if (!face->file) continue;
2156 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2157 if (!strcmpiW( face->file, file ))
2159 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2160 release_face( face );
2161 count++;
2164 release_family( family );
2166 return count;
2169 static void DumpFontList(void)
2171 Family *family;
2172 Face *face;
2174 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2175 TRACE( "Family: %s\n", debugstr_w(family->family_name) );
2176 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2177 TRACE( "\t%s\t%s\t%08x", debugstr_w(face->style_name), debugstr_w(face->full_name),
2178 face->fs.fsCsb[0] );
2179 if(!face->scalable)
2180 TRACE(" %d", face->size.height);
2181 TRACE("\n");
2186 static BOOL map_vertical_font_family(const WCHAR *orig, const WCHAR *repl, const Family *family)
2188 Face *face;
2189 BOOL ret = FALSE;
2190 WCHAR *at_orig, *at_repl = NULL;
2192 face = LIST_ENTRY(list_head(&family->faces), Face, entry);
2193 if (!face || !(face->fs.fsCsb[0] & FS_DBCS_MASK))
2194 return FALSE;
2196 at_orig = get_vertical_name( strdupW( orig ) );
2197 if (at_orig && !find_family_from_any_name(at_orig))
2199 at_repl = get_vertical_name( strdupW( repl ) );
2200 if (at_repl)
2201 ret = map_font_family(at_orig, at_repl);
2204 HeapFree(GetProcessHeap(), 0, at_orig);
2205 HeapFree(GetProcessHeap(), 0, at_repl);
2207 return ret;
2210 static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl)
2212 Family *family = find_family_from_any_name(repl);
2213 if (family != NULL)
2215 Family *new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2216 if (new_family != NULL)
2218 TRACE("mapping %s to %s\n", debugstr_w(repl), debugstr_w(orig));
2219 lstrcpynW( new_family->family_name, orig, LF_FACESIZE );
2220 new_family->second_name[0] = 0;
2221 list_init(&new_family->faces);
2222 new_family->replacement = &family->faces;
2223 list_add_tail(&font_list, &new_family->entry);
2225 if (repl[0] != '@')
2226 map_vertical_font_family(orig, repl, family);
2228 return TRUE;
2231 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl));
2232 return FALSE;
2235 /***********************************************************
2236 * The replacement list is a way to map an entire font
2237 * family onto another family. For example adding
2239 * [HKCU\Software\Wine\Fonts\Replacements]
2240 * "Wingdings"="Winedings"
2242 * would enumerate the Winedings font both as Winedings and
2243 * Wingdings. However if a real Wingdings font is present the
2244 * replacement does not take place.
2247 static void LoadReplaceList(void)
2249 HKEY hkey;
2250 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2251 LPWSTR value;
2252 LPVOID data;
2254 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2255 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2257 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2258 &valuelen, &datalen, NULL, NULL);
2260 valuelen++; /* returned value doesn't include room for '\0' */
2261 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2262 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2264 dlen = datalen;
2265 vlen = valuelen;
2266 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data, &dlen) == ERROR_SUCCESS)
2268 /* "NewName"="Oldname" */
2269 if(!find_family_from_any_name(value))
2271 if (type == REG_MULTI_SZ)
2273 WCHAR *replace = data;
2274 while(*replace)
2276 if (map_font_family(value, replace))
2277 break;
2278 replace += strlenW(replace) + 1;
2281 else if (type == REG_SZ)
2282 map_font_family(value, data);
2284 else
2285 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2287 /* reset dlen and vlen */
2288 dlen = datalen;
2289 vlen = valuelen;
2291 HeapFree(GetProcessHeap(), 0, data);
2292 HeapFree(GetProcessHeap(), 0, value);
2293 RegCloseKey(hkey);
2297 static const WCHAR *font_links_list[] =
2299 Lucida_Sans_Unicode,
2300 Microsoft_Sans_Serif,
2301 Tahoma
2304 static const struct font_links_defaults_list
2306 /* Keyed off substitution for "MS Shell Dlg" */
2307 const WCHAR *shelldlg;
2308 /* Maximum of four substitutes, plus terminating NULL pointer */
2309 const WCHAR *substitutes[5];
2310 } font_links_defaults_list[] =
2312 /* Non East-Asian */
2313 { Tahoma, /* FIXME unverified ordering */
2314 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2316 /* Below lists are courtesy of
2317 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2319 /* Japanese */
2320 { MS_UI_Gothic,
2321 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2323 /* Chinese Simplified */
2324 { SimSun,
2325 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2327 /* Korean */
2328 { Gulim,
2329 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2331 /* Chinese Traditional */
2332 { PMingLiU,
2333 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2338 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2340 SYSTEM_LINKS *font_link;
2342 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2344 if(!strncmpiW(font_link->font_name, name, LF_FACESIZE - 1))
2345 return font_link;
2348 return NULL;
2351 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2353 const WCHAR *value;
2354 int i;
2355 FontSubst *psub;
2356 Family *family;
2357 Face *face;
2358 const WCHAR *file;
2360 if (values)
2362 SYSTEM_LINKS *font_link;
2364 psub = get_font_subst(&font_subst_list, name, -1);
2365 /* Don't store fonts that are only substitutes for other fonts */
2366 if(psub)
2368 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2369 return;
2372 font_link = find_font_link(name);
2373 if (font_link == NULL)
2375 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2376 font_link->font_name = strdupW(name);
2377 list_init(&font_link->links);
2378 list_add_tail(&system_links, &font_link->entry);
2381 memset(&font_link->fs, 0, sizeof font_link->fs);
2382 for (i = 0; values[i] != NULL; i++)
2384 const struct list *face_list;
2385 CHILD_FONT *child_font;
2387 value = values[i];
2388 if (!strcmpiW(name,value))
2389 continue;
2390 psub = get_font_subst(&font_subst_list, value, -1);
2391 if(psub)
2392 value = psub->to.name;
2393 family = find_family_from_name(value);
2394 if (!family)
2395 continue;
2396 file = NULL;
2397 /* Use first extant filename for this Family */
2398 face_list = get_face_list_from_family(family);
2399 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2401 if (!face->file)
2402 continue;
2403 file = strrchrW(face->file, '\\');
2404 if (!file)
2405 file = face->file;
2406 else
2407 file++;
2408 break;
2410 if (!file)
2411 continue;
2412 face = find_face_from_filename(file, value);
2413 if(!face)
2415 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2416 continue;
2419 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2420 child_font->face = face;
2421 child_font->font = NULL;
2422 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2423 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2424 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2425 child_font->face->face_index);
2426 list_add_tail(&font_link->links, &child_font->entry);
2428 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2434 /*************************************************************
2435 * init_system_links
2437 static void init_system_links(void)
2439 HKEY hkey;
2440 DWORD type, max_val, max_data, val_len, data_len, index;
2441 WCHAR *value, *data;
2442 WCHAR *entry, *next;
2443 SYSTEM_LINKS *font_link, *system_font_link;
2444 CHILD_FONT *child_font;
2445 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2446 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2447 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2448 Face *face;
2449 FontSubst *psub;
2450 UINT i, j;
2452 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2454 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2455 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2456 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2457 val_len = max_val + 1;
2458 data_len = max_data;
2459 index = 0;
2460 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2462 psub = get_font_subst(&font_subst_list, value, -1);
2463 /* Don't store fonts that are only substitutes for other fonts */
2464 if(psub)
2466 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2467 goto next;
2469 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2470 font_link->font_name = strdupW(value);
2471 memset(&font_link->fs, 0, sizeof font_link->fs);
2472 list_init(&font_link->links);
2473 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2475 WCHAR *face_name;
2476 CHILD_FONT *child_font;
2478 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2480 next = entry + strlenW(entry) + 1;
2482 face_name = strchrW(entry, ',');
2483 if(face_name)
2485 *face_name++ = 0;
2486 while(isspaceW(*face_name))
2487 face_name++;
2489 psub = get_font_subst(&font_subst_list, face_name, -1);
2490 if(psub)
2491 face_name = psub->to.name;
2493 face = find_face_from_filename(entry, face_name);
2494 if(!face)
2496 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2497 continue;
2500 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2501 child_font->face = face;
2502 child_font->font = NULL;
2503 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2504 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2505 TRACE("Adding file %s index %ld\n",
2506 debugstr_w(child_font->face->file), child_font->face->face_index);
2507 list_add_tail(&font_link->links, &child_font->entry);
2509 list_add_tail(&system_links, &font_link->entry);
2510 next:
2511 val_len = max_val + 1;
2512 data_len = max_data;
2515 HeapFree(GetProcessHeap(), 0, value);
2516 HeapFree(GetProcessHeap(), 0, data);
2517 RegCloseKey(hkey);
2521 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2522 if (!psub) {
2523 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2524 goto skip_internal;
2527 for (i = 0; i < ARRAY_SIZE(font_links_defaults_list); i++)
2529 const FontSubst *psub2;
2530 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2532 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2534 for (j = 0; j < ARRAY_SIZE(font_links_list); j++)
2535 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2537 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2538 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2540 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2542 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2546 skip_internal:
2548 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2549 that Tahoma has */
2551 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2552 system_font_link->font_name = strdupW(System);
2553 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2554 list_init(&system_font_link->links);
2556 face = find_face_from_filename(tahoma_ttf, Tahoma);
2557 if(face)
2559 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2560 child_font->face = face;
2561 child_font->font = NULL;
2562 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2563 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2564 TRACE("Found Tahoma in %s index %ld\n",
2565 debugstr_w(child_font->face->file), child_font->face->face_index);
2566 list_add_tail(&system_font_link->links, &child_font->entry);
2568 font_link = find_font_link(Tahoma);
2569 if (font_link != NULL)
2571 CHILD_FONT *font_link_entry;
2572 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2574 CHILD_FONT *new_child;
2575 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2576 new_child->face = font_link_entry->face;
2577 new_child->font = NULL;
2578 new_child->face->refcount++;
2579 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2580 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2581 list_add_tail(&system_font_link->links, &new_child->entry);
2584 list_add_tail(&system_links, &system_font_link->entry);
2587 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2589 DIR *dir;
2590 struct dirent *dent;
2591 char path[MAX_PATH];
2593 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2595 dir = opendir(dirname);
2596 if(!dir) {
2597 WARN("Can't open directory %s\n", debugstr_a(dirname));
2598 return FALSE;
2600 while((dent = readdir(dir)) != NULL) {
2601 struct stat statbuf;
2603 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2604 continue;
2606 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2608 sprintf(path, "%s/%s", dirname, dent->d_name);
2610 if(stat(path, &statbuf) == -1)
2612 WARN("Can't stat %s\n", debugstr_a(path));
2613 continue;
2615 if(S_ISDIR(statbuf.st_mode))
2616 ReadFontDir(path, external_fonts);
2617 else
2619 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2620 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2621 AddFontToList(NULL, path, NULL, 0, addfont_flags);
2624 closedir(dir);
2625 return TRUE;
2628 static void read_font_dir( const WCHAR *dirname, BOOL external_fonts )
2630 char *unixname = wine_get_unix_file_name( dirname );
2631 if (unixname)
2633 ReadFontDir( unixname, external_fonts );
2634 HeapFree( GetProcessHeap(), 0, unixname );
2638 #ifdef SONAME_LIBFONTCONFIG
2640 static BOOL fontconfig_enabled;
2642 static UINT parse_aa_pattern( FcPattern *pattern )
2644 FcBool antialias;
2645 int rgba;
2646 UINT aa_flags = 0;
2648 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2649 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2651 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2653 switch (rgba)
2655 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2656 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2657 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2658 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2659 case FC_RGBA_NONE: aa_flags = aa_flags ? aa_flags : GGO_GRAY4_BITMAP; break;
2662 return aa_flags;
2665 static void init_fontconfig(void)
2667 void *fc_handle = dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW);
2669 if (!fc_handle)
2671 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2672 return;
2675 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2676 LOAD_FUNCPTR(FcConfigSubstitute);
2677 LOAD_FUNCPTR(FcDefaultSubstitute);
2678 LOAD_FUNCPTR(FcFontList);
2679 LOAD_FUNCPTR(FcFontMatch);
2680 LOAD_FUNCPTR(FcFontSetDestroy);
2681 LOAD_FUNCPTR(FcInit);
2682 LOAD_FUNCPTR(FcPatternAddString);
2683 LOAD_FUNCPTR(FcPatternCreate);
2684 LOAD_FUNCPTR(FcPatternDestroy);
2685 LOAD_FUNCPTR(FcPatternGetBool);
2686 LOAD_FUNCPTR(FcPatternGetInteger);
2687 LOAD_FUNCPTR(FcPatternGetString);
2688 #undef LOAD_FUNCPTR
2690 if (pFcInit())
2692 FcPattern *pattern = pFcPatternCreate();
2693 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2694 default_aa_flags = parse_aa_pattern( pattern );
2695 pFcPatternDestroy( pattern );
2697 if (!default_aa_flags)
2699 FcPattern *pattern = pFcPatternCreate();
2700 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
2701 default_aa_flags = parse_aa_pattern( pattern );
2702 pFcPatternDestroy( pattern );
2705 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2706 fontconfig_enabled = TRUE;
2710 static void load_fontconfig_fonts(void)
2712 FcPattern *pat;
2713 FcFontSet *fontset;
2714 int i, len;
2715 char *file;
2716 const char *ext;
2718 if (!fontconfig_enabled) return;
2720 pat = pFcPatternCreate();
2721 if (!pat) return;
2723 fontset = pFcFontList(NULL, pat, NULL);
2724 if (!fontset)
2726 pFcPatternDestroy(pat);
2727 return;
2730 for(i = 0; i < fontset->nfont; i++) {
2731 FcBool scalable;
2732 DWORD aa_flags;
2734 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2735 continue;
2737 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2739 /* We're just interested in OT/TT fonts for now, so this hack just
2740 picks up the scalable fonts without extensions .pf[ab] to save time
2741 loading every other font */
2743 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2745 TRACE("not scalable\n");
2746 continue;
2749 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2750 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2752 len = strlen( file );
2753 if(len < 4) continue;
2754 ext = &file[ len - 3 ];
2755 if(_strnicmp(ext, "pfa", -1) && _strnicmp(ext, "pfb", -1))
2756 AddFontToList(NULL, file, NULL, 0,
2757 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2759 pFcFontSetDestroy(fontset);
2760 pFcPatternDestroy(pat);
2763 #elif defined(HAVE_CARBON_CARBON_H)
2765 static void load_mac_font_callback(const void *value, void *context)
2767 CFStringRef pathStr = value;
2768 CFIndex len;
2769 char* path;
2771 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2772 path = HeapAlloc(GetProcessHeap(), 0, len);
2773 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2775 TRACE("font file %s\n", path);
2776 AddFontToList(NULL, path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2778 HeapFree(GetProcessHeap(), 0, path);
2781 static void load_mac_fonts(void)
2783 CFStringRef removeDupesKey;
2784 CFBooleanRef removeDupesValue;
2785 CFDictionaryRef options;
2786 CTFontCollectionRef col;
2787 CFArrayRef descs;
2788 CFMutableSetRef paths;
2789 CFIndex i;
2791 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2792 removeDupesValue = kCFBooleanTrue;
2793 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2794 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2795 col = CTFontCollectionCreateFromAvailableFonts(options);
2796 if (options) CFRelease(options);
2797 if (!col)
2799 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2800 return;
2803 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2804 CFRelease(col);
2805 if (!descs)
2807 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2808 return;
2811 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2812 if (!paths)
2814 WARN("CFSetCreateMutable failed\n");
2815 CFRelease(descs);
2816 return;
2819 for (i = 0; i < CFArrayGetCount(descs); i++)
2821 CTFontDescriptorRef desc;
2822 CFURLRef url;
2823 CFStringRef ext;
2824 CFStringRef path;
2826 desc = CFArrayGetValueAtIndex(descs, i);
2828 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2829 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
2830 #else
2831 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
2832 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2834 CTFontRef font;
2835 ATSFontRef atsFont;
2836 OSStatus status;
2837 FSRef fsref;
2839 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2840 if (!font) continue;
2842 atsFont = CTFontGetPlatformFont(font, NULL);
2843 if (!atsFont)
2845 CFRelease(font);
2846 continue;
2849 status = ATSFontGetFileReference(atsFont, &fsref);
2850 CFRelease(font);
2851 if (status != noErr) continue;
2853 url = CFURLCreateFromFSRef(NULL, &fsref);
2855 #endif
2856 if (!url) continue;
2858 ext = CFURLCopyPathExtension(url);
2859 if (ext)
2861 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2862 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2863 CFRelease(ext);
2864 if (skip)
2866 CFRelease(url);
2867 continue;
2871 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2872 CFRelease(url);
2873 if (!path) continue;
2875 CFSetAddValue(paths, path);
2876 CFRelease(path);
2879 CFRelease(descs);
2881 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2882 CFRelease(paths);
2885 #endif
2887 static void get_font_dir( WCHAR *path )
2889 static const WCHAR slashW[] = {'\\',0};
2890 static const WCHAR fontsW[] = {'\\','f','o','n','t','s',0};
2891 static const WCHAR winedatadirW[] = {'W','I','N','E','D','A','T','A','D','I','R',0};
2892 static const WCHAR winebuilddirW[] = {'W','I','N','E','B','U','I','L','D','D','I','R',0};
2894 if (GetEnvironmentVariableW( winedatadirW, path, MAX_PATH ))
2896 const char fontdir[] = WINE_FONT_DIR;
2897 strcatW( path, slashW );
2898 MultiByteToWideChar( CP_ACP, 0, fontdir, -1, path + strlenW(path), MAX_PATH - strlenW(path) );
2900 else if (GetEnvironmentVariableW( winebuilddirW, path, MAX_PATH ))
2902 strcatW( path, fontsW );
2904 if (path[5] == ':') memmove( path, path + 4, (strlenW(path) - 3) * sizeof(WCHAR) );
2905 else path[1] = '\\'; /* change \??\ to \\?\ */
2908 static void get_data_dir_path( LPCWSTR file, WCHAR *path )
2910 static const WCHAR slashW[] = {'\\','\0'};
2912 get_font_dir( path );
2913 strcatW( path, slashW );
2914 strcatW( path, file );
2917 static void get_winfonts_dir_path(LPCWSTR file, WCHAR *path)
2919 static const WCHAR slashW[] = {'\\','\0'};
2921 GetWindowsDirectoryW(path, MAX_PATH);
2922 strcatW(path, fontsW);
2923 strcatW(path, slashW);
2924 strcatW(path, file);
2927 static void load_system_fonts(void)
2929 HKEY hkey;
2930 WCHAR data[MAX_PATH], pathW[MAX_PATH];
2931 const WCHAR * const *value;
2932 DWORD dlen, type;
2934 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2935 for(value = SystemFontValues; *value; value++) {
2936 dlen = sizeof(data);
2937 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2938 type == REG_SZ) {
2939 get_winfonts_dir_path( data, pathW );
2940 if (!add_font_resource( pathW, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE ))
2942 get_data_dir_path( data, pathW );
2943 add_font_resource( pathW, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE );
2947 RegCloseKey(hkey);
2951 static WCHAR *get_full_path_name(const WCHAR *name)
2953 WCHAR *full_path;
2954 DWORD len;
2956 if (!(len = GetFullPathNameW(name, 0, NULL, NULL)))
2958 ERR("GetFullPathNameW() failed, name %s.\n", debugstr_w(name));
2959 return NULL;
2962 if (!(full_path = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*full_path))))
2964 ERR("Could not get memory.\n");
2965 return NULL;
2968 if (GetFullPathNameW(name, len, full_path, NULL) != len - 1)
2970 ERR("Unexpected GetFullPathNameW() result, name %s.\n", debugstr_w(name));
2971 HeapFree(GetProcessHeap(), 0, full_path);
2972 return NULL;
2975 return full_path;
2978 /*************************************************************
2980 * This adds registry entries for any externally loaded fonts
2981 * (fonts from fontconfig or FontDirs). It also deletes entries
2982 * of no longer existing fonts.
2985 static void update_reg_entries(void)
2987 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2988 LPWSTR valueW;
2989 DWORD len;
2990 Family *family;
2991 Face *face;
2992 WCHAR *file, *path;
2993 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2995 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2996 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2997 ERR("Can't create Windows font reg key\n");
2998 goto end;
3001 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3002 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3003 ERR("Can't create Windows font reg key\n");
3004 goto end;
3007 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
3008 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
3009 ERR("Can't create external font reg key\n");
3010 goto end;
3013 /* enumerate the fonts and add external ones to the two keys */
3015 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
3016 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
3017 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
3019 len = strlenW( face->full_name ) + 1;
3020 if (face->scalable)
3021 len += ARRAY_SIZE(TrueType);
3023 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3024 strcpyW( valueW, face->full_name );
3026 if (face->scalable)
3027 strcatW(valueW, TrueType);
3029 if ((path = get_full_path_name(face->file)))
3031 file = path;
3033 else if ((file = strrchrW(face->file, '\\')))
3035 file++;
3037 else
3039 file = face->file;
3042 len = strlenW(file) + 1;
3043 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3044 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3045 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3047 HeapFree(GetProcessHeap(), 0, path);
3048 HeapFree(GetProcessHeap(), 0, valueW);
3051 end:
3052 if(external_key) RegCloseKey(external_key);
3053 if(win9x_key) RegCloseKey(win9x_key);
3054 if(winnt_key) RegCloseKey(winnt_key);
3057 static void delete_external_font_keys(void)
3059 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3060 DWORD dlen, plen, vlen, datalen, valuelen, i, type, path_type;
3061 LPWSTR valueW;
3062 LPVOID data;
3063 BYTE *path;
3065 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3066 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3067 ERR("Can't create Windows font reg key\n");
3068 goto end;
3071 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3072 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3073 ERR("Can't create Windows font reg key\n");
3074 goto end;
3077 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3078 ERR("Can't create external font reg key\n");
3079 goto end;
3082 /* Delete all external fonts added last time */
3084 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3085 &valuelen, &datalen, NULL, NULL);
3086 valuelen++; /* returned value doesn't include room for '\0' */
3087 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3088 data = HeapAlloc(GetProcessHeap(), 0, datalen);
3089 path = HeapAlloc(GetProcessHeap(), 0, datalen);
3091 dlen = datalen;
3092 vlen = valuelen;
3093 i = 0;
3094 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3095 &dlen) == ERROR_SUCCESS) {
3096 plen = dlen;
3097 if (RegQueryValueExW(winnt_key, valueW, 0, &path_type, path, &plen) == ERROR_SUCCESS &&
3098 type == path_type && dlen == plen && !memcmp(data, path, plen))
3099 RegDeleteValueW(winnt_key, valueW);
3101 plen = dlen;
3102 if (RegQueryValueExW(win9x_key, valueW, 0, &path_type, path, &plen) == ERROR_SUCCESS &&
3103 type == path_type && dlen == plen && !memcmp(data, path, plen))
3104 RegDeleteValueW(win9x_key, valueW);
3106 /* reset dlen and vlen */
3107 dlen = datalen;
3108 vlen = valuelen;
3110 HeapFree(GetProcessHeap(), 0, path);
3111 HeapFree(GetProcessHeap(), 0, data);
3112 HeapFree(GetProcessHeap(), 0, valueW);
3114 /* Delete the old external fonts key */
3115 RegCloseKey(external_key);
3116 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3118 end:
3119 if(win9x_key) RegCloseKey(win9x_key);
3120 if(winnt_key) RegCloseKey(winnt_key);
3123 /*************************************************************
3124 * freetype_AddFontResourceEx
3127 static INT CDECL freetype_AddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3129 WCHAR path[MAX_PATH];
3130 INT ret = 0;
3131 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3133 EnterCriticalSection( &freetype_cs );
3135 if (!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3136 if (GetFullPathNameW( file, MAX_PATH, path, NULL ))
3137 ret = add_font_resource( path, addfont_flags );
3139 if (!ret && !strchrW(file, '\\')) {
3140 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3141 get_winfonts_dir_path( file, path );
3142 ret = add_font_resource( path, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3143 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3144 if (!ret)
3146 get_data_dir_path( file, path );
3147 ret = add_font_resource( path, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3151 LeaveCriticalSection( &freetype_cs );
3152 return ret;
3155 /*************************************************************
3156 * freetype_AddFontMemResourceEx
3159 static HANDLE CDECL freetype_AddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3161 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3163 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3164 memcpy(pFontCopy, pbFont, cbFont);
3166 EnterCriticalSection( &freetype_cs );
3167 *pcFonts = AddFontToList(NULL, NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3168 LeaveCriticalSection( &freetype_cs );
3170 if (*pcFonts == 0)
3172 TRACE("AddFontToList failed\n");
3173 HeapFree(GetProcessHeap(), 0, pFontCopy);
3174 return 0;
3176 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3177 * For now return something unique but quite random
3179 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3180 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3183 /*************************************************************
3184 * freetype_RemoveFontResourceEx
3187 static BOOL CDECL freetype_RemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3189 WCHAR path[MAX_PATH];
3190 INT ret = 0;
3191 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3193 EnterCriticalSection( &freetype_cs );
3195 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3196 if (GetFullPathNameW( file, MAX_PATH, path, NULL ))
3197 ret = remove_font_resource( path, addfont_flags );
3199 if (!ret && !strchrW(file, '\\'))
3201 get_winfonts_dir_path( file, path );
3202 ret = remove_font_resource( path, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3203 if (!ret)
3205 get_data_dir_path( file, path );
3206 ret = remove_font_resource( path, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3210 LeaveCriticalSection( &freetype_cs );
3211 return ret;
3214 static WCHAR *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3216 WCHAR *fullname;
3217 int file_len;
3219 if (!font_file) return NULL;
3221 file_len = strlenW( font_file );
3223 if (font_path && font_path[0])
3225 int path_len = strlenW( font_path );
3226 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3227 if (!fullname) return NULL;
3228 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3229 fullname[path_len] = '\\';
3230 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3231 return fullname;
3233 return get_full_path_name( font_file );
3236 #include <pshpack1.h>
3237 struct fontdir
3239 WORD num_of_resources;
3240 WORD res_id;
3241 WORD dfVersion;
3242 DWORD dfSize;
3243 CHAR dfCopyright[60];
3244 WORD dfType;
3245 WORD dfPoints;
3246 WORD dfVertRes;
3247 WORD dfHorizRes;
3248 WORD dfAscent;
3249 WORD dfInternalLeading;
3250 WORD dfExternalLeading;
3251 BYTE dfItalic;
3252 BYTE dfUnderline;
3253 BYTE dfStrikeOut;
3254 WORD dfWeight;
3255 BYTE dfCharSet;
3256 WORD dfPixWidth;
3257 WORD dfPixHeight;
3258 BYTE dfPitchAndFamily;
3259 WORD dfAvgWidth;
3260 WORD dfMaxWidth;
3261 BYTE dfFirstChar;
3262 BYTE dfLastChar;
3263 BYTE dfDefaultChar;
3264 BYTE dfBreakChar;
3265 WORD dfWidthBytes;
3266 DWORD dfDevice;
3267 DWORD dfFace;
3268 DWORD dfReserved;
3269 CHAR szFaceName[LF_FACESIZE];
3272 #include <poppack.h>
3274 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3275 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3277 static BOOL get_fontdir( const WCHAR *dos_name, struct fontdir *fd )
3279 FT_Face ft_face;
3280 Face *face = NULL;
3281 char *unix_name;
3282 WCHAR *family_name;
3283 ENUMLOGFONTEXW elf;
3284 NEWTEXTMETRICEXW ntm;
3285 DWORD type;
3287 if (!(unix_name = wine_get_unix_file_name( dos_name ))) return FALSE;
3288 ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3289 HeapFree( GetProcessHeap(), 0, unix_name );
3290 if (!ft_face) return FALSE;
3291 face = create_face( ft_face, 0, dos_name, NULL, 0, 0 );
3292 if (face)
3294 family_name = ft_face_get_family_name( ft_face, GetSystemDefaultLCID() );
3295 GetEnumStructs( face, family_name, &elf, &ntm, &type );
3296 release_face( face );
3297 HeapFree( GetProcessHeap(), 0, family_name );
3299 pFT_Done_Face( ft_face );
3301 if (!face) return FALSE;
3302 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3304 memset( fd, 0, sizeof(*fd) );
3306 fd->num_of_resources = 1;
3307 fd->res_id = 0;
3308 fd->dfVersion = 0x200;
3309 fd->dfSize = sizeof(*fd);
3310 strcpy( fd->dfCopyright, "Wine fontdir" );
3311 fd->dfType = 0x4003; /* 0x0080 set if private */
3312 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3313 fd->dfVertRes = 72;
3314 fd->dfHorizRes = 72;
3315 fd->dfAscent = ntm.ntmTm.tmAscent;
3316 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3317 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3318 fd->dfItalic = ntm.ntmTm.tmItalic;
3319 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3320 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3321 fd->dfWeight = ntm.ntmTm.tmWeight;
3322 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3323 fd->dfPixWidth = 0;
3324 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3325 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3326 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3327 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3328 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3329 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3330 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3331 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3332 fd->dfWidthBytes = 0;
3333 fd->dfDevice = 0;
3334 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3335 fd->dfReserved = 0;
3336 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3338 return TRUE;
3341 #define NE_FFLAGS_LIBMODULE 0x8000
3342 #define NE_OSFLAGS_WINDOWS 0x02
3344 static const char dos_string[0x40] = "This is a TrueType resource file";
3345 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3347 #include <pshpack2.h>
3349 struct ne_typeinfo
3351 WORD type_id;
3352 WORD count;
3353 DWORD res;
3356 struct ne_nameinfo
3358 WORD off;
3359 WORD len;
3360 WORD flags;
3361 WORD id;
3362 DWORD res;
3365 struct rsrc_tab
3367 WORD align;
3368 struct ne_typeinfo fontdir_type;
3369 struct ne_nameinfo fontdir_name;
3370 struct ne_typeinfo scalable_type;
3371 struct ne_nameinfo scalable_name;
3372 WORD end_of_rsrc;
3373 BYTE fontdir_res_name[8];
3376 #include <poppack.h>
3378 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3380 BOOL ret = FALSE;
3381 HANDLE file;
3382 DWORD size, written;
3383 BYTE *ptr, *start;
3384 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3385 char *font_fileA, *last_part, *ext;
3386 IMAGE_DOS_HEADER dos;
3387 IMAGE_OS2_HEADER ne =
3389 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3390 0, 0, 0, 0, 0, 0,
3391 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3392 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3394 struct rsrc_tab rsrc_tab =
3397 { 0x8007, 1, 0 },
3398 { 0, 0, 0x0c50, 0x2c, 0 },
3399 { 0x80cc, 1, 0 },
3400 { 0, 0, 0x0c50, 0x8001, 0 },
3402 { 7,'F','O','N','T','D','I','R'}
3405 memset( &dos, 0, sizeof(dos) );
3406 dos.e_magic = IMAGE_DOS_SIGNATURE;
3407 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3409 /* import name is last part\0, resident name is last part without extension
3410 non-resident name is "FONTRES:" + lfFaceName */
3412 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3413 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3414 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3416 last_part = strrchr( font_fileA, '\\' );
3417 if (last_part) last_part++;
3418 else last_part = font_fileA;
3419 import_name_len = strlen( last_part ) + 1;
3421 ext = strchr( last_part, '.' );
3422 if (ext) res_name_len = ext - last_part;
3423 else res_name_len = import_name_len - 1;
3425 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3427 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3428 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3429 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3430 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3431 ne.ne_cbenttab = 2;
3432 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3434 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3435 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3436 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3437 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3439 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3440 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3442 if (!ptr)
3444 HeapFree( GetProcessHeap(), 0, font_fileA );
3445 return FALSE;
3448 memcpy( ptr, &dos, sizeof(dos) );
3449 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3450 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3452 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3453 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3455 ptr = start + dos.e_lfanew + ne.ne_restab;
3456 *ptr++ = res_name_len;
3457 memcpy( ptr, last_part, res_name_len );
3459 ptr = start + dos.e_lfanew + ne.ne_imptab;
3460 *ptr++ = import_name_len;
3461 memcpy( ptr, last_part, import_name_len );
3463 ptr = start + ne.ne_nrestab;
3464 *ptr++ = non_res_name_len;
3465 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3466 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3468 ptr = start + (rsrc_tab.scalable_name.off << 4);
3469 memcpy( ptr, font_fileA, font_file_len );
3471 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3472 memcpy( ptr, fontdir, fontdir->dfSize );
3474 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3475 if (file != INVALID_HANDLE_VALUE)
3477 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3478 ret = TRUE;
3479 CloseHandle( file );
3482 HeapFree( GetProcessHeap(), 0, start );
3483 HeapFree( GetProcessHeap(), 0, font_fileA );
3485 return ret;
3488 /*************************************************************
3489 * freetype_CreateScalableFontResource
3492 static BOOL CDECL freetype_CreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3493 LPCWSTR font_file, LPCWSTR font_path )
3495 WCHAR *filename = get_ttf_file_name( font_file, font_path );
3496 struct fontdir fontdir;
3497 BOOL ret = FALSE;
3499 if (!filename || !get_fontdir( filename, &fontdir ))
3500 SetLastError( ERROR_INVALID_PARAMETER );
3501 else
3503 if (hidden) fontdir.dfType |= 0x80;
3504 ret = create_fot( resource, font_file, &fontdir );
3507 HeapFree( GetProcessHeap(), 0, filename );
3508 return ret;
3511 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3513 return ( ansi_cp == 932 /* CP932 for Japanese */
3514 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3515 || ansi_cp == 949 /* CP949 for Korean */
3516 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3519 static BOOL init_freetype(void)
3521 ft_handle = dlopen(SONAME_LIBFREETYPE, RTLD_NOW);
3522 if(!ft_handle) {
3523 WINE_MESSAGE(
3524 "Wine cannot find the FreeType font library. To enable Wine to\n"
3525 "use TrueType fonts please install a version of FreeType greater than\n"
3526 "or equal to 2.0.5.\n"
3527 "http://www.freetype.org\n");
3528 return FALSE;
3531 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
3533 LOAD_FUNCPTR(FT_Done_Face)
3534 LOAD_FUNCPTR(FT_Get_Char_Index)
3535 LOAD_FUNCPTR(FT_Get_First_Char)
3536 LOAD_FUNCPTR(FT_Get_Next_Char)
3537 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3538 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3539 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3540 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3541 LOAD_FUNCPTR(FT_Init_FreeType)
3542 LOAD_FUNCPTR(FT_Library_Version)
3543 LOAD_FUNCPTR(FT_Load_Glyph)
3544 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3545 LOAD_FUNCPTR(FT_Matrix_Multiply)
3546 #ifndef FT_MULFIX_INLINED
3547 LOAD_FUNCPTR(FT_MulFix)
3548 #endif
3549 LOAD_FUNCPTR(FT_New_Face)
3550 LOAD_FUNCPTR(FT_New_Memory_Face)
3551 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3552 LOAD_FUNCPTR(FT_Outline_Get_CBox)
3553 LOAD_FUNCPTR(FT_Outline_Transform)
3554 LOAD_FUNCPTR(FT_Outline_Translate)
3555 LOAD_FUNCPTR(FT_Render_Glyph)
3556 LOAD_FUNCPTR(FT_Set_Charmap)
3557 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3558 LOAD_FUNCPTR(FT_Vector_Length)
3559 LOAD_FUNCPTR(FT_Vector_Transform)
3560 LOAD_FUNCPTR(FT_Vector_Unit)
3561 #undef LOAD_FUNCPTR
3562 /* Don't warn if these ones are missing */
3563 pFT_Outline_Embolden = dlsym(ft_handle, "FT_Outline_Embolden");
3564 pFT_Get_TrueType_Engine_Type = dlsym(ft_handle, "FT_Get_TrueType_Engine_Type");
3565 #ifdef FT_LCD_FILTER_H
3566 pFT_Library_SetLcdFilter = dlsym(ft_handle, "FT_Library_SetLcdFilter");
3567 #endif
3568 pFT_Property_Set = dlsym(ft_handle, "FT_Property_Set");
3570 if(pFT_Init_FreeType(&library) != 0) {
3571 ERR("Can't init FreeType library\n");
3572 dlclose(ft_handle);
3573 ft_handle = NULL;
3574 return FALSE;
3576 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3578 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3579 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3580 ((FT_Version.minor << 8) & 0x00ff00) |
3581 ((FT_Version.patch ) & 0x0000ff);
3583 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
3584 if (pFT_Property_Set && FT_SimpleVersion < FT_VERSION_VALUE(2, 8, 1))
3586 FT_UInt interpreter_version = 35;
3587 pFT_Property_Set( library, "truetype", "interpreter-version", &interpreter_version );
3590 return TRUE;
3592 sym_not_found:
3593 WINE_MESSAGE(
3594 "Wine cannot find certain functions that it needs inside the FreeType\n"
3595 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3596 "FreeType to at least version 2.1.4.\n"
3597 "http://www.freetype.org\n");
3598 dlclose(ft_handle);
3599 ft_handle = NULL;
3600 return FALSE;
3603 static void init_font_list(void)
3605 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3606 static const WCHAR pathW[] = {'P','a','t','h',0};
3607 HKEY hkey;
3608 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3609 WCHAR path[MAX_PATH];
3610 char *unixname;
3612 delete_external_font_keys();
3614 /* load the system bitmap fonts */
3615 load_system_fonts();
3617 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3618 GetWindowsDirectoryW(path, ARRAY_SIZE(path));
3619 strcatW(path, fontsW);
3620 read_font_dir( path, FALSE );
3622 /* load the wine fonts */
3623 get_font_dir( path );
3624 read_font_dir( path, TRUE );
3626 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3627 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3628 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3629 will skip these. */
3630 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3631 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3632 &hkey) == ERROR_SUCCESS)
3634 LPWSTR data, valueW;
3635 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3636 &valuelen, &datalen, NULL, NULL);
3638 valuelen++; /* returned value doesn't include room for '\0' */
3639 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3640 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3641 if (valueW && data)
3643 dlen = datalen * sizeof(WCHAR);
3644 vlen = valuelen;
3645 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3646 &dlen) == ERROR_SUCCESS)
3648 if(data[0] && (data[1] == ':'))
3650 add_font_resource( data, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3652 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3654 WCHAR pathW[MAX_PATH];
3656 get_winfonts_dir_path( data, pathW );
3657 if (!add_font_resource( pathW, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE ))
3659 get_data_dir_path( data, pathW );
3660 add_font_resource( pathW, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE );
3663 /* reset dlen and vlen */
3664 dlen = datalen;
3665 vlen = valuelen;
3668 HeapFree(GetProcessHeap(), 0, data);
3669 HeapFree(GetProcessHeap(), 0, valueW);
3670 RegCloseKey(hkey);
3673 #ifdef SONAME_LIBFONTCONFIG
3674 load_fontconfig_fonts();
3675 #elif defined(HAVE_CARBON_CARBON_H)
3676 load_mac_fonts();
3677 #elif defined(__ANDROID__)
3678 ReadFontDir("/system/fonts", TRUE);
3679 #endif
3681 /* then look in any directories that we've specified in the config file */
3682 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3683 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3685 DWORD len;
3686 LPWSTR valueW;
3687 LPSTR valueA, ptr;
3689 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3691 len += sizeof(WCHAR);
3692 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3693 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3695 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3696 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3697 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3698 TRACE( "got font path %s\n", debugstr_a(valueA) );
3699 ptr = valueA;
3700 while (ptr)
3702 const char* home;
3703 LPSTR next = strchr( ptr, ':' );
3704 if (next) *next++ = 0;
3705 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3706 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3708 strcpy( unixname, home );
3709 strcat( unixname, ptr + 1 );
3710 ReadFontDir( unixname, TRUE );
3711 HeapFree( GetProcessHeap(), 0, unixname );
3713 else
3714 ReadFontDir( ptr, TRUE );
3715 ptr = next;
3717 HeapFree( GetProcessHeap(), 0, valueA );
3719 HeapFree( GetProcessHeap(), 0, valueW );
3721 RegCloseKey(hkey);
3725 static BOOL move_to_front(const WCHAR *name)
3727 Family *family, *cursor2;
3728 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3730 if (!strncmpiW( family->family_name, name, LF_FACESIZE - 1 ))
3732 list_remove(&family->entry);
3733 list_add_head(&font_list, &family->entry);
3734 return TRUE;
3737 return FALSE;
3740 static const WCHAR *set_default(const WCHAR **name_list)
3742 const WCHAR **entry = name_list;
3744 while (*entry)
3746 if (move_to_front(*entry)) return *entry;
3747 entry++;
3750 return *name_list;
3753 static void reorder_font_list(void)
3755 default_serif = set_default( default_serif_list );
3756 default_fixed = set_default( default_fixed_list );
3757 default_sans = set_default( default_sans_list );
3760 /*************************************************************
3761 * WineEngInit
3763 * Initialize FreeType library and create a list of available faces
3765 BOOL WineEngInit( const struct font_backend_funcs **funcs )
3767 HKEY hkey;
3768 DWORD disposition;
3769 HANDLE font_mutex;
3771 if(!init_freetype()) return FALSE;
3773 #ifdef SONAME_LIBFONTCONFIG
3774 init_fontconfig();
3775 #endif
3777 *funcs = &font_funcs;
3779 if (!RegOpenKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, KEY_READ, &hkey))
3781 static const WCHAR antialias_fake_bold_or_italic[] = { 'A','n','t','i','a','l','i','a','s','F','a','k','e',
3782 'B','o','l','d','O','r','I','t','a','l','i','c',0 };
3783 static const WCHAR true_options[] = { 'y','Y','t','T','1',0 };
3784 DWORD type, size;
3785 WCHAR buffer[20];
3787 size = sizeof(buffer);
3788 if (!RegQueryValueExW(hkey, antialias_fake_bold_or_italic, NULL, &type, (BYTE*)buffer, &size) &&
3789 type == REG_SZ && size >= 1)
3791 antialias_fakes = (strchrW(true_options, buffer[0]) != NULL);
3793 RegCloseKey(hkey);
3796 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3798 ERR("Failed to create font mutex\n");
3799 return FALSE;
3801 WaitForSingleObject(font_mutex, INFINITE);
3803 create_font_cache_key(&hkey_font_cache, &disposition);
3805 if(disposition == REG_CREATED_NEW_KEY)
3806 init_font_list();
3807 else
3808 load_font_list_from_cache(hkey_font_cache);
3810 reorder_font_list();
3812 DumpFontList();
3813 LoadSubstList();
3814 DumpSubstList();
3815 LoadReplaceList();
3817 if(disposition == REG_CREATED_NEW_KEY)
3818 update_reg_entries();
3820 init_system_links();
3822 ReleaseMutex(font_mutex);
3823 return TRUE;
3826 /* Some fonts have large usWinDescent values, as a result of storing signed short
3827 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
3828 some font generation tools. */
3829 static inline USHORT get_fixed_windescent(USHORT windescent)
3831 return abs((SHORT)windescent);
3834 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3836 TT_OS2 *pOS2;
3837 TT_HoriHeader *pHori;
3839 LONG ppem;
3840 const LONG MAX_PPEM = (1 << 16) - 1;
3842 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3843 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3845 if(height == 0) height = 16;
3847 /* Calc. height of EM square:
3849 * For +ve lfHeight we have
3850 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3851 * Re-arranging gives:
3852 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3854 * For -ve lfHeight we have
3855 * |lfHeight| = ppem
3856 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3857 * with il = winAscent + winDescent - units_per_em]
3861 if(height > 0) {
3862 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
3863 if(pOS2->usWinAscent + windescent == 0)
3864 ppem = MulDiv(ft_face->units_per_EM, height,
3865 pHori->Ascender - pHori->Descender);
3866 else
3867 ppem = MulDiv(ft_face->units_per_EM, height,
3868 pOS2->usWinAscent + windescent);
3869 if(ppem > MAX_PPEM) {
3870 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
3871 ppem = 1;
3874 else if(height >= -MAX_PPEM)
3875 ppem = -height;
3876 else {
3877 WARN("Ignoring too large height %d\n", height);
3878 ppem = 1;
3881 return ppem;
3884 static struct font_mapping *map_font_file( const char *name )
3886 struct font_mapping *mapping;
3887 struct stat st;
3888 int fd;
3890 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3891 if (fstat( fd, &st ) == -1) goto error;
3893 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3895 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3897 mapping->refcount++;
3898 close( fd );
3899 return mapping;
3902 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3903 goto error;
3905 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3906 close( fd );
3908 if (mapping->data == MAP_FAILED)
3910 HeapFree( GetProcessHeap(), 0, mapping );
3911 return NULL;
3913 mapping->refcount = 1;
3914 mapping->dev = st.st_dev;
3915 mapping->ino = st.st_ino;
3916 mapping->size = st.st_size;
3917 list_add_tail( &mappings_list, &mapping->entry );
3918 return mapping;
3920 error:
3921 close( fd );
3922 return NULL;
3925 static void unmap_font_file( struct font_mapping *mapping )
3927 if (!--mapping->refcount)
3929 list_remove( &mapping->entry );
3930 munmap( mapping->data, mapping->size );
3931 HeapFree( GetProcessHeap(), 0, mapping );
3935 static LONG load_VDMX(GdiFont*, LONG);
3937 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3939 struct gdi_font *gdi_font = font->gdi_font;
3940 FT_Error err;
3941 FT_Face ft_face;
3942 void *data_ptr;
3943 DWORD data_size;
3945 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
3947 if (face->file)
3949 char *filename = wine_get_unix_file_name( face->file );
3950 font->mapping = map_font_file( filename );
3951 HeapFree( GetProcessHeap(), 0, filename );
3952 if (!font->mapping)
3954 WARN("failed to map %s\n", debugstr_w(face->file));
3955 return 0;
3957 data_ptr = font->mapping->data;
3958 data_size = font->mapping->size;
3960 else
3962 data_ptr = face->font_data_ptr;
3963 data_size = face->font_data_size;
3966 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3967 if(err) {
3968 ERR("FT_New_Face rets %d\n", err);
3969 return 0;
3972 /* set it here, as load_VDMX needs it */
3973 font->ft_face = ft_face;
3974 gdi_font->scalable = FT_IS_SCALABLE(ft_face);
3975 gdi_font->face_index = face->face_index;
3977 if(FT_IS_SCALABLE(ft_face)) {
3978 FT_ULong len;
3979 DWORD header;
3981 /* load the VDMX table if we have one */
3982 gdi_font->ppem = load_VDMX(font, height);
3983 if(gdi_font->ppem == 0)
3984 gdi_font->ppem = calc_ppem_for_height(ft_face, height);
3985 TRACE("height %d => ppem %d\n", height, gdi_font->ppem);
3987 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, gdi_font->ppem)) != 0)
3988 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, gdi_font->ppem, err);
3990 /* see if it's a TTC */
3991 len = sizeof(header);
3992 if (!pFT_Load_Sfnt_Table(ft_face, 0, 0, (void*)&header, &len)) {
3993 if (header == MS_TTCF_TAG)
3995 len = sizeof(font->ttc_item_offset);
3996 if (pFT_Load_Sfnt_Table(ft_face, 0, (3 + face->face_index) * sizeof(DWORD),
3997 (void*)&font->ttc_item_offset, &len))
3998 font->ttc_item_offset = 0;
3999 else
4000 font->ttc_item_offset = GET_BE_DWORD(font->ttc_item_offset);
4003 } else {
4004 gdi_font->ppem = height;
4005 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4006 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4008 return ft_face;
4012 static UINT get_nearest_charset(const WCHAR *family_name, Face *face, UINT *cp)
4014 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4015 a single face with the requested charset. The idea is to check if
4016 the selected font supports the current ANSI codepage, if it does
4017 return the corresponding charset, else return the first charset */
4019 CHARSETINFO csi;
4020 int acp = GetACP(), i;
4021 DWORD fs0;
4023 *cp = acp;
4024 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4026 const SYSTEM_LINKS *font_link;
4028 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4029 return csi.ciCharset;
4031 font_link = find_font_link(family_name);
4032 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4033 return csi.ciCharset;
4036 for(i = 0; i < 32; i++) {
4037 fs0 = 1L << i;
4038 if(face->fs.fsCsb[0] & fs0) {
4039 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4040 *cp = csi.ciACP;
4041 return csi.ciCharset;
4043 else
4044 FIXME("TCI failing on %x\n", fs0);
4048 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4049 face->fs.fsCsb[0], debugstr_w(face->file));
4050 *cp = acp;
4051 return DEFAULT_CHARSET;
4054 /*************************************************************
4055 * freetype_alloc_font
4057 static BOOL CDECL freetype_alloc_font( struct gdi_font *font )
4059 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4060 ret->potm = NULL;
4061 ret->total_kern_pairs = (DWORD)-1;
4062 ret->kern_pairs = NULL;
4063 list_init(&ret->child_fonts);
4064 ret->gdi_font = font;
4065 font->private = ret;
4066 return TRUE;
4069 /*************************************************************
4070 * freetype_destroy_font
4072 static void CDECL freetype_destroy_font( struct gdi_font *gdi_font )
4074 GdiFont *font = get_font_ptr( gdi_font );
4075 CHILD_FONT *child, *child_next;
4077 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4079 list_remove(&child->entry);
4080 if(child->font)
4081 free_gdi_font(child->font->gdi_font);
4082 release_face( child->face );
4083 HeapFree(GetProcessHeap(), 0, child);
4086 if (font->ft_face) pFT_Done_Face(font->ft_face);
4087 if (font->mapping) unmap_font_file( font->mapping );
4088 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4089 HeapFree(GetProcessHeap(), 0, font->potm);
4090 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4091 HeapFree(GetProcessHeap(), 0, font);
4094 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4096 FT_Face ft_face = font->ft_face;
4097 FT_ULong len;
4098 FT_Error err;
4100 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4102 if(!buf)
4103 len = 0;
4104 else
4105 len = cbData;
4107 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
4108 0 tag means to read from start of collection member data. */
4109 if (font->ttc_item_offset)
4111 if (table == MS_TTCF_TAG)
4112 table = 0;
4113 else if (table == 0)
4114 offset += font->ttc_item_offset;
4117 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4119 /* make sure value of len is the value freetype says it needs */
4120 if (buf && len)
4122 FT_ULong needed = 0;
4123 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4124 if( !err && needed < len) len = needed;
4126 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4127 if (err)
4129 table = RtlUlongByteSwap( table );
4130 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
4131 return GDI_ERROR;
4133 return len;
4136 /*************************************************************
4137 * load_VDMX
4139 * load the vdmx entry for the specified height
4144 typedef struct {
4145 WORD version;
4146 WORD numRecs;
4147 WORD numRatios;
4148 } VDMX_Header;
4150 typedef struct {
4151 BYTE bCharSet;
4152 BYTE xRatio;
4153 BYTE yStartRatio;
4154 BYTE yEndRatio;
4155 } Ratios;
4157 typedef struct {
4158 WORD recs;
4159 BYTE startsz;
4160 BYTE endsz;
4161 } VDMX_group;
4163 typedef struct {
4164 WORD yPelHeight;
4165 WORD yMax;
4166 WORD yMin;
4167 } VDMX_vTable;
4169 static LONG load_VDMX(GdiFont *font, LONG height)
4171 struct gdi_font *gdi_font = font->gdi_font;
4172 VDMX_Header hdr;
4173 VDMX_group group;
4174 BYTE devXRatio, devYRatio;
4175 USHORT numRecs, numRatios;
4176 DWORD result, offset = -1;
4177 LONG ppem = 0;
4178 int i;
4180 result = get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
4182 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4183 return ppem;
4185 /* FIXME: need the real device aspect ratio */
4186 devXRatio = 1;
4187 devYRatio = 1;
4189 numRecs = GET_BE_WORD(hdr.numRecs);
4190 numRatios = GET_BE_WORD(hdr.numRatios);
4192 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
4193 for(i = 0; i < numRatios; i++) {
4194 Ratios ratio;
4196 offset = sizeof(hdr) + (i * sizeof(Ratios));
4197 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4198 offset = -1;
4200 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4202 if (!ratio.bCharSet) continue;
4204 if((ratio.xRatio == 0 &&
4205 ratio.yStartRatio == 0 &&
4206 ratio.yEndRatio == 0) ||
4207 (devXRatio == ratio.xRatio &&
4208 devYRatio >= ratio.yStartRatio &&
4209 devYRatio <= ratio.yEndRatio))
4211 WORD group_offset;
4213 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
4214 get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
4215 offset = GET_BE_WORD(group_offset);
4216 break;
4220 if(offset == -1) return 0;
4222 if(get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
4223 USHORT recs;
4224 BYTE startsz, endsz;
4225 WORD *vTable;
4227 recs = GET_BE_WORD(group.recs);
4228 startsz = group.startsz;
4229 endsz = group.endsz;
4231 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4233 vTable = HeapAlloc(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
4234 result = get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
4235 if(result == GDI_ERROR) {
4236 FIXME("Failed to retrieve vTable\n");
4237 goto end;
4240 if(height > 0) {
4241 for(i = 0; i < recs; i++) {
4242 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4243 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4244 ppem = GET_BE_WORD(vTable[i * 3]);
4246 if(yMax + -yMin == height) {
4247 gdi_font->yMax = yMax;
4248 gdi_font->yMin = yMin;
4249 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, gdi_font->yMax, gdi_font->yMin);
4250 break;
4252 if(yMax + -yMin > height) {
4253 if(--i < 0) {
4254 ppem = 0;
4255 goto end; /* failed */
4257 gdi_font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4258 gdi_font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4259 ppem = GET_BE_WORD(vTable[i * 3]);
4260 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, gdi_font->yMax, gdi_font->yMin);
4261 break;
4264 if(!gdi_font->yMax) {
4265 ppem = 0;
4266 TRACE("ppem not found for height %d\n", height);
4268 } else {
4269 ppem = -height;
4270 if(ppem < startsz || ppem > endsz)
4272 ppem = 0;
4273 goto end;
4276 for(i = 0; i < recs; i++) {
4277 USHORT yPelHeight;
4278 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4280 if(yPelHeight > ppem)
4282 ppem = 0;
4283 break; /* failed */
4286 if(yPelHeight == ppem) {
4287 gdi_font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4288 gdi_font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4289 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, gdi_font->yMax, gdi_font->yMin);
4290 break;
4294 end:
4295 HeapFree(GetProcessHeap(), 0, vTable);
4298 return ppem;
4301 /*************************************************************
4302 * create_child_font_list
4304 static BOOL create_child_font_list(GdiFont *font)
4306 struct gdi_font *gdi_font = font->gdi_font;
4307 BOOL ret = FALSE;
4308 SYSTEM_LINKS *font_link;
4309 CHILD_FONT *font_link_entry, *new_child;
4310 FontSubst *psub;
4311 WCHAR* font_name;
4313 psub = get_font_subst(&font_subst_list, gdi_font->name, -1);
4314 font_name = psub ? psub->to.name : gdi_font->name;
4315 font_link = find_font_link(font_name);
4316 if (font_link != NULL)
4318 TRACE("found entry in system list\n");
4319 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4321 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4322 new_child->face = font_link_entry->face;
4323 new_child->font = NULL;
4324 new_child->face->refcount++;
4325 list_add_tail(&font->child_fonts, &new_child->entry);
4326 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4328 ret = TRUE;
4331 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4332 * Sans Serif. This is how asian windows get default fallbacks for fonts
4334 if (is_dbcs_ansi_cp(GetACP()) && gdi_font->charset != SYMBOL_CHARSET &&
4335 gdi_font->charset != OEM_CHARSET &&
4336 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4338 font_link = find_font_link(szDefaultFallbackLink);
4339 if (font_link != NULL)
4341 TRACE("found entry in default fallback list\n");
4342 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4344 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4345 new_child->face = font_link_entry->face;
4346 new_child->font = NULL;
4347 new_child->face->refcount++;
4348 list_add_tail(&font->child_fonts, &new_child->entry);
4349 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4351 ret = TRUE;
4355 return ret;
4358 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4360 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4361 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4362 FT_Int i;
4364 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4366 for (i = 0; i < ft_face->num_charmaps; i++)
4368 if (ft_face->charmaps[i]->encoding == encoding)
4370 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4371 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4373 switch (ft_face->charmaps[i]->platform_id)
4375 default:
4376 cmap_def = ft_face->charmaps[i];
4377 break;
4378 case 0: /* Apple Unicode */
4379 cmap0 = ft_face->charmaps[i];
4380 break;
4381 case 1: /* Macintosh */
4382 cmap1 = ft_face->charmaps[i];
4383 break;
4384 case 2: /* ISO */
4385 cmap2 = ft_face->charmaps[i];
4386 break;
4387 case 3: /* Microsoft */
4388 cmap3 = ft_face->charmaps[i];
4389 break;
4393 if (cmap3) /* prefer Microsoft cmap table */
4394 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4395 else if (cmap1)
4396 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4397 else if (cmap2)
4398 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4399 else if (cmap0)
4400 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4401 else if (cmap_def)
4402 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4405 return ft_err == FT_Err_Ok;
4409 static FT_Encoding pick_charmap( FT_Face face, int charset )
4411 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4412 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4413 const FT_Encoding *encs = regular_order;
4415 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4417 while (*encs != 0)
4419 if (select_charmap( face, *encs )) break;
4420 encs++;
4423 if (!face->charmap && face->num_charmaps)
4425 if (!pFT_Set_Charmap(face, face->charmaps[0]))
4426 return face->charmap->encoding;
4429 return *encs;
4432 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4434 DWORD size;
4435 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4436 WORD *alloced = NULL, *ptr = buf;
4437 WORD num_recs, version;
4438 BOOL ret = FALSE;
4440 *flags = 0;
4441 size = get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
4442 if (size == GDI_ERROR) return FALSE;
4443 if (size < 4 * sizeof(WORD)) return FALSE;
4444 if (size > sizeof(buf))
4446 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4447 if (!ptr) return FALSE;
4450 get_font_data( font, MS_GASP_TAG, 0, ptr, size );
4452 version = GET_BE_WORD( *ptr++ );
4453 num_recs = GET_BE_WORD( *ptr++ );
4455 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4457 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4458 goto done;
4461 while (num_recs--)
4463 *flags = GET_BE_WORD( *(ptr + 1) );
4464 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4465 ptr += 2;
4467 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4468 ret = TRUE;
4470 done:
4471 HeapFree( GetProcessHeap(), 0, alloced );
4472 return ret;
4475 #ifdef SONAME_LIBFONTCONFIG
4476 static Family* get_fontconfig_family(DWORD pitch_and_family, const CHARSETINFO *csi, BOOL want_vertical)
4478 const char *name;
4479 WCHAR nameW[LF_FACESIZE];
4480 FcChar8 *str;
4481 FcPattern *pat = NULL, *best = NULL;
4482 FcResult result;
4483 FcBool r;
4484 int ret, i;
4485 Family *family = NULL;
4487 if (!csi->fs.fsCsb[0]) return NULL;
4489 if((pitch_and_family & FIXED_PITCH) ||
4490 (pitch_and_family & 0xF0) == FF_MODERN)
4491 name = "monospace";
4492 else if((pitch_and_family & 0xF0) == FF_ROMAN)
4493 name = "serif";
4494 else
4495 name = "sans-serif";
4497 pat = pFcPatternCreate();
4498 if (!pat) return NULL;
4499 r = pFcPatternAddString(pat, FC_FAMILY, (const FcChar8 *)name);
4500 if (!r) goto end;
4501 r = pFcPatternAddString(pat, FC_NAMELANG, (const FcChar8 *)"en-us");
4502 if (!r) goto end;
4503 r = pFcPatternAddString(pat, FC_PRGNAME, (const FcChar8 *)"wine");
4504 if (!r) goto end;
4505 r = pFcConfigSubstitute(NULL, pat, FcMatchPattern);
4506 if (!r) goto end;
4507 pFcDefaultSubstitute(pat);
4509 best = pFcFontMatch(NULL, pat, &result);
4510 if (!best || result != FcResultMatch) goto end;
4512 for (i = 0;
4513 !family && pFcPatternGetString(best, FC_FAMILY, i, &str) == FcResultMatch;
4514 i++)
4516 Face *face;
4517 const SYSTEM_LINKS *font_link;
4518 const struct list *face_list;
4520 if (!want_vertical)
4522 ret = MultiByteToWideChar(CP_UTF8, 0, (const char*)str, -1,
4523 nameW, ARRAY_SIZE(nameW));
4525 else
4527 nameW[0] = '@';
4528 ret = MultiByteToWideChar(CP_UTF8, 0, (const char*)str, -1,
4529 nameW + 1, ARRAY_SIZE(nameW) - 1);
4531 if (!ret) continue;
4532 family = find_family_from_any_name(nameW);
4533 if (!family) continue;
4535 font_link = find_font_link( family->family_name );
4536 face_list = get_face_list_from_family(family);
4537 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4538 if (!face->scalable)
4539 continue;
4540 if (csi->fs.fsCsb[0] & face->fs.fsCsb[0])
4541 goto found;
4542 if (font_link != NULL &&
4543 csi->fs.fsCsb[0] & font_link->fs.fsCsb[0])
4544 goto found;
4546 family = NULL;
4549 found:
4550 if (family)
4551 TRACE("got %s\n", wine_dbgstr_w(nameW));
4553 end:
4554 pFcPatternDestroy(pat);
4555 pFcPatternDestroy(best);
4556 return family;
4558 #endif
4560 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4562 const GSUB_ScriptList *script;
4563 const GSUB_Script *deflt = NULL;
4564 int i;
4565 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4567 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4568 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4570 const GSUB_Script *scr;
4571 int offset;
4573 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4574 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4576 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4577 return scr;
4578 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4579 deflt = scr;
4581 return deflt;
4584 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4586 int i;
4587 int offset;
4588 const GSUB_LangSys *Lang;
4590 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4592 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4594 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4595 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4597 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4598 return Lang;
4600 offset = GET_BE_WORD(script->DefaultLangSys);
4601 if (offset)
4603 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4604 return Lang;
4606 return NULL;
4609 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4611 int i;
4612 const GSUB_FeatureList *feature;
4613 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4615 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4616 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4618 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4619 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4621 const GSUB_Feature *feat;
4622 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4623 return feat;
4626 return NULL;
4629 static const char* get_opentype_script(const struct gdi_font *font)
4632 * I am not sure if this is the correct way to generate our script tag
4635 switch (font->charset)
4637 case ANSI_CHARSET: return "latn";
4638 case BALTIC_CHARSET: return "latn"; /* ?? */
4639 case CHINESEBIG5_CHARSET: return "hani";
4640 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4641 case GB2312_CHARSET: return "hani";
4642 case GREEK_CHARSET: return "grek";
4643 case HANGUL_CHARSET: return "hang";
4644 case RUSSIAN_CHARSET: return "cyrl";
4645 case SHIFTJIS_CHARSET: return "kana";
4646 case TURKISH_CHARSET: return "latn"; /* ?? */
4647 case VIETNAMESE_CHARSET: return "latn";
4648 case JOHAB_CHARSET: return "latn"; /* ?? */
4649 case ARABIC_CHARSET: return "arab";
4650 case HEBREW_CHARSET: return "hebr";
4651 case THAI_CHARSET: return "thai";
4652 default: return "latn";
4656 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
4658 const GSUB_Header *header;
4659 const GSUB_Script *script;
4660 const GSUB_LangSys *language;
4661 const GSUB_Feature *feature;
4663 if (!font->GSUB_Table)
4664 return NULL;
4666 header = font->GSUB_Table;
4668 script = GSUB_get_script_table(header, get_opentype_script(font->gdi_font));
4669 if (!script)
4671 TRACE("Script not found\n");
4672 return NULL;
4674 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4675 if (!language)
4677 TRACE("Language not found\n");
4678 return NULL;
4680 feature = GSUB_get_feature(header, language, "vrt2");
4681 if (!feature)
4682 feature = GSUB_get_feature(header, language, "vert");
4683 if (!feature)
4685 TRACE("vrt2/vert feature not found\n");
4686 return NULL;
4688 return feature;
4691 /*************************************************************
4692 * freetype_SelectFont
4694 static struct gdi_font * CDECL freetype_SelectFont( DC *dc, HFONT hfont, UINT *aa_flags,
4695 UINT default_aa_flags )
4697 struct gdi_font *gdi_font;
4698 GdiFont *ret;
4699 Face *face, *best, *best_bitmap;
4700 Family *family, *last_resort_family;
4701 const struct list *face_list;
4702 INT height, width = 0;
4703 unsigned int score = 0, new_score;
4704 signed int diff = 0, newdiff;
4705 BOOL bd, it, can_use_bitmap, want_vertical;
4706 LOGFONTW lf;
4707 CHARSETINFO csi;
4708 FMAT2 dcmat;
4709 FontSubst *psub = NULL;
4710 const SYSTEM_LINKS *font_link;
4712 GetObjectW( hfont, sizeof(lf), &lf );
4713 lf.lfWidth = abs(lf.lfWidth);
4715 can_use_bitmap = !!(GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE);
4717 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4718 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4719 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4720 lf.lfEscapement);
4722 if(dc->GraphicsMode == GM_ADVANCED)
4724 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4725 /* Try to avoid not necessary glyph transformations */
4726 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4728 lf.lfHeight *= fabs(dcmat.eM11);
4729 lf.lfWidth *= fabs(dcmat.eM11);
4730 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4733 else
4735 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4736 font scaling abilities. */
4737 dcmat.eM11 = dcmat.eM22 = 1.0;
4738 dcmat.eM21 = dcmat.eM12 = 0;
4739 lf.lfOrientation = lf.lfEscapement;
4740 if (dc->vport2WorldValid)
4742 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4743 lf.lfOrientation = -lf.lfOrientation;
4744 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4745 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4749 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4750 dcmat.eM21, dcmat.eM22);
4752 EnterCriticalSection( &freetype_cs );
4754 /* check the cache first */
4755 if ((gdi_font = find_cached_gdi_font( &lf, &dcmat, can_use_bitmap ))) {
4756 ret = get_font_ptr( gdi_font );
4757 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4758 goto done;
4761 TRACE("not in cache\n");
4762 gdi_font = alloc_gdi_font();
4763 ret = get_font_ptr( gdi_font );
4765 gdi_font->matrix = dcmat;
4766 gdi_font->lf = lf;
4767 gdi_font->can_use_bitmap = can_use_bitmap;
4769 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4770 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4771 original value lfCharSet. Note this is a special case for
4772 Symbol and doesn't happen at least for "Wingdings*" */
4774 if(!strcmpiW(lf.lfFaceName, SymbolW))
4775 lf.lfCharSet = SYMBOL_CHARSET;
4777 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4778 switch(lf.lfCharSet) {
4779 case DEFAULT_CHARSET:
4780 csi.fs.fsCsb[0] = 0;
4781 break;
4782 default:
4783 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4784 csi.fs.fsCsb[0] = 0;
4785 break;
4789 family = NULL;
4790 if(lf.lfFaceName[0] != '\0') {
4791 CHILD_FONT *font_link_entry;
4792 LPWSTR FaceName = lf.lfFaceName;
4794 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4796 if(psub) {
4797 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4798 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4799 if (psub->to.charset != -1)
4800 lf.lfCharSet = psub->to.charset;
4803 /* We want a match on name and charset or just name if
4804 charset was DEFAULT_CHARSET. If the latter then
4805 we fixup the returned charset later in get_nearest_charset
4806 where we'll either use the charset of the current ansi codepage
4807 or if that's unavailable the first charset that the font supports.
4809 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4810 if (!strncmpiW( family->family_name, FaceName, LF_FACESIZE - 1 ) ||
4811 (psub && !strncmpiW( family->family_name, psub->to.name, LF_FACESIZE - 1 )))
4813 font_link = find_font_link( family->family_name );
4814 face_list = get_face_list_from_family(family);
4815 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4816 if (!(face->scalable || can_use_bitmap))
4817 continue;
4818 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4819 goto found;
4820 if (font_link != NULL &&
4821 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4822 goto found;
4823 if (!csi.fs.fsCsb[0])
4824 goto found;
4829 /* Search by full face name. */
4830 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4831 face_list = get_face_list_from_family(family);
4832 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4833 if (!strncmpiW( face->full_name, FaceName, LF_FACESIZE - 1 ) && (face->scalable || can_use_bitmap))
4835 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4836 goto found_face;
4837 font_link = find_font_link( family->family_name );
4838 if (font_link != NULL &&
4839 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4840 goto found_face;
4846 * Try check the SystemLink list first for a replacement font.
4847 * We may find good replacements there.
4849 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4851 if(!strncmpiW(font_link->font_name, FaceName, LF_FACESIZE - 1) ||
4852 (psub && !strncmpiW(font_link->font_name,psub->to.name, LF_FACESIZE - 1)))
4854 TRACE("found entry in system list\n");
4855 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4857 const SYSTEM_LINKS *links;
4859 face = font_link_entry->face;
4860 if (!(face->scalable || can_use_bitmap))
4861 continue;
4862 family = face->family;
4863 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4864 goto found;
4865 links = find_font_link( family->family_name );
4866 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4867 goto found;
4873 psub = NULL; /* substitution is no more relevant */
4875 /* If requested charset was DEFAULT_CHARSET then try using charset
4876 corresponding to the current ansi codepage */
4877 if (!csi.fs.fsCsb[0])
4879 INT acp = GetACP();
4880 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4881 FIXME("TCI failed on codepage %d\n", acp);
4882 csi.fs.fsCsb[0] = 0;
4883 } else
4884 lf.lfCharSet = csi.ciCharset;
4887 want_vertical = (lf.lfFaceName[0] == '@');
4889 /* Face families are in the top 4 bits of lfPitchAndFamily,
4890 so mask with 0xF0 before testing */
4892 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4893 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4894 strcpyW(lf.lfFaceName, default_fixed);
4895 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4896 strcpyW(lf.lfFaceName, default_serif);
4897 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4898 strcpyW(lf.lfFaceName, default_sans);
4899 else
4900 strcpyW(lf.lfFaceName, default_sans);
4901 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4902 if (!strncmpiW( family->family_name, lf.lfFaceName, LF_FACESIZE - 1 ))
4904 font_link = find_font_link( family->family_name );
4905 face_list = get_face_list_from_family(family);
4906 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4907 if (!(face->scalable || can_use_bitmap))
4908 continue;
4909 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4910 goto found;
4911 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4912 goto found;
4917 #ifdef SONAME_LIBFONTCONFIG
4918 /* Try FontConfig substitutions if the face isn't found */
4919 family = get_fontconfig_family(lf.lfPitchAndFamily, &csi, want_vertical);
4920 if (family) goto found;
4921 #endif
4923 last_resort_family = NULL;
4924 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4925 font_link = find_font_link( family->family_name );
4926 face_list = get_face_list_from_family(family);
4927 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4928 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
4929 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4930 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4931 if(face->scalable)
4932 goto found;
4933 if(can_use_bitmap && !last_resort_family)
4934 last_resort_family = family;
4939 if(last_resort_family) {
4940 family = last_resort_family;
4941 csi.fs.fsCsb[0] = 0;
4942 goto found;
4945 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4946 face_list = get_face_list_from_family(family);
4947 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4948 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
4949 csi.fs.fsCsb[0] = 0;
4950 WARN("just using first face for now\n");
4951 goto found;
4953 if(can_use_bitmap && !last_resort_family)
4954 last_resort_family = family;
4957 if(!last_resort_family) {
4958 FIXME("can't find a single appropriate font - bailing\n");
4959 free_gdi_font(gdi_font);
4960 ret = NULL;
4961 goto done;
4964 WARN("could only find a bitmap font - this will probably look awful!\n");
4965 family = last_resort_family;
4966 csi.fs.fsCsb[0] = 0;
4968 found:
4969 it = lf.lfItalic ? 1 : 0;
4970 bd = lf.lfWeight > 550 ? 1 : 0;
4972 height = lf.lfHeight;
4974 face = best = best_bitmap = NULL;
4975 font_link = find_font_link( family->family_name );
4976 face_list = get_face_list_from_family(family);
4977 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4979 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4980 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4981 !csi.fs.fsCsb[0])
4983 BOOL italic, bold;
4985 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4986 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4987 new_score = (italic ^ it) + (bold ^ bd);
4988 if(!best || new_score <= score)
4990 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4991 italic, bold, it, bd);
4992 score = new_score;
4993 best = face;
4994 if(best->scalable && score == 0) break;
4995 if(!best->scalable)
4997 if(height > 0)
4998 newdiff = height - (signed int)(best->size.height);
4999 else
5000 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5001 if(!best_bitmap || new_score < score ||
5002 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5004 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5005 diff = newdiff;
5006 best_bitmap = best;
5007 if(score == 0 && diff == 0) break;
5013 if(best)
5014 face = best->scalable ? best : best_bitmap;
5015 gdi_font->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5016 gdi_font->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5018 found_face:
5019 height = lf.lfHeight;
5021 gdi_font->fs = face->fs;
5023 if(csi.fs.fsCsb[0]) {
5024 gdi_font->charset = lf.lfCharSet;
5025 gdi_font->codepage = csi.ciACP;
5027 else
5028 gdi_font->charset = get_nearest_charset( family->family_name, face, &gdi_font->codepage );
5030 TRACE( "Chosen: %s (%s/%p:%ld)\n", debugstr_w(face->full_name), debugstr_w(face->file),
5031 face->font_data_ptr, face->face_index );
5033 gdi_font->aveWidth = height ? lf.lfWidth : 0;
5035 if(!face->scalable) {
5036 /* Windows uses integer scaling factors for bitmap fonts */
5037 INT scale, scaled_height;
5038 struct gdi_font *cachedfont;
5040 /* FIXME: rotation of bitmap fonts is ignored */
5041 height = abs(GDI_ROUND( (double)height * gdi_font->matrix.eM22 ));
5042 if (gdi_font->aveWidth)
5043 gdi_font->aveWidth = (double)gdi_font->aveWidth * gdi_font->matrix.eM11;
5044 gdi_font->matrix.eM11 = gdi_font->matrix.eM22 = 1.0;
5045 dcmat.eM11 = dcmat.eM22 = 1.0;
5046 /* As we changed the matrix, we need to search the cache for the font again,
5047 * otherwise we might explode the cache. */
5048 if((cachedfont = find_cached_gdi_font( &lf, &dcmat, can_use_bitmap ))) {
5049 TRACE("Found cached font after non-scalable matrix rescale!\n");
5050 free_gdi_font( gdi_font );
5051 gdi_font = cachedfont;
5052 ret = get_font_ptr( gdi_font );
5053 goto done;
5056 if (height != 0) height = diff;
5057 height += face->size.height;
5059 scale = (height + face->size.height - 1) / face->size.height;
5060 scaled_height = scale * face->size.height;
5061 /* Only jump to the next height if the difference <= 25% original height */
5062 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5063 /* The jump between unscaled and doubled is delayed by 1 */
5064 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5065 gdi_font->scale_y = scale;
5067 width = face->size.x_ppem >> 6;
5068 height = face->size.y_ppem >> 6;
5070 TRACE("font scale y: %f\n", gdi_font->scale_y);
5072 ret->ft_face = OpenFontFace(ret, face, width, height);
5074 if (!ret->ft_face)
5076 free_gdi_font( gdi_font );
5077 ret = NULL;
5078 goto done;
5081 set_gdi_font_file_info( gdi_font, face->file, face->font_data_size );
5082 gdi_font->ntmFlags = face->ntmFlags;
5083 gdi_font->aa_flags = HIWORD( face->flags );
5085 pick_charmap( ret->ft_face, gdi_font->charset );
5087 set_gdi_font_name( gdi_font, psub ? psub->from.name : family->family_name );
5088 create_child_font_list(ret);
5090 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5092 int length = get_font_data(ret, MS_GSUB_TAG , 0, NULL, 0);
5093 if (length != GDI_ERROR)
5095 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5096 get_font_data(ret, MS_GSUB_TAG , 0, ret->GSUB_Table, length);
5097 TRACE("Loaded GSUB table of %i bytes\n",length);
5098 ret->vert_feature = get_GSUB_vert_feature(ret);
5099 if (!ret->vert_feature)
5101 TRACE("Vertical feature not found\n");
5102 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5103 ret->GSUB_Table = NULL;
5108 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5110 cache_gdi_font( gdi_font );
5111 done:
5112 if (ret)
5114 switch (lf.lfQuality)
5116 case NONANTIALIASED_QUALITY:
5117 case ANTIALIASED_QUALITY:
5118 if (!*aa_flags) *aa_flags = default_aa_flags;
5119 break;
5120 case CLEARTYPE_QUALITY:
5121 case CLEARTYPE_NATURAL_QUALITY:
5122 default:
5123 if (!*aa_flags) *aa_flags = gdi_font->aa_flags;
5124 if (!*aa_flags) *aa_flags = default_aa_flags;
5126 /* fixup the antialiasing flags for that font */
5127 switch (*aa_flags)
5129 case WINE_GGO_HRGB_BITMAP:
5130 case WINE_GGO_HBGR_BITMAP:
5131 case WINE_GGO_VRGB_BITMAP:
5132 case WINE_GGO_VBGR_BITMAP:
5133 if (is_subpixel_rendering_enabled()) break;
5134 *aa_flags = GGO_GRAY4_BITMAP;
5135 /* fall through */
5136 case GGO_GRAY2_BITMAP:
5137 case GGO_GRAY4_BITMAP:
5138 case GGO_GRAY8_BITMAP:
5139 case WINE_GGO_GRAY16_BITMAP:
5140 if ((!antialias_fakes || (!gdi_font->fake_bold && !gdi_font->fake_italic)) && is_hinting_enabled())
5142 WORD gasp_flags;
5143 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5145 TRACE( "font %s %d aa disabled by GASP\n",
5146 debugstr_w(lf.lfFaceName), lf.lfHeight );
5147 *aa_flags = GGO_BITMAP;
5152 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5154 LeaveCriticalSection( &freetype_cs );
5155 return gdi_font;
5158 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5160 HRSRC rsrc;
5161 HGLOBAL hMem;
5162 WCHAR *p;
5163 int i;
5165 id += IDS_FIRST_SCRIPT;
5166 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5167 if (!rsrc) return 0;
5168 hMem = LoadResource( gdi32_module, rsrc );
5169 if (!hMem) return 0;
5171 p = LockResource( hMem );
5172 id &= 0x000f;
5173 while (id--) p += *p + 1;
5175 i = min(LF_FACESIZE - 1, *p);
5176 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5177 buffer[i] = 0;
5178 return i;
5181 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
5183 return (ansi_cp == 874 /* Thai */
5184 || ansi_cp == 1255 /* Hebrew */
5185 || ansi_cp == 1256 /* Arabic */
5189 /***************************************************
5190 * create_enum_charset_list
5192 * This function creates charset enumeration list because in DEFAULT_CHARSET
5193 * case, the ANSI codepage's charset takes precedence over other charsets.
5194 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5195 * This function works as a filter other than DEFAULT_CHARSET case.
5197 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5199 CHARSETINFO csi;
5200 DWORD n = 0;
5202 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5203 csi.fs.fsCsb[0] != 0) {
5204 list->element[n].mask = csi.fs.fsCsb[0];
5205 list->element[n].charset = csi.ciCharset;
5206 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5207 n++;
5209 else { /* charset is DEFAULT_CHARSET or invalid. */
5210 INT acp, i;
5211 DWORD mask = 0;
5213 /* Set the current codepage's charset as the first element. */
5214 acp = GetACP();
5215 if (!is_complex_script_ansi_cp(acp) &&
5216 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5217 csi.fs.fsCsb[0] != 0) {
5218 list->element[n].mask = csi.fs.fsCsb[0];
5219 list->element[n].charset = csi.ciCharset;
5220 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5221 mask |= csi.fs.fsCsb[0];
5222 n++;
5225 /* Fill out left elements. */
5226 for (i = 0; i < 32; i++) {
5227 FONTSIGNATURE fs;
5228 fs.fsCsb[0] = 1L << i;
5229 fs.fsCsb[1] = 0;
5230 if (fs.fsCsb[0] & mask)
5231 continue; /* skip, already added. */
5232 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5233 continue; /* skip, this is an invalid fsCsb bit. */
5235 list->element[n].mask = fs.fsCsb[0];
5236 list->element[n].charset = csi.ciCharset;
5237 load_script_name( i, list->element[n].name );
5238 mask |= fs.fsCsb[0];
5239 n++;
5242 /* add catch all mask for remaining bits */
5243 if (~mask)
5245 list->element[n].mask = ~mask;
5246 list->element[n].charset = DEFAULT_CHARSET;
5247 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5248 n++;
5251 list->total = n;
5253 return n;
5256 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5257 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5259 struct gdi_font *gdi_font;
5260 GdiFont *font;
5261 LONG width, height;
5263 if (face->cached_enum_data)
5265 TRACE("Cached\n");
5266 *pelf = face->cached_enum_data->elf;
5267 *pntm = face->cached_enum_data->ntm;
5268 *ptype = face->cached_enum_data->type;
5269 return;
5272 gdi_font = alloc_gdi_font();
5273 font = get_font_ptr( gdi_font );
5275 if(face->scalable) {
5276 height = 100;
5277 width = 0;
5278 } else {
5279 height = face->size.y_ppem >> 6;
5280 width = face->size.x_ppem >> 6;
5283 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5285 free_gdi_font(gdi_font);
5286 return;
5289 set_gdi_font_name( gdi_font, family_name );
5290 gdi_font->ntmFlags = face->ntmFlags;
5292 if (get_outline_text_metrics(font))
5294 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5296 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5297 pntm->ntmTm.ntmCellHeight = gdi_font->ntmCellHeight;
5298 pntm->ntmTm.ntmAvgWidth = gdi_font->ntmAvgWidth;
5300 lstrcpynW(pelf->elfLogFont.lfFaceName,
5301 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5302 LF_FACESIZE);
5303 lstrcpynW(pelf->elfFullName,
5304 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5305 LF_FULLFACESIZE);
5306 lstrcpynW(pelf->elfStyle,
5307 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5308 LF_FACESIZE);
5310 else
5312 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5314 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5315 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5316 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5318 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5319 lstrcpynW( pelf->elfFullName, face->full_name, LF_FULLFACESIZE );
5320 lstrcpynW( pelf->elfStyle, face->style_name, LF_FACESIZE );
5323 pntm->ntmTm.ntmFlags = face->ntmFlags;
5324 pntm->ntmFontSig = face->fs;
5326 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5328 pelf->elfLogFont.lfEscapement = 0;
5329 pelf->elfLogFont.lfOrientation = 0;
5330 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5331 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5332 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5333 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5334 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5335 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5336 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5337 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5338 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5339 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5340 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5342 *ptype = 0;
5343 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5344 *ptype |= TRUETYPE_FONTTYPE;
5345 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5346 *ptype |= DEVICE_FONTTYPE;
5347 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5348 *ptype |= RASTER_FONTTYPE;
5350 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5351 if (face->cached_enum_data)
5353 face->cached_enum_data->elf = *pelf;
5354 face->cached_enum_data->ntm = *pntm;
5355 face->cached_enum_data->type = *ptype;
5358 free_gdi_font(gdi_font);
5361 static BOOL family_matches(Family *family, const WCHAR *face_name)
5363 Face *face;
5364 const struct list *face_list;
5366 if (!strncmpiW( face_name, family->family_name, LF_FACESIZE - 1 )) return TRUE;
5368 face_list = get_face_list_from_family(family);
5369 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5370 if (!strncmpiW( face_name, face->full_name, LF_FACESIZE - 1 )) return TRUE;
5372 return FALSE;
5375 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
5377 if (!strncmpiW(face_name, family_name, LF_FACESIZE - 1)) return TRUE;
5378 return !strncmpiW( face_name, face->full_name, LF_FACESIZE - 1 );
5381 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5382 FONTENUMPROCW proc, LPARAM lparam, const WCHAR *subst)
5384 ENUMLOGFONTEXW elf;
5385 NEWTEXTMETRICEXW ntm;
5386 DWORD type = 0;
5387 DWORD i;
5389 GetEnumStructs( face, face->family->family_name, &elf, &ntm, &type );
5390 for(i = 0; i < list->total; i++) {
5391 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5392 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5393 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5394 i = list->total; /* break out of loop after enumeration */
5396 else
5398 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5399 /* use the DEFAULT_CHARSET case only if no other charset is present */
5400 if (list->element[i].charset == DEFAULT_CHARSET &&
5401 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5402 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5403 strcpyW(elf.elfScript, list->element[i].name);
5404 if (!elf.elfScript[0])
5405 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5407 /* Font Replacement */
5408 if (family != face->family)
5410 lstrcpynW( elf.elfLogFont.lfFaceName, family->family_name, LF_FACESIZE );
5411 lstrcpynW( elf.elfFullName, face->full_name, LF_FULLFACESIZE );
5413 if (subst)
5414 strcpyW(elf.elfLogFont.lfFaceName, subst);
5415 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5416 debugstr_w(elf.elfLogFont.lfFaceName),
5417 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5418 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5419 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5420 ntm.ntmTm.ntmFlags);
5421 /* release section before callback (FIXME) */
5422 LeaveCriticalSection( &freetype_cs );
5423 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5424 EnterCriticalSection( &freetype_cs );
5426 return TRUE;
5429 /*************************************************************
5430 * freetype_EnumFonts
5432 static BOOL CDECL freetype_EnumFonts( LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5434 Family *family;
5435 Face *face;
5436 const struct list *face_list;
5437 LOGFONTW lf;
5438 struct enum_charset_list enum_charsets;
5440 if (!plf)
5442 lf.lfCharSet = DEFAULT_CHARSET;
5443 lf.lfPitchAndFamily = 0;
5444 lf.lfFaceName[0] = 0;
5445 plf = &lf;
5448 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5450 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5452 EnterCriticalSection( &freetype_cs );
5453 if(plf->lfFaceName[0]) {
5454 WCHAR *face_name = plf->lfFaceName;
5455 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5457 if(psub) {
5458 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5459 debugstr_w(psub->to.name));
5460 face_name = psub->to.name;
5463 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5464 if (!family_matches(family, face_name)) continue;
5465 face_list = get_face_list_from_family(family);
5466 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5467 if (!face_matches( family->family_name, face, face_name )) continue;
5468 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, psub ? psub->from.name : NULL)) return FALSE;
5471 } else {
5472 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5473 face_list = get_face_list_from_family(family);
5474 face = LIST_ENTRY(list_head(face_list), Face, entry);
5475 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, NULL)) return FALSE;
5478 LeaveCriticalSection( &freetype_cs );
5479 return TRUE;
5482 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5484 pt->x.value = vec->x >> 6;
5485 pt->x.fract = (vec->x & 0x3f) << 10;
5486 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5487 pt->y.value = vec->y >> 6;
5488 pt->y.fract = (vec->y & 0x3f) << 10;
5489 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5492 /***************************************************
5493 * According to the MSDN documentation on WideCharToMultiByte,
5494 * certain codepages cannot set the default_used parameter.
5495 * This returns TRUE if the codepage can set that parameter, false else
5496 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5498 static BOOL codepage_sets_default_used(UINT codepage)
5500 switch (codepage)
5502 case CP_UTF7:
5503 case CP_UTF8:
5504 case CP_SYMBOL:
5505 return FALSE;
5506 default:
5507 return TRUE;
5512 * GSUB Table handling functions
5515 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5517 const GSUB_CoverageFormat1* cf1;
5519 cf1 = table;
5521 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5523 int count = GET_BE_WORD(cf1->GlyphCount);
5524 int i;
5525 TRACE("Coverage Format 1, %i glyphs\n",count);
5526 for (i = 0; i < count; i++)
5527 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5528 return i;
5529 return -1;
5531 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5533 const GSUB_CoverageFormat2* cf2;
5534 int i;
5535 int count;
5536 cf2 = (const GSUB_CoverageFormat2*)cf1;
5538 count = GET_BE_WORD(cf2->RangeCount);
5539 TRACE("Coverage Format 2, %i ranges\n",count);
5540 for (i = 0; i < count; i++)
5542 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5543 return -1;
5544 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5545 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5547 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5548 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5551 return -1;
5553 else
5554 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5556 return -1;
5559 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5561 int i;
5562 int offset;
5563 const GSUB_LookupList *lookup;
5564 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5566 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5567 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5569 const GSUB_LookupTable *look;
5570 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5571 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5572 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5573 if (GET_BE_WORD(look->LookupType) != 1)
5574 FIXME("We only handle SubType 1\n");
5575 else
5577 int j;
5579 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5581 const GSUB_SingleSubstFormat1 *ssf1;
5582 offset = GET_BE_WORD(look->SubTable[j]);
5583 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5584 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5586 int offset = GET_BE_WORD(ssf1->Coverage);
5587 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5588 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5590 TRACE(" Glyph 0x%x ->",glyph);
5591 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5592 TRACE(" 0x%x\n",glyph);
5595 else
5597 const GSUB_SingleSubstFormat2 *ssf2;
5598 INT index;
5599 INT offset;
5601 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5602 offset = GET_BE_WORD(ssf1->Coverage);
5603 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5604 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5605 TRACE(" Coverage index %i\n",index);
5606 if (index != -1)
5608 TRACE(" Glyph is 0x%x ->",glyph);
5609 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5610 TRACE("0x%x\n",glyph);
5616 return glyph;
5620 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5622 const GSUB_Header *header;
5623 const GSUB_Feature *feature;
5625 if (!font->GSUB_Table)
5626 return glyph;
5628 header = font->GSUB_Table;
5629 feature = font->vert_feature;
5631 return GSUB_apply_feature(header, feature, glyph);
5634 static FT_UInt get_glyph_index_symbol(const GdiFont *font, UINT glyph)
5636 FT_UInt ret;
5638 if (glyph < 0x100) glyph += 0xf000;
5639 /* there are a number of old pre-Unicode "broken" TTFs, which
5640 do have symbols at U+00XX instead of U+f0XX */
5641 if (!(ret = pFT_Get_Char_Index(font->ft_face, glyph)))
5642 ret = pFT_Get_Char_Index(font->ft_face, glyph - 0xf000);
5644 return ret;
5647 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5649 struct gdi_font *gdi_font = font->gdi_font;
5650 FT_UInt ret;
5651 WCHAR wc;
5652 char buf;
5654 if (font->ft_face->charmap->encoding == FT_ENCODING_NONE)
5656 BOOL default_used;
5657 BOOL *default_used_pointer;
5659 default_used_pointer = NULL;
5660 default_used = FALSE;
5661 if (codepage_sets_default_used(gdi_font->codepage))
5662 default_used_pointer = &default_used;
5663 wc = (WCHAR)glyph;
5664 if (!WideCharToMultiByte(gdi_font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) ||
5665 default_used)
5667 if (gdi_font->codepage == CP_SYMBOL)
5669 ret = get_glyph_index_symbol(font, glyph);
5670 if (!ret)
5672 if (WideCharToMultiByte(CP_ACP, 0, &wc, 1, &buf, 1, NULL, NULL))
5673 ret = get_glyph_index_symbol(font, buf);
5676 else
5677 ret = 0;
5679 else
5680 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5681 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
5682 return ret;
5685 if (font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5687 ret = get_glyph_index_symbol(font, glyph);
5688 if (!ret)
5690 wc = (WCHAR)glyph;
5691 if (WideCharToMultiByte(CP_ACP, 0, &wc, 1, &buf, 1, NULL, NULL))
5692 ret = get_glyph_index_symbol(font, (unsigned char)buf);
5694 return ret;
5697 return pFT_Get_Char_Index(font->ft_face, glyph);
5700 /* helper for freetype_GetGlyphIndices */
5701 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
5703 struct gdi_font *gdi_font = font->gdi_font;
5704 WCHAR wc = (WCHAR)glyph;
5705 BOOL default_used = FALSE;
5706 BOOL *default_used_pointer = NULL;
5707 FT_UInt ret;
5708 char buf;
5710 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
5711 return get_glyph_index(font, glyph);
5713 if (codepage_sets_default_used(gdi_font->codepage))
5714 default_used_pointer = &default_used;
5715 if(!WideCharToMultiByte(gdi_font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
5716 || default_used)
5718 if (gdi_font->codepage == CP_SYMBOL && wc < 0x100)
5719 ret = (unsigned char)wc;
5720 else
5721 ret = 0;
5723 else
5724 ret = (unsigned char)buf;
5725 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
5726 return ret;
5729 static FT_UInt get_default_char_index(GdiFont *font)
5731 FT_UInt default_char;
5733 if (FT_IS_SFNT(font->ft_face))
5735 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
5736 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
5738 else
5740 TEXTMETRICW textm;
5741 get_text_metrics(font, &textm);
5742 default_char = textm.tmDefaultChar;
5745 return default_char;
5748 /*************************************************************
5749 * freetype_GetGlyphIndices
5751 static DWORD CDECL freetype_GetGlyphIndices( struct gdi_font *gdi_font, LPCWSTR lpstr,
5752 INT count, LPWORD pgi, DWORD flags )
5754 GdiFont *font = get_font_ptr(gdi_font);
5755 int i;
5756 WORD default_char;
5757 BOOL got_default = FALSE;
5759 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5761 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5762 got_default = TRUE;
5765 EnterCriticalSection( &freetype_cs );
5767 for(i = 0; i < count; i++)
5769 pgi[i] = get_gdi_glyph_index(font, lpstr[i]);
5770 if (pgi[i] == 0)
5772 if (!got_default)
5774 default_char = get_default_char_index(font);
5775 got_default = TRUE;
5777 pgi[i] = default_char;
5779 else
5780 pgi[i] = get_GSUB_vert_glyph(font, pgi[i]);
5782 LeaveCriticalSection( &freetype_cs );
5783 return count;
5786 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5788 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5789 return !memcmp(matrix, &identity, sizeof(FMAT2));
5792 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5794 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5795 return !memcmp(matrix, &identity, sizeof(MAT2));
5798 static inline FT_Vector normalize_vector(FT_Vector *vec)
5800 FT_Vector out;
5801 FT_Fixed len;
5802 len = pFT_Vector_Length(vec);
5803 if (len) {
5804 out.x = (vec->x << 6) / len;
5805 out.y = (vec->y << 6) / len;
5807 else
5808 out.x = out.y = 0;
5809 return out;
5812 /* get_glyph_outline() glyph transform matrices index */
5813 enum matrices_index
5815 matrix_hori,
5816 matrix_vert,
5817 matrix_unrotated
5820 static BOOL get_transform_matrices( GdiFont *font, BOOL vertical, const MAT2 *user_transform,
5821 FT_Matrix matrices[3] )
5823 struct gdi_font *gdi_font = font->gdi_font;
5824 static const FT_Matrix identity_mat = { (1 << 16), 0, 0, (1 << 16) };
5825 BOOL needs_transform = FALSE;
5826 double width_ratio;
5827 int i;
5829 matrices[matrix_unrotated] = identity_mat;
5831 /* Scaling factor */
5832 if (gdi_font->aveWidth)
5834 TEXTMETRICW tm;
5835 get_text_metrics( font, &tm );
5837 width_ratio = (double)gdi_font->aveWidth;
5838 width_ratio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5840 else
5841 width_ratio = gdi_font->scale_y;
5843 /* Scaling transform */
5844 if (width_ratio != 1.0 || gdi_font->scale_y != 1.0)
5846 FT_Matrix scale_mat;
5847 scale_mat.xx = FT_FixedFromFloat( width_ratio );
5848 scale_mat.xy = 0;
5849 scale_mat.yx = 0;
5850 scale_mat.yy = FT_FixedFromFloat( gdi_font->scale_y );
5852 pFT_Matrix_Multiply( &scale_mat, &matrices[matrix_unrotated] );
5853 needs_transform = TRUE;
5856 /* Slant transform */
5857 if (gdi_font->fake_italic)
5859 FT_Matrix slant_mat;
5860 slant_mat.xx = (1 << 16);
5861 slant_mat.xy = (1 << 16) >> 2;
5862 slant_mat.yx = 0;
5863 slant_mat.yy = (1 << 16);
5865 pFT_Matrix_Multiply( &slant_mat, &matrices[matrix_unrotated] );
5866 needs_transform = TRUE;
5869 /* Rotation transform */
5870 matrices[matrix_hori] = matrices[matrix_unrotated];
5871 if (gdi_font->scalable && gdi_font->lf.lfOrientation % 3600)
5873 FT_Matrix rotation_mat;
5874 FT_Vector angle;
5876 pFT_Vector_Unit( &angle, MulDiv( 1 << 16, gdi_font->lf.lfOrientation, 10 ) );
5877 rotation_mat.xx = angle.x;
5878 rotation_mat.xy = -angle.y;
5879 rotation_mat.yx = angle.y;
5880 rotation_mat.yy = angle.x;
5881 pFT_Matrix_Multiply( &rotation_mat, &matrices[matrix_hori] );
5882 needs_transform = TRUE;
5885 /* Vertical transform */
5886 matrices[matrix_vert] = matrices[matrix_hori];
5887 if (vertical)
5889 FT_Matrix vertical_mat = { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
5891 pFT_Matrix_Multiply( &vertical_mat, &matrices[matrix_vert] );
5892 needs_transform = TRUE;
5895 /* World transform */
5896 if (!is_identity_FMAT2( &gdi_font->matrix ))
5898 FT_Matrix world_mat;
5899 world_mat.xx = FT_FixedFromFloat( gdi_font->matrix.eM11 );
5900 world_mat.xy = -FT_FixedFromFloat( gdi_font->matrix.eM21 );
5901 world_mat.yx = -FT_FixedFromFloat( gdi_font->matrix.eM12 );
5902 world_mat.yy = FT_FixedFromFloat( gdi_font->matrix.eM22 );
5904 for (i = 0; i < 3; i++)
5905 pFT_Matrix_Multiply( &world_mat, &matrices[i] );
5906 needs_transform = TRUE;
5909 /* Extra transformation specified by caller */
5910 if (!is_identity_MAT2( user_transform ))
5912 FT_Matrix user_mat;
5913 user_mat.xx = FT_FixedFromFIXED( user_transform->eM11 );
5914 user_mat.xy = FT_FixedFromFIXED( user_transform->eM21 );
5915 user_mat.yx = FT_FixedFromFIXED( user_transform->eM12 );
5916 user_mat.yy = FT_FixedFromFIXED( user_transform->eM22 );
5918 for (i = 0; i < 3; i++)
5919 pFT_Matrix_Multiply( &user_mat, &matrices[i] );
5920 needs_transform = TRUE;
5923 return needs_transform;
5926 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
5928 FT_Error err;
5929 FT_Pos strength;
5930 FT_BBox bbox;
5932 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
5933 return FALSE;
5934 if(!pFT_Outline_Embolden)
5935 return FALSE;
5937 strength = MulDiv(ppem, 1 << 6, 24);
5938 err = pFT_Outline_Embolden(&glyph->outline, strength);
5939 if(err) {
5940 TRACE("FT_Ouline_Embolden returns %d\n", err);
5941 return FALSE;
5944 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
5945 metrics->width = bbox.xMax - bbox.xMin;
5946 metrics->height = bbox.yMax - bbox.yMin;
5947 metrics->horiBearingX = bbox.xMin;
5948 metrics->horiBearingY = bbox.yMax;
5949 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
5950 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
5951 return TRUE;
5954 static inline BYTE get_max_level( UINT format )
5956 switch( format )
5958 case GGO_GRAY2_BITMAP: return 4;
5959 case GGO_GRAY4_BITMAP: return 16;
5960 case GGO_GRAY8_BITMAP: return 64;
5962 return 255;
5965 extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
5967 static BOOL check_unicode_tategaki(WCHAR uchar)
5969 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
5971 /* We only reach this code if typographical substitution did not occur */
5972 /* Type: U or Type: Tu */
5973 return (orientation == 1 || orientation == 3);
5976 static FT_Vector get_advance_metric(GdiFont *incoming_font, GdiFont *font,
5977 const FT_Glyph_Metrics *metrics,
5978 const FT_Matrix *transMat, BOOL vertical_metrics)
5980 struct gdi_font *incoming_gdi_font = incoming_font->gdi_font;
5981 struct gdi_font *gdi_font = font->gdi_font;
5982 FT_Vector adv;
5983 FT_Fixed base_advance, em_scale = 0;
5984 BOOL fixed_pitch_full = FALSE;
5986 if (vertical_metrics)
5987 base_advance = metrics->vertAdvance;
5988 else
5989 base_advance = metrics->horiAdvance;
5991 adv.x = base_advance;
5992 adv.y = 0;
5994 /* In fixed-pitch font, we adjust the fullwidth character advance so that
5995 they have double halfwidth character width. E.g. if the font is 19 ppem,
5996 we return 20 (not 19) for fullwidth characters as we return 10 for
5997 halfwidth characters. */
5998 if(incoming_gdi_font->scalable &&
5999 (incoming_font->potm || get_outline_text_metrics(incoming_font)) &&
6000 !(incoming_font->potm->otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6001 UINT avg_advance;
6002 em_scale = MulDiv(incoming_gdi_font->ppem, 1 << 16,
6003 incoming_font->ft_face->units_per_EM);
6004 avg_advance = pFT_MulFix(incoming_gdi_font->ntmAvgWidth, em_scale);
6005 fixed_pitch_full = (avg_advance > 0 &&
6006 (base_advance + 63) >> 6 ==
6007 pFT_MulFix(incoming_gdi_font->ntmAvgWidth*2, em_scale));
6008 if (fixed_pitch_full && !transMat)
6009 adv.x = (avg_advance * 2) << 6;
6012 if (transMat) {
6013 pFT_Vector_Transform(&adv, transMat);
6014 if (fixed_pitch_full && adv.y == 0) {
6015 FT_Vector vec;
6016 vec.x = incoming_gdi_font->ntmAvgWidth;
6017 vec.y = 0;
6018 pFT_Vector_Transform(&vec, transMat);
6019 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
6023 if (gdi_font->fake_bold) {
6024 if (!transMat)
6025 adv.x += 1 << 6;
6026 else {
6027 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
6028 pFT_Vector_Transform(&vec, transMat);
6029 fake_bold_adv = normalize_vector(&vec);
6030 adv.x += fake_bold_adv.x;
6031 adv.y += fake_bold_adv.y;
6035 adv.x = (adv.x + 63) & -64;
6036 adv.y = -((adv.y + 63) & -64);
6037 return adv;
6040 static FT_BBox get_transformed_bbox( const FT_Glyph_Metrics *metrics,
6041 BOOL needs_transform, const FT_Matrix metrices[3] )
6043 FT_BBox bbox = { 0, 0, 0, 0 };
6045 if (!needs_transform)
6047 bbox.xMin = (metrics->horiBearingX) & -64;
6048 bbox.xMax = (metrics->horiBearingX + metrics->width + 63) & -64;
6049 bbox.yMax = (metrics->horiBearingY + 63) & -64;
6050 bbox.yMin = (metrics->horiBearingY - metrics->height) & -64;
6052 else
6054 FT_Vector vec;
6055 INT xc, yc;
6057 for (xc = 0; xc < 2; xc++)
6059 for (yc = 0; yc < 2; yc++)
6061 vec.x = metrics->horiBearingX + xc * metrics->width;
6062 vec.y = metrics->horiBearingY - yc * metrics->height;
6063 TRACE( "Vec %ld,i %ld\n", vec.x, vec.y );
6064 pFT_Vector_Transform( &vec, &metrices[matrix_vert] );
6065 if (xc == 0 && yc == 0)
6067 bbox.xMin = bbox.xMax = vec.x;
6068 bbox.yMin = bbox.yMax = vec.y;
6070 else
6072 if (vec.x < bbox.xMin) bbox.xMin = vec.x;
6073 else if (vec.x > bbox.xMax) bbox.xMax = vec.x;
6074 if (vec.y < bbox.yMin) bbox.yMin = vec.y;
6075 else if (vec.y > bbox.yMax) bbox.yMax = vec.y;
6079 bbox.xMin = bbox.xMin & -64;
6080 bbox.xMax = (bbox.xMax + 63) & -64;
6081 bbox.yMin = bbox.yMin & -64;
6082 bbox.yMax = (bbox.yMax + 63) & -64;
6083 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox.xMin, bbox.yMax, bbox.xMax, bbox.yMin );
6086 return bbox;
6089 static void compute_metrics( GdiFont *incoming_font, GdiFont *font,
6090 FT_BBox bbox, const FT_Glyph_Metrics *metrics,
6091 BOOL vertical, BOOL vertical_metrics,
6092 BOOL needs_transform, const FT_Matrix matrices[3],
6093 GLYPHMETRICS *gm, ABC *abc )
6095 FT_Vector adv, vec, origin;
6097 if (!needs_transform)
6099 adv = get_advance_metric( incoming_font, font, metrics, NULL, vertical_metrics );
6100 gm->gmCellIncX = adv.x >> 6;
6101 gm->gmCellIncY = 0;
6102 origin.x = bbox.xMin;
6103 origin.y = bbox.yMax;
6104 abc->abcA = origin.x >> 6;
6105 abc->abcB = (metrics->width + 63) >> 6;
6107 else
6109 FT_Pos lsb;
6111 if (vertical && (font->potm || get_outline_text_metrics( font )))
6113 if (vertical_metrics)
6114 lsb = metrics->horiBearingY + metrics->vertBearingY;
6115 else
6116 lsb = metrics->vertAdvance + (font->potm->otmDescent << 6);
6117 vec.x = lsb;
6118 vec.y = font->potm->otmDescent << 6;
6119 TRACE( "Vec %ld,%ld\n", vec.x>>6, vec.y>>6 );
6120 pFT_Vector_Transform( &vec, &matrices[matrix_hori] );
6121 origin.x = (vec.x + bbox.xMin) & -64;
6122 origin.y = (vec.y + bbox.yMax + 63) & -64;
6123 lsb -= metrics->horiBearingY;
6125 else
6127 origin.x = bbox.xMin;
6128 origin.y = bbox.yMax;
6129 lsb = metrics->horiBearingX;
6132 adv = get_advance_metric( incoming_font, font, metrics, &matrices[matrix_hori],
6133 vertical_metrics );
6134 gm->gmCellIncX = adv.x >> 6;
6135 gm->gmCellIncY = adv.y >> 6;
6137 adv = get_advance_metric( incoming_font, font, metrics, &matrices[matrix_unrotated],
6138 vertical_metrics );
6139 adv.x = pFT_Vector_Length( &adv );
6140 adv.y = 0;
6142 vec.x = lsb;
6143 vec.y = 0;
6144 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
6145 if (lsb > 0) abc->abcA = pFT_Vector_Length( &vec ) >> 6;
6146 else abc->abcA = -((pFT_Vector_Length( &vec ) + 63) >> 6);
6148 /* We use lsb again to avoid rounding errors */
6149 vec.x = lsb + (vertical ? metrics->height : metrics->width);
6150 vec.y = 0;
6151 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
6152 abc->abcB = ((pFT_Vector_Length( &vec ) + 63) >> 6) - abc->abcA;
6154 if (!abc->abcB) abc->abcB = 1;
6155 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
6157 gm->gmptGlyphOrigin.x = origin.x >> 6;
6158 gm->gmptGlyphOrigin.y = origin.y >> 6;
6159 gm->gmBlackBoxX = (bbox.xMax - bbox.xMin) >> 6;
6160 gm->gmBlackBoxY = (bbox.yMax - bbox.yMin) >> 6;
6161 if (!gm->gmBlackBoxX) gm->gmBlackBoxX = 1;
6162 if (!gm->gmBlackBoxY) gm->gmBlackBoxY = 1;
6164 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
6165 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point(&gm->gmptGlyphOrigin),
6166 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
6170 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6172 static DWORD get_mono_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox,
6173 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
6174 DWORD buflen, BYTE *buf )
6176 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
6177 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
6178 DWORD pitch = ((width + 31) >> 5) << 2;
6179 DWORD needed = pitch * height;
6180 FT_Bitmap ft_bitmap;
6181 BYTE *src, *dst;
6182 INT w, h, x;
6184 if (!buf || !buflen) return needed;
6185 if (!needed) return GDI_ERROR; /* empty glyph */
6186 if (needed > buflen) return GDI_ERROR;
6188 switch (glyph->format)
6190 case FT_GLYPH_FORMAT_BITMAP:
6191 src = glyph->bitmap.buffer;
6192 dst = buf;
6193 w = min( pitch, (glyph->bitmap.width + 7) >> 3 );
6194 h = min( height, glyph->bitmap.rows );
6195 while (h--)
6197 if (!fake_bold)
6198 memcpy( dst, src, w );
6199 else
6201 dst[0] = 0;
6202 for (x = 0; x < w; x++)
6204 dst[x] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
6205 if (x + 1 < pitch)
6206 dst[x + 1] = (src[x] & 0x01) << 7;
6209 src += glyph->bitmap.pitch;
6210 dst += pitch;
6212 break;
6214 case FT_GLYPH_FORMAT_OUTLINE:
6215 ft_bitmap.width = width;
6216 ft_bitmap.rows = height;
6217 ft_bitmap.pitch = pitch;
6218 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
6219 ft_bitmap.buffer = buf;
6221 if (needs_transform)
6222 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
6223 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
6225 /* Note: FreeType will only set 'black' bits for us. */
6226 memset( buf, 0, buflen );
6227 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
6228 break;
6230 default:
6231 FIXME( "loaded glyph format %x\n", glyph->format );
6232 return GDI_ERROR;
6235 return needed;
6238 static DWORD get_antialias_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
6239 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
6240 DWORD buflen, BYTE *buf )
6242 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
6243 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
6244 DWORD pitch = (width + 3) / 4 * 4;
6245 DWORD needed = pitch * height;
6246 FT_Bitmap ft_bitmap;
6247 INT w, h, x, max_level;
6248 BYTE *src, *dst;
6250 if (!buf || !buflen) return needed;
6251 if (!needed) return GDI_ERROR; /* empty glyph */
6252 if (needed > buflen) return GDI_ERROR;
6254 max_level = get_max_level( format );
6256 switch (glyph->format)
6258 case FT_GLYPH_FORMAT_BITMAP:
6259 src = glyph->bitmap.buffer;
6260 dst = buf;
6261 memset( buf, 0, buflen );
6263 w = min( pitch, glyph->bitmap.width );
6264 h = min( height, glyph->bitmap.rows );
6265 while (h--)
6267 for (x = 0; x < w; x++)
6269 if (src[x / 8] & masks[x % 8])
6271 dst[x] = max_level;
6272 if (fake_bold && x + 1 < pitch) dst[x + 1] = max_level;
6275 src += glyph->bitmap.pitch;
6276 dst += pitch;
6278 break;
6280 case FT_GLYPH_FORMAT_OUTLINE:
6281 ft_bitmap.width = width;
6282 ft_bitmap.rows = height;
6283 ft_bitmap.pitch = pitch;
6284 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
6285 ft_bitmap.buffer = buf;
6287 if (needs_transform)
6288 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
6289 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
6291 memset( buf, 0, buflen );
6292 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
6294 if (max_level != 255)
6296 INT row, col;
6297 BYTE *ptr, *start;
6299 for (row = 0, start = buf; row < height; row++)
6301 for (col = 0, ptr = start; col < width; col++, ptr++)
6302 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6303 start += pitch;
6306 break;
6308 default:
6309 FIXME("loaded glyph format %x\n", glyph->format);
6310 return GDI_ERROR;
6313 return needed;
6316 static DWORD get_subpixel_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
6317 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
6318 GLYPHMETRICS *gm, DWORD buflen, BYTE *buf )
6320 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
6321 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
6322 DWORD pitch, needed = 0;
6323 BYTE *src, *dst;
6324 INT w, h, x;
6326 switch (glyph->format)
6328 case FT_GLYPH_FORMAT_BITMAP:
6329 pitch = width * 4;
6330 needed = pitch * height;
6332 if (!buf || !buflen) break;
6333 if (!needed) return GDI_ERROR; /* empty glyph */
6334 if (needed > buflen) return GDI_ERROR;
6336 src = glyph->bitmap.buffer;
6337 dst = buf;
6338 memset( buf, 0, buflen );
6340 w = min( width, glyph->bitmap.width );
6341 h = min( height, glyph->bitmap.rows );
6342 while (h--)
6344 for (x = 0; x < w; x++)
6346 if ( src[x / 8] & masks[x % 8] )
6348 ((unsigned int *)dst)[x] = ~0u;
6349 if (fake_bold && x + 1 < width) ((unsigned int *)dst)[x + 1] = ~0u;
6352 src += glyph->bitmap.pitch;
6353 dst += pitch;
6355 break;
6357 case FT_GLYPH_FORMAT_OUTLINE:
6359 INT src_pitch, src_width, src_height, x_shift, y_shift;
6360 INT sub_stride, hmul, vmul;
6361 const INT *sub_order;
6362 const INT rgb_order[3] = { 0, 1, 2 };
6363 const INT bgr_order[3] = { 2, 1, 0 };
6364 FT_Render_Mode render_mode =
6365 (format == WINE_GGO_HRGB_BITMAP ||
6366 format == WINE_GGO_HBGR_BITMAP) ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
6368 if (!width || !height) /* empty glyph */
6370 if (!buf || !buflen) break;
6371 return GDI_ERROR;
6374 if ( render_mode == FT_RENDER_MODE_LCD)
6376 gm->gmBlackBoxX += 2;
6377 gm->gmptGlyphOrigin.x -= 1;
6378 bbox.xMin -= (1 << 6);
6380 else
6382 gm->gmBlackBoxY += 2;
6383 gm->gmptGlyphOrigin.y += 1;
6384 bbox.yMax += (1 << 6);
6387 width = gm->gmBlackBoxX;
6388 height = gm->gmBlackBoxY;
6389 pitch = width * 4;
6390 needed = pitch * height;
6392 if (!buf || !buflen) return needed;
6393 if (needed > buflen) return GDI_ERROR;
6395 if (needs_transform)
6396 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
6398 #ifdef FT_LCD_FILTER_H
6399 if (pFT_Library_SetLcdFilter)
6400 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
6401 #endif
6402 pFT_Render_Glyph( glyph, render_mode );
6404 src_pitch = glyph->bitmap.pitch;
6405 src_width = glyph->bitmap.width;
6406 src_height = glyph->bitmap.rows;
6407 src = glyph->bitmap.buffer;
6408 dst = buf;
6409 memset( buf, 0, buflen );
6411 sub_order = (format == WINE_GGO_HRGB_BITMAP ||
6412 format == WINE_GGO_VRGB_BITMAP) ? rgb_order : bgr_order;
6413 sub_stride = render_mode == FT_RENDER_MODE_LCD ? 1 : src_pitch;
6414 hmul = render_mode == FT_RENDER_MODE_LCD ? 3 : 1;
6415 vmul = render_mode == FT_RENDER_MODE_LCD ? 1 : 3;
6417 x_shift = glyph->bitmap_left - (bbox.xMin >> 6);
6418 if ( x_shift < 0 )
6420 src += hmul * -x_shift;
6421 src_width -= hmul * -x_shift;
6423 else if ( x_shift > 0 )
6425 dst += x_shift * sizeof(unsigned int);
6426 width -= x_shift;
6429 y_shift = (bbox.yMax >> 6) - glyph->bitmap_top;
6430 if ( y_shift < 0 )
6432 src += src_pitch * vmul * -y_shift;
6433 src_height -= vmul * -y_shift;
6435 else if ( y_shift > 0 )
6437 dst += y_shift * pitch;
6438 height -= y_shift;
6441 w = min( width, src_width / hmul );
6442 h = min( height, src_height / vmul );
6443 while (h--)
6445 for (x = 0; x < w; x++)
6447 ((unsigned int *)dst)[x] =
6448 ((unsigned int)src[hmul * x + sub_stride * sub_order[0]] << 16) |
6449 ((unsigned int)src[hmul * x + sub_stride * sub_order[1]] << 8) |
6450 ((unsigned int)src[hmul * x + sub_stride * sub_order[2]]);
6452 src += src_pitch * vmul;
6453 dst += pitch;
6455 break;
6457 default:
6458 FIXME ( "loaded glyph format %x\n", glyph->format );
6459 return GDI_ERROR;
6462 return needed;
6465 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6467 TTPOLYGONHEADER *pph;
6468 TTPOLYCURVE *ppc;
6469 unsigned int needed = 0, point = 0, contour, first_pt;
6470 unsigned int pph_start, cpfx;
6471 DWORD type;
6473 for (contour = 0; contour < outline->n_contours; contour++)
6475 /* Ignore contours containing one point */
6476 if (point == outline->contours[contour])
6478 point++;
6479 continue;
6482 pph_start = needed;
6483 pph = (TTPOLYGONHEADER *)(buf + needed);
6484 first_pt = point;
6485 if (buf)
6487 pph->dwType = TT_POLYGON_TYPE;
6488 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6490 needed += sizeof(*pph);
6491 point++;
6492 while (point <= outline->contours[contour])
6494 ppc = (TTPOLYCURVE *)(buf + needed);
6495 type = outline->tags[point] & FT_Curve_Tag_On ?
6496 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6497 cpfx = 0;
6500 if (buf)
6501 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6502 cpfx++;
6503 point++;
6504 } while (point <= outline->contours[contour] &&
6505 (outline->tags[point] & FT_Curve_Tag_On) ==
6506 (outline->tags[point-1] & FT_Curve_Tag_On));
6507 /* At the end of a contour Windows adds the start point, but
6508 only for Beziers */
6509 if (point > outline->contours[contour] &&
6510 !(outline->tags[point-1] & FT_Curve_Tag_On))
6512 if (buf)
6513 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6514 cpfx++;
6516 else if (point <= outline->contours[contour] &&
6517 outline->tags[point] & FT_Curve_Tag_On)
6519 /* add closing pt for bezier */
6520 if (buf)
6521 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6522 cpfx++;
6523 point++;
6525 if (buf)
6527 ppc->wType = type;
6528 ppc->cpfx = cpfx;
6530 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6532 if (buf)
6533 pph->cb = needed - pph_start;
6535 return needed;
6538 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6540 /* Convert the quadratic Beziers to cubic Beziers.
6541 The parametric eqn for a cubic Bezier is, from PLRM:
6542 r(t) = at^3 + bt^2 + ct + r0
6543 with the control points:
6544 r1 = r0 + c/3
6545 r2 = r1 + (c + b)/3
6546 r3 = r0 + c + b + a
6548 A quadratic Bezier has the form:
6549 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6551 So equating powers of t leads to:
6552 r1 = 2/3 p1 + 1/3 p0
6553 r2 = 2/3 p1 + 1/3 p2
6554 and of course r0 = p0, r3 = p2
6556 int contour, point = 0, first_pt;
6557 TTPOLYGONHEADER *pph;
6558 TTPOLYCURVE *ppc;
6559 DWORD pph_start, cpfx, type;
6560 FT_Vector cubic_control[4];
6561 unsigned int needed = 0;
6563 for (contour = 0; contour < outline->n_contours; contour++)
6565 pph_start = needed;
6566 pph = (TTPOLYGONHEADER *)(buf + needed);
6567 first_pt = point;
6568 if (buf)
6570 pph->dwType = TT_POLYGON_TYPE;
6571 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6573 needed += sizeof(*pph);
6574 point++;
6575 while (point <= outline->contours[contour])
6577 ppc = (TTPOLYCURVE *)(buf + needed);
6578 type = outline->tags[point] & FT_Curve_Tag_On ?
6579 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6580 cpfx = 0;
6583 if (type == TT_PRIM_LINE)
6585 if (buf)
6586 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6587 cpfx++;
6588 point++;
6590 else
6592 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6593 so cpfx = 3n */
6595 /* FIXME: Possible optimization in endpoint calculation
6596 if there are two consecutive curves */
6597 cubic_control[0] = outline->points[point-1];
6598 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
6600 cubic_control[0].x += outline->points[point].x + 1;
6601 cubic_control[0].y += outline->points[point].y + 1;
6602 cubic_control[0].x >>= 1;
6603 cubic_control[0].y >>= 1;
6605 if (point+1 > outline->contours[contour])
6606 cubic_control[3] = outline->points[first_pt];
6607 else
6609 cubic_control[3] = outline->points[point+1];
6610 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
6612 cubic_control[3].x += outline->points[point].x + 1;
6613 cubic_control[3].y += outline->points[point].y + 1;
6614 cubic_control[3].x >>= 1;
6615 cubic_control[3].y >>= 1;
6618 /* r1 = 1/3 p0 + 2/3 p1
6619 r2 = 1/3 p2 + 2/3 p1 */
6620 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6621 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6622 cubic_control[2] = cubic_control[1];
6623 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6624 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6625 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6626 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6627 if (buf)
6629 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6630 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6631 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6633 cpfx += 3;
6634 point++;
6636 } while (point <= outline->contours[contour] &&
6637 (outline->tags[point] & FT_Curve_Tag_On) ==
6638 (outline->tags[point-1] & FT_Curve_Tag_On));
6639 /* At the end of a contour Windows adds the start point,
6640 but only for Beziers and we've already done that.
6642 if (point <= outline->contours[contour] &&
6643 outline->tags[point] & FT_Curve_Tag_On)
6645 /* This is the closing pt of a bezier, but we've already
6646 added it, so just inc point and carry on */
6647 point++;
6649 if (buf)
6651 ppc->wType = type;
6652 ppc->cpfx = cpfx;
6654 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6656 if (buf)
6657 pph->cb = needed - pph_start;
6659 return needed;
6662 static FT_Int get_load_flags( UINT format )
6664 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6666 if (format & GGO_UNHINTED)
6667 return load_flags | FT_LOAD_NO_HINTING;
6669 switch (format & ~GGO_GLYPH_INDEX)
6671 case GGO_BITMAP:
6672 load_flags |= FT_LOAD_TARGET_MONO;
6673 break;
6674 case GGO_GRAY2_BITMAP:
6675 case GGO_GRAY4_BITMAP:
6676 case GGO_GRAY8_BITMAP:
6677 case WINE_GGO_GRAY16_BITMAP:
6678 load_flags |= FT_LOAD_TARGET_NORMAL;
6679 break;
6680 case WINE_GGO_HRGB_BITMAP:
6681 case WINE_GGO_HBGR_BITMAP:
6682 load_flags |= FT_LOAD_TARGET_LCD;
6683 break;
6684 case WINE_GGO_VRGB_BITMAP:
6685 case WINE_GGO_VBGR_BITMAP:
6686 load_flags |= FT_LOAD_TARGET_LCD_V;
6687 break;
6690 return load_flags;
6693 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6694 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6695 const MAT2* lpmat)
6697 GLYPHMETRICS gm;
6698 FT_Face ft_face = incoming_font->ft_face;
6699 GdiFont *font = incoming_font;
6700 struct gdi_font *gdi_font = font->gdi_font;
6701 FT_Glyph_Metrics metrics;
6702 FT_UInt glyph_index;
6703 DWORD needed = 0;
6704 FT_Error err;
6705 FT_BBox bbox;
6706 FT_Int load_flags = get_load_flags(format);
6707 FT_Matrix matrices[3];
6708 BOOL needsTransform = FALSE;
6709 BOOL tategaki = (gdi_font->name[0] == '@');
6710 BOOL vertical_metrics;
6712 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6713 buflen, buf, lpmat);
6715 TRACE("font transform %f %f %f %f\n",
6716 gdi_font->matrix.eM11, gdi_font->matrix.eM12,
6717 gdi_font->matrix.eM21, gdi_font->matrix.eM22);
6719 if(format & GGO_GLYPH_INDEX) {
6720 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6721 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6722 as glyph index. "Treasure Adventure Game" depends on this. */
6723 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6724 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6725 } else
6726 glyph_index = glyph;
6727 format &= ~GGO_GLYPH_INDEX;
6728 /* TODO: Window also turns off tategaki for glyphs passed in by index
6729 if their unicode code points fall outside of the range that is
6730 rotated. */
6731 } else {
6732 BOOL vert;
6733 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6734 ft_face = font->ft_face;
6735 gdi_font = font->gdi_font;
6736 if (!vert && tategaki)
6737 tategaki = check_unicode_tategaki(glyph);
6740 format &= ~GGO_UNHINTED;
6742 if (format == GGO_METRICS && is_identity_MAT2(lpmat) &&
6743 get_gdi_font_glyph_metrics( gdi_font, glyph_index, lpgm, abc ))
6744 return 1; /* FIXME */
6746 needsTransform = get_transform_matrices( font, tategaki, lpmat, matrices );
6748 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6749 /* there is a freetype bug where vertical metrics are only
6750 properly scaled and correct in 2.4.0 or greater */
6751 if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0))
6752 vertical_metrics = FALSE;
6754 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6755 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6757 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6758 if (err && !(load_flags & FT_LOAD_NO_HINTING))
6760 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph_index, err);
6761 load_flags |= FT_LOAD_NO_HINTING;
6762 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6765 if(err) {
6766 WARN("Failed to load glyph %#x, error %#x.\n", glyph_index, err);
6767 return GDI_ERROR;
6770 metrics = ft_face->glyph->metrics;
6771 if(gdi_font->fake_bold) {
6772 if (!get_bold_glyph_outline(ft_face->glyph, gdi_font->ppem, &metrics) && metrics.width)
6773 metrics.width += 1 << 6;
6776 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6777 * by the text metrics. The proper behavior is to clip the glyph metrics to
6778 * fit within the maximums specified in the text metrics. */
6779 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6780 get_bitmap_text_metrics(incoming_font)) {
6781 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6782 INT top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6783 INT bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6784 metrics.horiBearingY = top;
6785 metrics.height = top - bottom;
6787 /* TODO: Are we supposed to clip the width as well...? */
6788 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6791 bbox = get_transformed_bbox( &metrics, needsTransform, matrices );
6792 compute_metrics( incoming_font, font, bbox, &metrics,
6793 tategaki, vertical_metrics, needsTransform, matrices,
6794 &gm, abc );
6796 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6797 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6798 set_gdi_font_glyph_metrics( gdi_font, glyph_index, &gm, abc );
6800 if(format == GGO_METRICS)
6802 *lpgm = gm;
6803 return 1; /* FIXME */
6806 if(ft_face->glyph->format != ft_glyph_format_outline &&
6807 (format == GGO_NATIVE || format == GGO_BEZIER))
6809 TRACE("loaded a bitmap\n");
6810 return GDI_ERROR;
6813 switch (format)
6815 case GGO_BITMAP:
6816 needed = get_mono_glyph_bitmap( ft_face->glyph, bbox, gdi_font->fake_bold,
6817 needsTransform, matrices, buflen, buf );
6818 break;
6820 case GGO_GRAY2_BITMAP:
6821 case GGO_GRAY4_BITMAP:
6822 case GGO_GRAY8_BITMAP:
6823 case WINE_GGO_GRAY16_BITMAP:
6824 needed = get_antialias_glyph_bitmap( ft_face->glyph, bbox, format, gdi_font->fake_bold,
6825 needsTransform, matrices, buflen, buf );
6826 break;
6828 case WINE_GGO_HRGB_BITMAP:
6829 case WINE_GGO_HBGR_BITMAP:
6830 case WINE_GGO_VRGB_BITMAP:
6831 case WINE_GGO_VBGR_BITMAP:
6832 needed = get_subpixel_glyph_bitmap( ft_face->glyph, bbox, format, gdi_font->fake_bold,
6833 needsTransform, matrices, &gm, buflen, buf );
6834 break;
6836 case GGO_NATIVE:
6838 FT_Outline *outline = &ft_face->glyph->outline;
6840 if(buflen == 0) buf = NULL;
6842 if (needsTransform && buf)
6843 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
6845 needed = get_native_glyph_outline(outline, buflen, NULL);
6847 if (!buf || !buflen)
6848 break;
6849 if (needed > buflen)
6850 return GDI_ERROR;
6852 get_native_glyph_outline(outline, buflen, buf);
6853 break;
6855 case GGO_BEZIER:
6857 FT_Outline *outline = &ft_face->glyph->outline;
6858 if(buflen == 0) buf = NULL;
6860 if (needsTransform && buf)
6861 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
6863 needed = get_bezier_glyph_outline(outline, buflen, NULL);
6865 if (!buf || !buflen)
6866 break;
6867 if (needed > buflen)
6868 return GDI_ERROR;
6870 get_bezier_glyph_outline(outline, buflen, buf);
6871 break;
6874 default:
6875 FIXME("Unsupported format %d\n", format);
6876 return GDI_ERROR;
6878 if (needed != GDI_ERROR)
6879 *lpgm = gm;
6881 return needed;
6884 static BOOL get_bitmap_text_metrics(GdiFont *font)
6886 struct gdi_font *gdi_font = font->gdi_font;
6887 FT_Face ft_face = font->ft_face;
6888 FT_WinFNT_HeaderRec winfnt_header;
6889 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6890 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6891 font->potm->otmSize = size;
6893 #define TM font->potm->otmTextMetrics
6894 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6896 TM.tmHeight = winfnt_header.pixel_height;
6897 TM.tmAscent = winfnt_header.ascent;
6898 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6899 TM.tmInternalLeading = winfnt_header.internal_leading;
6900 TM.tmExternalLeading = winfnt_header.external_leading;
6901 TM.tmAveCharWidth = winfnt_header.avg_width;
6902 TM.tmMaxCharWidth = winfnt_header.max_width;
6903 TM.tmWeight = winfnt_header.weight;
6904 TM.tmOverhang = 0;
6905 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6906 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6907 TM.tmFirstChar = winfnt_header.first_char;
6908 TM.tmLastChar = winfnt_header.last_char;
6909 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6910 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6911 TM.tmItalic = winfnt_header.italic;
6912 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6913 TM.tmCharSet = winfnt_header.charset;
6915 else
6917 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6918 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6919 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6920 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6921 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6922 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6923 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6924 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6925 TM.tmOverhang = 0;
6926 TM.tmDigitizedAspectX = 96; /* FIXME */
6927 TM.tmDigitizedAspectY = 96; /* FIXME */
6928 TM.tmFirstChar = 1;
6929 TM.tmLastChar = 255;
6930 TM.tmDefaultChar = 32;
6931 TM.tmBreakChar = 32;
6932 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6933 /* NB inverted meaning of TMPF_FIXED_PITCH */
6934 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
6935 TM.tmCharSet = gdi_font->charset;
6937 TM.tmUnderlined = gdi_font->lf.lfUnderline ? 0xff : 0;
6938 TM.tmStruckOut = gdi_font->lf.lfStrikeOut ? 0xff : 0;
6940 if(gdi_font->fake_bold)
6941 TM.tmWeight = FW_BOLD;
6942 #undef TM
6944 return TRUE;
6948 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6950 const struct gdi_font *gdi_font = font->gdi_font;
6951 double scale_x, scale_y;
6953 if (gdi_font->aveWidth)
6955 scale_x = (double)gdi_font->aveWidth;
6956 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6958 else
6959 scale_x = gdi_font->scale_y;
6961 scale_x *= fabs(gdi_font->matrix.eM11);
6962 scale_y = gdi_font->scale_y * fabs(gdi_font->matrix.eM22);
6964 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6965 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6967 SCALE_Y(ptm->tmHeight);
6968 SCALE_Y(ptm->tmAscent);
6969 SCALE_Y(ptm->tmDescent);
6970 SCALE_Y(ptm->tmInternalLeading);
6971 SCALE_Y(ptm->tmExternalLeading);
6973 SCALE_X(ptm->tmOverhang);
6974 if(gdi_font->fake_bold)
6976 if(!gdi_font->scalable)
6977 ptm->tmOverhang++;
6978 ptm->tmAveCharWidth++;
6979 ptm->tmMaxCharWidth++;
6981 SCALE_X(ptm->tmAveCharWidth);
6982 SCALE_X(ptm->tmMaxCharWidth);
6984 #undef SCALE_X
6985 #undef SCALE_Y
6988 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6990 const struct gdi_font *gdi_font = font->gdi_font;
6991 double scale_x, scale_y;
6993 if (gdi_font->aveWidth)
6995 scale_x = (double)gdi_font->aveWidth;
6996 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6998 else
6999 scale_x = gdi_font->scale_y;
7001 scale_x *= fabs(gdi_font->matrix.eM11);
7002 scale_y = gdi_font->scale_y * fabs(gdi_font->matrix.eM22);
7004 scale_font_metrics(font, &potm->otmTextMetrics);
7006 /* Windows scales these values as signed integers even if they are unsigned */
7007 #define SCALE_X(x) (x) = GDI_ROUND((int)(x) * (scale_x))
7008 #define SCALE_Y(y) (y) = GDI_ROUND((int)(y) * (scale_y))
7010 SCALE_Y(potm->otmAscent);
7011 SCALE_Y(potm->otmDescent);
7012 SCALE_Y(potm->otmLineGap);
7013 SCALE_Y(potm->otmsCapEmHeight);
7014 SCALE_Y(potm->otmsXHeight);
7015 SCALE_Y(potm->otmrcFontBox.top);
7016 SCALE_Y(potm->otmrcFontBox.bottom);
7017 SCALE_X(potm->otmrcFontBox.left);
7018 SCALE_X(potm->otmrcFontBox.right);
7019 SCALE_Y(potm->otmMacAscent);
7020 SCALE_Y(potm->otmMacDescent);
7021 SCALE_Y(potm->otmMacLineGap);
7022 SCALE_X(potm->otmptSubscriptSize.x);
7023 SCALE_Y(potm->otmptSubscriptSize.y);
7024 SCALE_X(potm->otmptSubscriptOffset.x);
7025 SCALE_Y(potm->otmptSubscriptOffset.y);
7026 SCALE_X(potm->otmptSuperscriptSize.x);
7027 SCALE_Y(potm->otmptSuperscriptSize.y);
7028 SCALE_X(potm->otmptSuperscriptOffset.x);
7029 SCALE_Y(potm->otmptSuperscriptOffset.y);
7030 SCALE_Y(potm->otmsStrikeoutSize);
7031 SCALE_Y(potm->otmsStrikeoutPosition);
7032 SCALE_Y(potm->otmsUnderscoreSize);
7033 SCALE_Y(potm->otmsUnderscorePosition);
7035 #undef SCALE_X
7036 #undef SCALE_Y
7039 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7041 struct gdi_font *gdi_font = font->gdi_font;
7042 if(!font->potm)
7044 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7046 /* Make sure that the font has sane width/height ratio */
7047 if (gdi_font->aveWidth)
7049 if ((gdi_font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7051 WARN("Ignoring too large font->aveWidth %d\n", gdi_font->aveWidth);
7052 gdi_font->aveWidth = 0;
7056 *ptm = font->potm->otmTextMetrics;
7057 scale_font_metrics(font, ptm);
7058 return TRUE;
7061 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7063 int i;
7065 for(i = 0; i < ft_face->num_charmaps; i++)
7067 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7068 return TRUE;
7070 return FALSE;
7073 static BOOL get_outline_text_metrics(GdiFont *font)
7075 BOOL ret = FALSE;
7076 FT_Face ft_face = font->ft_face;
7077 struct gdi_font *gdi_font = font->gdi_font;
7078 UINT needed, lenfam, lensty, lenface, lenfull;
7079 TT_OS2 *pOS2;
7080 TT_HoriHeader *pHori;
7081 TT_Postscript *pPost;
7082 FT_Fixed em_scale;
7083 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7084 char *cp;
7085 INT ascent, descent;
7086 USHORT windescent;
7088 TRACE("font=%p\n", font);
7090 if(!FT_IS_SCALABLE(ft_face))
7091 return FALSE;
7093 needed = sizeof(*font->potm);
7095 lenfam = (strlenW(gdi_font->name) + 1) * sizeof(WCHAR);
7096 family_nameW = strdupW(gdi_font->name);
7098 style_nameW = ft_face_get_style_name( ft_face, GetSystemDefaultLangID() );
7099 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7101 face_nameW = ft_face_get_full_name( ft_face, GetSystemDefaultLangID() );
7102 if (gdi_font->name[0] == '@') face_nameW = get_vertical_name( face_nameW );
7103 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7105 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7106 if (!full_nameW)
7108 static const WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7109 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(gdi_font->name));
7110 full_nameW = strdupW(fake_nameW);
7112 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7114 /* These names should be read from the TT name table */
7116 /* length of otmpFamilyName */
7117 needed += lenfam;
7119 /* length of otmpFaceName */
7120 needed += lenface;
7122 /* length of otmpStyleName */
7123 needed += lensty;
7125 /* length of otmpFullName */
7126 needed += lenfull;
7129 em_scale = (FT_Fixed)MulDiv(gdi_font->ppem, 1 << 16, ft_face->units_per_EM);
7131 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7132 if(!pOS2) {
7133 FIXME("Can't find OS/2 table - not TT font?\n");
7134 goto end;
7137 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7138 if(!pHori) {
7139 FIXME("Can't find HHEA table - not TT font?\n");
7140 goto end;
7143 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7145 TRACE("OS/2 winA = %u winD = %u typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
7146 pOS2->usWinAscent, pOS2->usWinDescent,
7147 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7148 pOS2->xAvgCharWidth,
7149 ft_face->ascender, ft_face->descender, ft_face->height,
7150 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7151 ft_face->bbox.yMax, ft_face->bbox.yMin);
7153 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7154 font->potm->otmSize = needed;
7156 #define TM font->potm->otmTextMetrics
7158 windescent = get_fixed_windescent(pOS2->usWinDescent);
7159 if(pOS2->usWinAscent + windescent == 0) {
7160 ascent = pHori->Ascender;
7161 descent = -pHori->Descender;
7162 } else {
7163 ascent = pOS2->usWinAscent;
7164 descent = windescent;
7167 gdi_font->ntmCellHeight = ascent + descent;
7168 gdi_font->ntmAvgWidth = pOS2->xAvgCharWidth;
7170 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7171 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7173 if(gdi_font->yMax) {
7174 TM.tmAscent = gdi_font->yMax;
7175 TM.tmDescent = -gdi_font->yMin;
7176 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7177 } else {
7178 TM.tmAscent = SCALE_Y(ascent);
7179 TM.tmDescent = SCALE_Y(descent);
7180 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7183 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7185 /* MSDN says:
7186 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7188 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7189 ((ascent + descent) -
7190 (pHori->Ascender - pHori->Descender))));
7192 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7193 if (TM.tmAveCharWidth == 0) {
7194 TM.tmAveCharWidth = 1;
7196 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7197 TM.tmWeight = FW_REGULAR;
7198 if (gdi_font->fake_bold)
7199 TM.tmWeight = FW_BOLD;
7200 else
7202 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7204 if (pOS2->usWeightClass > FW_MEDIUM)
7205 TM.tmWeight = pOS2->usWeightClass;
7207 else if (pOS2->usWeightClass <= FW_MEDIUM)
7208 TM.tmWeight = pOS2->usWeightClass;
7210 TM.tmOverhang = 0;
7211 TM.tmDigitizedAspectX = 96; /* FIXME */
7212 TM.tmDigitizedAspectY = 96; /* FIXME */
7213 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7214 * symbol range to 0 - f0ff
7217 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7219 TM.tmFirstChar = 0;
7220 switch(GetACP())
7222 case 1255: /* Hebrew */
7223 TM.tmLastChar = 0xf896;
7224 break;
7225 case 1257: /* Baltic */
7226 TM.tmLastChar = 0xf8fd;
7227 break;
7228 default:
7229 TM.tmLastChar = 0xf0ff;
7231 TM.tmBreakChar = 0x20;
7232 TM.tmDefaultChar = 0x1f;
7234 else
7236 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7237 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7239 if(pOS2->usFirstCharIndex <= 1)
7240 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7241 else if (pOS2->usFirstCharIndex > 0xff)
7242 TM.tmBreakChar = 0x20;
7243 else
7244 TM.tmBreakChar = pOS2->usFirstCharIndex;
7245 TM.tmDefaultChar = TM.tmBreakChar - 1;
7247 TM.tmItalic = gdi_font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7248 TM.tmUnderlined = gdi_font->lf.lfUnderline ? 255 : 0;
7249 TM.tmStruckOut = gdi_font->lf.lfStrikeOut ? 255 : 0;
7251 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7252 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7253 (pOS2->version == 0xFFFFU ||
7254 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7255 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7256 else
7257 TM.tmPitchAndFamily = 0;
7259 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7261 case PAN_FAMILY_SCRIPT:
7262 TM.tmPitchAndFamily |= FF_SCRIPT;
7263 break;
7265 case PAN_FAMILY_DECORATIVE:
7266 TM.tmPitchAndFamily |= FF_DECORATIVE;
7267 break;
7269 case PAN_ANY:
7270 case PAN_NO_FIT:
7271 case PAN_FAMILY_TEXT_DISPLAY:
7272 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7273 /* which is clearly not what the panose spec says. */
7274 default:
7275 if(TM.tmPitchAndFamily == 0 || /* fixed */
7276 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7277 TM.tmPitchAndFamily = FF_MODERN;
7278 else
7280 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7282 case PAN_ANY:
7283 case PAN_NO_FIT:
7284 default:
7285 TM.tmPitchAndFamily |= FF_DONTCARE;
7286 break;
7288 case PAN_SERIF_COVE:
7289 case PAN_SERIF_OBTUSE_COVE:
7290 case PAN_SERIF_SQUARE_COVE:
7291 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7292 case PAN_SERIF_SQUARE:
7293 case PAN_SERIF_THIN:
7294 case PAN_SERIF_BONE:
7295 case PAN_SERIF_EXAGGERATED:
7296 case PAN_SERIF_TRIANGLE:
7297 TM.tmPitchAndFamily |= FF_ROMAN;
7298 break;
7300 case PAN_SERIF_NORMAL_SANS:
7301 case PAN_SERIF_OBTUSE_SANS:
7302 case PAN_SERIF_PERP_SANS:
7303 case PAN_SERIF_FLARED:
7304 case PAN_SERIF_ROUNDED:
7305 TM.tmPitchAndFamily |= FF_SWISS;
7306 break;
7309 break;
7312 if(FT_IS_SCALABLE(ft_face))
7313 TM.tmPitchAndFamily |= TMPF_VECTOR;
7315 if(FT_IS_SFNT(ft_face))
7317 if (gdi_font->ntmFlags & NTM_PS_OPENTYPE)
7318 TM.tmPitchAndFamily |= TMPF_DEVICE;
7319 else
7320 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7323 TM.tmCharSet = gdi_font->charset;
7325 font->potm->otmFiller = 0;
7326 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7327 font->potm->otmfsSelection = pOS2->fsSelection;
7328 if (gdi_font->fake_italic)
7329 font->potm->otmfsSelection |= 1;
7330 if (gdi_font->fake_bold)
7331 font->potm->otmfsSelection |= 1 << 5;
7332 /* Only return valid bits that define embedding and subsetting restrictions */
7333 font->potm->otmfsType = pOS2->fsType & 0x30e;
7334 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7335 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7336 font->potm->otmItalicAngle = 0; /* POST table */
7337 font->potm->otmEMSquare = ft_face->units_per_EM;
7338 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7339 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7340 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7341 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7342 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7343 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7344 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7345 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7346 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7347 font->potm->otmMacAscent = TM.tmAscent;
7348 font->potm->otmMacDescent = -TM.tmDescent;
7349 font->potm->otmMacLineGap = SCALE_Y(pHori->Line_Gap);
7350 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7351 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7352 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7353 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7354 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7355 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7356 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7357 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7358 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7359 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7360 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7361 if(!pPost) {
7362 font->potm->otmsUnderscoreSize = 0;
7363 font->potm->otmsUnderscorePosition = 0;
7364 } else {
7365 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7366 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7368 #undef SCALE_X
7369 #undef SCALE_Y
7370 #undef TM
7372 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7373 cp = (char*)font->potm + sizeof(*font->potm);
7374 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7375 strcpyW((WCHAR*)cp, family_nameW);
7376 cp += lenfam;
7377 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7378 strcpyW((WCHAR*)cp, style_nameW);
7379 cp += lensty;
7380 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7381 strcpyW((WCHAR*)cp, face_nameW);
7382 cp += lenface;
7383 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7384 strcpyW((WCHAR*)cp, full_nameW);
7385 ret = TRUE;
7387 end:
7388 HeapFree(GetProcessHeap(), 0, style_nameW);
7389 HeapFree(GetProcessHeap(), 0, family_nameW);
7390 HeapFree(GetProcessHeap(), 0, face_nameW);
7391 HeapFree(GetProcessHeap(), 0, full_nameW);
7392 return ret;
7395 /*************************************************************
7396 * freetype_GetGlyphOutline
7398 static DWORD CDECL freetype_GetGlyphOutline( struct gdi_font *font, UINT glyph, UINT format,
7399 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7401 DWORD ret;
7402 ABC abc;
7404 EnterCriticalSection( &freetype_cs );
7405 ret = get_glyph_outline( get_font_ptr(font), glyph, format, lpgm, &abc, buflen, buf, lpmat );
7406 LeaveCriticalSection( &freetype_cs );
7407 return ret;
7410 /*************************************************************
7411 * freetype_GetTextMetrics
7413 static BOOL CDECL freetype_GetTextMetrics( struct gdi_font *font, TEXTMETRICW *metrics )
7415 BOOL ret;
7417 EnterCriticalSection( &freetype_cs );
7418 ret = get_text_metrics( get_font_ptr(font), metrics );
7419 LeaveCriticalSection( &freetype_cs );
7420 return ret;
7423 /*************************************************************
7424 * freetype_GetOutlineTextMetrics
7426 static UINT CDECL freetype_GetOutlineTextMetrics( struct gdi_font *gdi_font, UINT cbSize, OUTLINETEXTMETRICW *potm )
7428 GdiFont *font = get_font_ptr(gdi_font);
7429 UINT ret = 0;
7431 TRACE("font=%p\n", font);
7433 if (!gdi_font->scalable) return 0;
7435 EnterCriticalSection( &freetype_cs );
7437 if (font->potm || get_outline_text_metrics( font ))
7439 if(potm && cbSize >= font->potm->otmSize)
7441 memcpy(potm, font->potm, font->potm->otmSize);
7442 scale_outline_font_metrics(font, potm);
7444 ret = font->potm->otmSize;
7446 LeaveCriticalSection( &freetype_cs );
7447 return ret;
7450 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7452 struct gdi_font *gdi_font = font->gdi_font;
7453 const struct list *face_list;
7454 Face *child_face = NULL, *best_face = NULL;
7455 UINT penalty = 0, new_penalty = 0;
7456 BOOL bold, italic, bd, it;
7458 italic = !!gdi_font->lf.lfItalic;
7459 bold = gdi_font->lf.lfWeight > FW_MEDIUM;
7461 face_list = get_face_list_from_family( child->face->family );
7462 LIST_FOR_EACH_ENTRY( child_face, face_list, Face, entry )
7464 it = !!(child_face->ntmFlags & NTM_ITALIC);
7465 bd = !!(child_face->ntmFlags & NTM_BOLD);
7466 new_penalty = ( it ^ italic ) + ( bd ^ bold );
7467 if (!best_face || new_penalty < penalty)
7469 penalty = new_penalty;
7470 best_face = child_face;
7473 child_face = best_face ? best_face : child->face;
7475 child->font = get_font_ptr( alloc_gdi_font() );
7476 child->font->ft_face = OpenFontFace( child->font, child_face, 0, -gdi_font->ppem );
7477 if(!child->font->ft_face)
7479 free_gdi_font(child->font->gdi_font);
7480 child->font = NULL;
7481 return FALSE;
7484 child->font->gdi_font->fake_italic = italic && !( child_face->ntmFlags & NTM_ITALIC );
7485 child->font->gdi_font->fake_bold = bold && !( child_face->ntmFlags & NTM_BOLD );
7486 child->font->gdi_font->lf = gdi_font->lf;
7487 child->font->gdi_font->matrix = gdi_font->matrix;
7488 child->font->gdi_font->can_use_bitmap = gdi_font->can_use_bitmap;
7489 child->font->gdi_font->ntmFlags = child_face->ntmFlags;
7490 child->font->gdi_font->aa_flags = HIWORD( child_face->flags );
7491 child->font->gdi_font->scale_y = gdi_font->scale_y;
7492 set_gdi_font_name( child->font->gdi_font, child_face->family->family_name );
7493 child->font->base_font = font;
7494 TRACE("created child font %p for base %p\n", child->font, font);
7495 return TRUE;
7498 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
7500 FT_UInt g,o;
7501 CHILD_FONT *child_font;
7503 if(font->base_font)
7504 font = font->base_font;
7506 *linked_font = font;
7508 if((*glyph = get_glyph_index(font, c)))
7510 o = *glyph;
7511 *glyph = get_GSUB_vert_glyph(font, *glyph);
7512 *vert = (o != *glyph);
7513 return TRUE;
7516 if (c < 32) goto done; /* don't check linked fonts for control characters */
7518 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7520 if(!child_font->font)
7521 if(!load_child_font(font, child_font))
7522 continue;
7524 if(!child_font->font->ft_face)
7525 continue;
7526 g = get_glyph_index(child_font->font, c);
7527 o = g;
7528 g = get_GSUB_vert_glyph(child_font->font, g);
7529 if(g)
7531 *glyph = g;
7532 *linked_font = child_font->font;
7533 *vert = (o != g);
7534 return TRUE;
7538 done:
7539 *vert = FALSE;
7540 return FALSE;
7543 /*************************************************************
7544 * freetype_GetCharWidth
7546 static BOOL CDECL freetype_GetCharWidth( struct gdi_font *font, UINT firstChar, UINT lastChar, LPINT buffer )
7548 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7549 UINT c;
7550 GLYPHMETRICS gm;
7551 ABC abc;
7553 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
7555 EnterCriticalSection( &freetype_cs );
7556 for(c = firstChar; c <= lastChar; c++) {
7557 if (get_glyph_outline( get_font_ptr(font), c, GGO_METRICS, &gm, &abc, 0, NULL, &identity ) == GDI_ERROR)
7558 buffer[c - firstChar] = 0;
7559 else
7560 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7562 LeaveCriticalSection( &freetype_cs );
7563 return TRUE;
7566 /*************************************************************
7567 * freetype_GetCharWidthInfo
7569 static BOOL CDECL freetype_GetCharWidthInfo( struct gdi_font *gdi_font, struct char_width_info *info )
7571 GdiFont *font = get_font_ptr(gdi_font);
7572 TT_HoriHeader *pHori;
7574 TRACE("%p, %p\n", font, info);
7576 if (gdi_font->scalable &&
7577 (pHori = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_hhea)))
7579 FT_Fixed em_scale;
7580 em_scale = MulDiv(gdi_font->ppem, 1 << 16, font->ft_face->units_per_EM);
7581 info->lsb = (SHORT)pFT_MulFix(pHori->min_Left_Side_Bearing, em_scale);
7582 info->rsb = (SHORT)pFT_MulFix(pHori->min_Right_Side_Bearing, em_scale);
7584 else
7585 info->lsb = info->rsb = 0;
7587 info->unk = 0;
7589 return TRUE;
7592 /*************************************************************
7593 * freetype_GetCharABCWidths
7595 static BOOL CDECL freetype_GetCharABCWidths( struct gdi_font *font, UINT firstChar, UINT lastChar, LPABC buffer )
7597 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7598 UINT c;
7599 GLYPHMETRICS gm;
7601 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
7603 EnterCriticalSection( &freetype_cs );
7605 for(c = firstChar; c <= lastChar; c++, buffer++)
7606 get_glyph_outline( get_font_ptr(font), c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7608 LeaveCriticalSection( &freetype_cs );
7609 return TRUE;
7612 /*************************************************************
7613 * freetype_GetCharABCWidthsI
7615 static BOOL CDECL freetype_GetCharABCWidthsI( struct gdi_font *gdi_font, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7617 GdiFont *font = get_font_ptr(gdi_font);
7618 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7619 UINT c;
7620 GLYPHMETRICS gm;
7622 if(!FT_HAS_HORIZONTAL(font->ft_face))
7623 return FALSE;
7625 EnterCriticalSection( &freetype_cs );
7627 for(c = 0; c < count; c++, buffer++)
7628 get_glyph_outline( font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7629 &gm, buffer, 0, NULL, &identity );
7631 LeaveCriticalSection( &freetype_cs );
7632 return TRUE;
7635 /*************************************************************
7636 * freetype_GetTextExtentExPoint
7638 static BOOL CDECL freetype_GetTextExtentExPoint( struct gdi_font *font, LPCWSTR wstr, INT count, INT *dxs )
7640 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7641 INT idx, pos;
7642 ABC abc;
7643 GLYPHMETRICS gm;
7645 TRACE("%p, %s, %d\n", font, debugstr_wn(wstr, count), count);
7647 EnterCriticalSection( &freetype_cs );
7649 for (idx = pos = 0; idx < count; idx++)
7651 get_glyph_outline( get_font_ptr(font), wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7652 pos += abc.abcA + abc.abcB + abc.abcC;
7653 dxs[idx] = pos;
7656 LeaveCriticalSection( &freetype_cs );
7657 return TRUE;
7660 /*************************************************************
7661 * freetype_GetTextExtentExPointI
7663 static BOOL CDECL freetype_GetTextExtentExPointI( struct gdi_font *font, const WORD *indices, INT count, INT *dxs )
7665 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7666 INT idx, pos;
7667 ABC abc;
7668 GLYPHMETRICS gm;
7670 TRACE("%p, %p, %d\n", font, indices, count);
7672 EnterCriticalSection( &freetype_cs );
7674 for (idx = pos = 0; idx < count; idx++)
7676 get_glyph_outline( get_font_ptr(font), indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7677 &gm, &abc, 0, NULL, &identity );
7678 pos += abc.abcA + abc.abcB + abc.abcC;
7679 dxs[idx] = pos;
7682 LeaveCriticalSection( &freetype_cs );
7683 return TRUE;
7686 /*************************************************************
7687 * freetype_GetFontData
7689 static DWORD CDECL freetype_GetFontData( struct gdi_font *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7691 TRACE("font=%p, table=%s, offset=0x%x, buf=%p, cbData=0x%x\n",
7692 font, debugstr_an((char*)&table, 4), offset, buf, cbData);
7694 return get_font_data( get_font_ptr(font), table, offset, buf, cbData );
7697 /* Retrieve a list of supported Unicode ranges for a given font.
7698 * Can be called with NULL gs to calculate the buffer size. Returns
7699 * the number of ranges found.
7701 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7703 DWORD num_ranges = 0;
7705 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7707 FT_UInt glyph_code;
7708 FT_ULong char_code, char_code_prev;
7710 glyph_code = 0;
7711 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7713 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7714 face->num_glyphs, glyph_code, char_code);
7716 if (!glyph_code) return 0;
7718 if (gs)
7720 gs->ranges[0].wcLow = (USHORT)char_code;
7721 gs->ranges[0].cGlyphs = 0;
7722 gs->cGlyphsSupported = 0;
7725 num_ranges = 1;
7726 while (glyph_code)
7728 if (char_code < char_code_prev)
7730 ERR("expected increasing char code from FT_Get_Next_Char\n");
7731 return 0;
7733 if (char_code - char_code_prev > 1)
7735 num_ranges++;
7736 if (gs)
7738 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7739 gs->ranges[num_ranges - 1].cGlyphs = 1;
7740 gs->cGlyphsSupported++;
7743 else if (gs)
7745 gs->ranges[num_ranges - 1].cGlyphs++;
7746 gs->cGlyphsSupported++;
7748 char_code_prev = char_code;
7749 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7752 else
7754 DWORD encoding = RtlUlongByteSwap(face->charmap->encoding);
7755 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
7758 return num_ranges;
7761 /*************************************************************
7762 * freetype_GetFontUnicodeRanges
7764 static DWORD CDECL freetype_GetFontUnicodeRanges( struct gdi_font *font, GLYPHSET *glyphset )
7766 DWORD size, num_ranges;
7768 num_ranges = get_font_unicode_ranges(get_font_ptr(font)->ft_face, glyphset);
7769 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7770 if (glyphset)
7772 glyphset->cbThis = size;
7773 glyphset->cRanges = num_ranges;
7774 glyphset->flAccel = 0;
7776 return size;
7779 /*************************************************************
7780 * freetype_FontIsLinked
7782 static BOOL CDECL freetype_FontIsLinked( struct gdi_font *font )
7784 BOOL ret;
7786 EnterCriticalSection( &freetype_cs );
7787 ret = !list_empty( &get_font_ptr(font)->child_fonts );
7788 LeaveCriticalSection( &freetype_cs );
7789 return ret;
7792 /*************************************************************************
7793 * freetype_GetFontFileData
7795 static BOOL CDECL freetype_GetFontFileData( struct gdi_font *gdi_font, DWORD unknown, UINT64 offset,
7796 void *buff, DWORD buff_size )
7798 DWORD tag = 0, size;
7799 GdiFont *font = get_font_ptr( gdi_font );
7801 if (font->ttc_item_offset)
7802 tag = MS_TTCF_TAG;
7804 size = get_font_data( font, tag, 0, NULL, 0 );
7805 if (size < buff_size || offset > size - buff_size)
7807 SetLastError(ERROR_INVALID_PARAMETER);
7808 return FALSE;
7811 /* For now this only works for SFNT case. */
7812 return get_font_data( font, tag, offset, buff, buff_size ) != 0;
7815 /*************************************************************************
7816 * Kerning support for TrueType fonts
7819 struct TT_kern_table
7821 USHORT version;
7822 USHORT nTables;
7825 struct TT_kern_subtable
7827 USHORT version;
7828 USHORT length;
7829 union
7831 USHORT word;
7832 struct
7834 USHORT horizontal : 1;
7835 USHORT minimum : 1;
7836 USHORT cross_stream: 1;
7837 USHORT override : 1;
7838 USHORT reserved1 : 4;
7839 USHORT format : 8;
7840 } bits;
7841 } coverage;
7844 struct TT_format0_kern_subtable
7846 USHORT nPairs;
7847 USHORT searchRange;
7848 USHORT entrySelector;
7849 USHORT rangeShift;
7852 struct TT_kern_pair
7854 USHORT left;
7855 USHORT right;
7856 short value;
7859 static DWORD parse_format0_kern_subtable(GdiFont *font,
7860 const struct TT_format0_kern_subtable *tt_f0_ks,
7861 const USHORT *glyph_to_char,
7862 KERNINGPAIR *kern_pair, DWORD cPairs)
7864 struct gdi_font *gdi_font = font->gdi_font;
7865 USHORT i, nPairs;
7866 const struct TT_kern_pair *tt_kern_pair;
7868 TRACE("font height %d, units_per_EM %d\n", gdi_font->ppem, font->ft_face->units_per_EM);
7870 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7872 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7873 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7874 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7876 if (!kern_pair || !cPairs)
7877 return nPairs;
7879 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7881 nPairs = min(nPairs, cPairs);
7883 for (i = 0; i < nPairs; i++)
7885 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7886 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7887 /* this algorithm appears to better match what Windows does */
7888 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * gdi_font->ppem;
7889 if (kern_pair->iKernAmount < 0)
7891 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7892 kern_pair->iKernAmount -= gdi_font->ppem;
7894 else if (kern_pair->iKernAmount > 0)
7896 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7897 kern_pair->iKernAmount += gdi_font->ppem;
7899 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7901 TRACE("left %u right %u value %d\n",
7902 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7904 kern_pair++;
7906 TRACE("copied %u entries\n", nPairs);
7907 return nPairs;
7910 /*************************************************************
7911 * freetype_GetKerningPairs
7913 static DWORD CDECL freetype_GetKerningPairs( struct gdi_font *gdi_font, DWORD cPairs, KERNINGPAIR *kern_pair )
7915 GdiFont *font = get_font_ptr(gdi_font);
7916 DWORD length;
7917 void *buf;
7918 const struct TT_kern_table *tt_kern_table;
7919 const struct TT_kern_subtable *tt_kern_subtable;
7920 USHORT i, nTables;
7921 USHORT *glyph_to_char;
7923 EnterCriticalSection( &freetype_cs );
7924 if (font->total_kern_pairs != (DWORD)-1)
7926 if (cPairs && kern_pair)
7928 cPairs = min(cPairs, font->total_kern_pairs);
7929 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7931 else cPairs = font->total_kern_pairs;
7933 LeaveCriticalSection( &freetype_cs );
7934 return cPairs;
7937 font->total_kern_pairs = 0;
7939 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7941 if (length == GDI_ERROR)
7943 TRACE("no kerning data in the font\n");
7944 LeaveCriticalSection( &freetype_cs );
7945 return 0;
7948 buf = HeapAlloc(GetProcessHeap(), 0, length);
7949 if (!buf)
7951 WARN("Out of memory\n");
7952 LeaveCriticalSection( &freetype_cs );
7953 return 0;
7956 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7958 /* build a glyph index to char code map */
7959 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7960 if (!glyph_to_char)
7962 WARN("Out of memory allocating a glyph index to char code map\n");
7963 HeapFree(GetProcessHeap(), 0, buf);
7964 LeaveCriticalSection( &freetype_cs );
7965 return 0;
7968 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7970 FT_UInt glyph_code;
7971 FT_ULong char_code;
7973 glyph_code = 0;
7974 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7976 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7977 font->ft_face->num_glyphs, glyph_code, char_code);
7979 while (glyph_code)
7981 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7983 /* FIXME: This doesn't match what Windows does: it does some fancy
7984 * things with duplicate glyph index to char code mappings, while
7985 * we just avoid overriding existing entries.
7987 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7988 glyph_to_char[glyph_code] = (USHORT)char_code;
7990 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7993 else
7995 DWORD encoding = RtlUlongByteSwap(font->ft_face->charmap->encoding);
7996 ULONG n;
7998 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
7999 for (n = 0; n <= 65535; n++)
8000 glyph_to_char[n] = (USHORT)n;
8003 tt_kern_table = buf;
8004 nTables = GET_BE_WORD(tt_kern_table->nTables);
8005 TRACE("version %u, nTables %u\n",
8006 GET_BE_WORD(tt_kern_table->version), nTables);
8008 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8010 for (i = 0; i < nTables; i++)
8012 struct TT_kern_subtable tt_kern_subtable_copy;
8014 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8015 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8016 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8018 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8019 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8020 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8022 /* According to the TrueType specification this is the only format
8023 * that will be properly interpreted by Windows and OS/2
8025 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8027 DWORD new_chunk, old_total = font->total_kern_pairs;
8029 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8030 glyph_to_char, NULL, 0);
8031 font->total_kern_pairs += new_chunk;
8033 if (!font->kern_pairs)
8034 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8035 font->total_kern_pairs * sizeof(*font->kern_pairs));
8036 else
8037 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8038 font->total_kern_pairs * sizeof(*font->kern_pairs));
8040 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8041 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8043 else
8044 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8046 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8049 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8050 HeapFree(GetProcessHeap(), 0, buf);
8052 if (cPairs && kern_pair)
8054 cPairs = min(cPairs, font->total_kern_pairs);
8055 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8057 else cPairs = font->total_kern_pairs;
8059 LeaveCriticalSection( &freetype_cs );
8060 return cPairs;
8063 static const struct font_backend_funcs font_funcs =
8065 freetype_EnumFonts,
8066 freetype_FontIsLinked,
8067 freetype_GetCharABCWidths,
8068 freetype_GetCharABCWidthsI,
8069 freetype_GetCharWidth,
8070 freetype_GetCharWidthInfo,
8071 freetype_GetFontData,
8072 freetype_GetFontUnicodeRanges,
8073 freetype_GetGlyphIndices,
8074 freetype_GetGlyphOutline,
8075 freetype_GetKerningPairs,
8076 freetype_GetOutlineTextMetrics,
8077 freetype_GetTextExtentExPoint,
8078 freetype_GetTextExtentExPointI,
8079 freetype_GetTextMetrics,
8080 freetype_SelectFont,
8081 freetype_AddFontResourceEx,
8082 freetype_RemoveFontResourceEx,
8083 freetype_AddFontMemResourceEx,
8084 freetype_CreateScalableFontResource,
8085 freetype_GetFontFileData,
8086 freetype_alloc_font,
8087 freetype_destroy_font
8090 #else /* HAVE_FREETYPE */
8092 /*************************************************************************/
8094 BOOL WineEngInit( const struct font_backend_funcs **funcs )
8096 return FALSE;
8099 #endif /* HAVE_FREETYPE */