gdi32/freetype: Handle fonts with broken usWinDescent values.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob8e89cc5acf7d246ac83b79fda2fdbede95154657
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 DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #ifdef HAVE_FT2BUILD_H
81 #include <ft2build.h>
82 #include FT_FREETYPE_H
83 #include FT_GLYPH_H
84 #include FT_TYPES_H
85 #include FT_TRUETYPE_TABLES_H
86 #include FT_SFNT_NAMES_H
87 #include FT_TRUETYPE_IDS_H
88 #include FT_OUTLINE_H
89 #include FT_TRIGONOMETRY_H
90 #include FT_MODULE_H
91 #include FT_WINFONTS_H
92 #ifdef FT_LCD_FILTER_H
93 #include FT_LCD_FILTER_H
94 #endif
95 #endif /* HAVE_FT2BUILD_H */
97 #include "windef.h"
98 #include "winbase.h"
99 #include "winternl.h"
100 #include "winerror.h"
101 #include "winreg.h"
102 #include "wingdi.h"
103 #include "gdi_private.h"
104 #include "wine/library.h"
105 #include "wine/unicode.h"
106 #include "wine/debug.h"
107 #include "wine/list.h"
109 #include "resource.h"
111 WINE_DEFAULT_DEBUG_CHANNEL(font);
113 #ifdef HAVE_FREETYPE
115 #ifndef HAVE_FT_TRUETYPEENGINETYPE
116 typedef enum
118 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
119 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
120 FT_TRUETYPE_ENGINE_TYPE_PATENTED
121 } FT_TrueTypeEngineType;
122 #endif
124 static FT_Library library = 0;
125 typedef struct
127 FT_Int major;
128 FT_Int minor;
129 FT_Int patch;
130 } FT_Version_t;
131 static FT_Version_t FT_Version;
132 static DWORD FT_SimpleVersion;
134 static void *ft_handle = NULL;
136 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
137 MAKE_FUNCPTR(FT_Done_Face);
138 MAKE_FUNCPTR(FT_Get_Char_Index);
139 MAKE_FUNCPTR(FT_Get_First_Char);
140 MAKE_FUNCPTR(FT_Get_Next_Char);
141 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
142 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
143 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
144 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
145 MAKE_FUNCPTR(FT_Init_FreeType);
146 MAKE_FUNCPTR(FT_Library_Version);
147 MAKE_FUNCPTR(FT_Load_Glyph);
148 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
149 MAKE_FUNCPTR(FT_Matrix_Multiply);
150 #ifdef FT_MULFIX_INLINED
151 #define pFT_MulFix FT_MULFIX_INLINED
152 #else
153 MAKE_FUNCPTR(FT_MulFix);
154 #endif
155 MAKE_FUNCPTR(FT_New_Face);
156 MAKE_FUNCPTR(FT_New_Memory_Face);
157 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
158 MAKE_FUNCPTR(FT_Outline_Get_CBox);
159 MAKE_FUNCPTR(FT_Outline_Transform);
160 MAKE_FUNCPTR(FT_Outline_Translate);
161 MAKE_FUNCPTR(FT_Render_Glyph);
162 MAKE_FUNCPTR(FT_Select_Charmap);
163 MAKE_FUNCPTR(FT_Set_Charmap);
164 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
165 MAKE_FUNCPTR(FT_Vector_Transform);
166 MAKE_FUNCPTR(FT_Vector_Unit);
167 static FT_Error (*pFT_Outline_Embolden)(FT_Outline *, FT_Pos);
168 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
169 #ifdef FT_LCD_FILTER_H
170 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
171 #endif
173 #ifdef SONAME_LIBFONTCONFIG
174 #include <fontconfig/fontconfig.h>
175 MAKE_FUNCPTR(FcConfigSubstitute);
176 MAKE_FUNCPTR(FcFontList);
177 MAKE_FUNCPTR(FcFontSetDestroy);
178 MAKE_FUNCPTR(FcInit);
179 MAKE_FUNCPTR(FcObjectSetAdd);
180 MAKE_FUNCPTR(FcObjectSetCreate);
181 MAKE_FUNCPTR(FcObjectSetDestroy);
182 MAKE_FUNCPTR(FcPatternCreate);
183 MAKE_FUNCPTR(FcPatternDestroy);
184 MAKE_FUNCPTR(FcPatternGetBool);
185 MAKE_FUNCPTR(FcPatternGetInteger);
186 MAKE_FUNCPTR(FcPatternGetString);
187 #endif
189 #undef MAKE_FUNCPTR
191 #ifndef FT_MAKE_TAG
192 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
193 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
194 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
195 #endif
197 #ifndef ft_encoding_none
198 #define FT_ENCODING_NONE ft_encoding_none
199 #endif
200 #ifndef ft_encoding_ms_symbol
201 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
202 #endif
203 #ifndef ft_encoding_unicode
204 #define FT_ENCODING_UNICODE ft_encoding_unicode
205 #endif
206 #ifndef ft_encoding_apple_roman
207 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
208 #endif
210 #ifdef WORDS_BIGENDIAN
211 #define GET_BE_WORD(x) (x)
212 #else
213 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
214 #endif
216 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
217 typedef struct {
218 FT_Short height;
219 FT_Short width;
220 FT_Pos size;
221 FT_Pos x_ppem;
222 FT_Pos y_ppem;
223 FT_Short internal_leading;
224 } Bitmap_Size;
226 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
227 So to let this compile on older versions of FreeType we'll define the
228 new structure here. */
229 typedef struct {
230 FT_Short height, width;
231 FT_Pos size, x_ppem, y_ppem;
232 } My_FT_Bitmap_Size;
234 struct enum_data
236 ENUMLOGFONTEXW elf;
237 NEWTEXTMETRICEXW ntm;
238 DWORD type;
241 typedef struct tagFace {
242 struct list entry;
243 unsigned int refcount;
244 WCHAR *StyleName;
245 WCHAR *FullName;
246 WCHAR *file;
247 dev_t dev;
248 ino_t ino;
249 void *font_data_ptr;
250 DWORD font_data_size;
251 FT_Long face_index;
252 FONTSIGNATURE fs;
253 DWORD ntmFlags;
254 FT_Fixed font_version;
255 BOOL scalable;
256 Bitmap_Size size; /* set if face is a bitmap */
257 DWORD flags; /* ADDFONT flags */
258 struct tagFamily *family;
259 /* Cached data for Enum */
260 struct enum_data *cached_enum_data;
261 } Face;
263 #define ADDFONT_EXTERNAL_FONT 0x01
264 #define ADDFONT_ALLOW_BITMAP 0x02
265 #define ADDFONT_ADD_TO_CACHE 0x04
266 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
267 #define ADDFONT_VERTICAL_FONT 0x10
268 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
270 typedef struct tagFamily {
271 struct list entry;
272 unsigned int refcount;
273 WCHAR *FamilyName;
274 WCHAR *EnglishName;
275 struct list faces;
276 struct list *replacement;
277 } Family;
279 typedef struct {
280 GLYPHMETRICS gm;
281 ABC abc; /* metrics of the unrotated char */
282 BOOL init;
283 } GM;
285 typedef struct {
286 FLOAT eM11, eM12;
287 FLOAT eM21, eM22;
288 } FMAT2;
290 typedef struct {
291 DWORD hash;
292 LOGFONTW lf;
293 FMAT2 matrix;
294 BOOL can_use_bitmap;
295 } FONT_DESC;
297 typedef struct tagGdiFont GdiFont;
299 typedef struct {
300 struct list entry;
301 Face *face;
302 GdiFont *font;
303 } CHILD_FONT;
305 struct tagGdiFont {
306 struct list entry;
307 struct list unused_entry;
308 unsigned int refcount;
309 GM **gm;
310 DWORD gmsize;
311 OUTLINETEXTMETRICW *potm;
312 DWORD total_kern_pairs;
313 KERNINGPAIR *kern_pairs;
314 struct list child_fonts;
316 /* the following members can be accessed without locking, they are never modified after creation */
317 FT_Face ft_face;
318 struct font_mapping *mapping;
319 LPWSTR name;
320 int charset;
321 int codepage;
322 BOOL fake_italic;
323 BOOL fake_bold;
324 BYTE underline;
325 BYTE strikeout;
326 INT orientation;
327 FONT_DESC font_desc;
328 LONG aveWidth, ppem;
329 double scale_y;
330 SHORT yMax;
331 SHORT yMin;
332 DWORD ntmFlags;
333 DWORD aa_flags;
334 UINT ntmCellHeight, ntmAvgWidth;
335 FONTSIGNATURE fs;
336 GdiFont *base_font;
337 VOID *GSUB_Table;
338 const VOID *vert_feature;
339 DWORD cache_num;
342 typedef struct {
343 struct list entry;
344 const WCHAR *font_name;
345 FONTSIGNATURE fs;
346 struct list links;
347 } SYSTEM_LINKS;
349 struct enum_charset_element {
350 DWORD mask;
351 DWORD charset;
352 WCHAR name[LF_FACESIZE];
355 struct enum_charset_list {
356 DWORD total;
357 struct enum_charset_element element[32];
360 #define GM_BLOCK_SIZE 128
361 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
363 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
364 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
365 static unsigned int unused_font_count;
366 #define UNUSED_CACHE_SIZE 10
367 static struct list system_links = LIST_INIT(system_links);
369 static struct list font_subst_list = LIST_INIT(font_subst_list);
371 static struct list font_list = LIST_INIT(font_list);
373 struct freetype_physdev
375 struct gdi_physdev dev;
376 GdiFont *font;
379 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
381 return (struct freetype_physdev *)dev;
384 static const struct gdi_dc_funcs freetype_funcs;
386 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
387 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
388 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
390 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
391 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
392 'W','i','n','d','o','w','s','\\',
393 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
394 'F','o','n','t','s','\0'};
396 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
397 'W','i','n','d','o','w','s',' ','N','T','\\',
398 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
399 'F','o','n','t','s','\0'};
401 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
402 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
403 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
404 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
406 static const WCHAR * const SystemFontValues[] = {
407 System_Value,
408 OEMFont_Value,
409 FixedSys_Value,
410 NULL
413 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
414 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
416 /* Interesting and well-known (frequently-assumed!) font names */
417 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
418 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 };
419 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
420 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
421 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
422 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
423 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
424 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
426 static const WCHAR arial[] = {'A','r','i','a','l',0};
427 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
428 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};
429 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};
430 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
431 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
432 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
433 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
434 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
435 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
437 static const WCHAR *default_serif_list[] =
439 times_new_roman,
440 liberation_serif,
441 bitstream_vera_serif,
442 NULL
445 static const WCHAR *default_fixed_list[] =
447 courier_new,
448 liberation_mono,
449 bitstream_vera_sans_mono,
450 NULL
453 static const WCHAR *default_sans_list[] =
455 arial,
456 liberation_sans,
457 bitstream_vera_sans,
458 NULL
461 typedef struct {
462 WCHAR *name;
463 INT charset;
464 } NameCs;
466 typedef struct tagFontSubst {
467 struct list entry;
468 NameCs from;
469 NameCs to;
470 } FontSubst;
472 /* Registry font cache key and value names */
473 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
474 'F','o','n','t','s',0};
475 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
476 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
477 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
478 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
479 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
480 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
481 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
482 static const WCHAR face_size_value[] = {'S','i','z','e',0};
483 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
484 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
485 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
486 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
487 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
488 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
489 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
492 struct font_mapping
494 struct list entry;
495 int refcount;
496 dev_t dev;
497 ino_t ino;
498 void *data;
499 size_t size;
502 static struct list mappings_list = LIST_INIT( mappings_list );
504 static UINT default_aa_flags;
505 static HKEY hkey_font_cache;
507 static CRITICAL_SECTION freetype_cs;
508 static CRITICAL_SECTION_DEBUG critsect_debug =
510 0, 0, &freetype_cs,
511 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
512 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
514 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
516 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
518 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
519 static BOOL use_default_fallback = FALSE;
521 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL *vert);
522 static BOOL get_outline_text_metrics(GdiFont *font);
523 static BOOL get_bitmap_text_metrics(GdiFont *font);
524 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
525 static void remove_face_from_cache( Face *face );
527 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
528 'W','i','n','d','o','w','s',' ','N','T','\\',
529 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
530 'S','y','s','t','e','m','L','i','n','k',0};
532 /****************************************
533 * Notes on .fon files
535 * The fonts System, FixedSys and Terminal are special. There are typically multiple
536 * versions installed for different resolutions and codepages. Windows stores which one to use
537 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
538 * Key Meaning
539 * FIXEDFON.FON FixedSys
540 * FONTS.FON System
541 * OEMFONT.FON Terminal
542 * LogPixels Current dpi set by the display control panel applet
543 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
544 * also has a LogPixels value that appears to mirror this)
546 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
547 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
548 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
549 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
550 * so that makes sense.
552 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
553 * to be mapped into the registry on Windows 2000 at least).
554 * I have
555 * woafont=app850.fon
556 * ega80woa.fon=ega80850.fon
557 * ega40woa.fon=ega40850.fon
558 * cga80woa.fon=cga80850.fon
559 * cga40woa.fon=cga40850.fon
562 /* These are all structures needed for the GSUB table */
564 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
566 typedef struct {
567 DWORD version;
568 WORD ScriptList;
569 WORD FeatureList;
570 WORD LookupList;
571 } GSUB_Header;
573 typedef struct {
574 CHAR ScriptTag[4];
575 WORD Script;
576 } GSUB_ScriptRecord;
578 typedef struct {
579 WORD ScriptCount;
580 GSUB_ScriptRecord ScriptRecord[1];
581 } GSUB_ScriptList;
583 typedef struct {
584 CHAR LangSysTag[4];
585 WORD LangSys;
586 } GSUB_LangSysRecord;
588 typedef struct {
589 WORD DefaultLangSys;
590 WORD LangSysCount;
591 GSUB_LangSysRecord LangSysRecord[1];
592 } GSUB_Script;
594 typedef struct {
595 WORD LookupOrder; /* Reserved */
596 WORD ReqFeatureIndex;
597 WORD FeatureCount;
598 WORD FeatureIndex[1];
599 } GSUB_LangSys;
601 typedef struct {
602 CHAR FeatureTag[4];
603 WORD Feature;
604 } GSUB_FeatureRecord;
606 typedef struct {
607 WORD FeatureCount;
608 GSUB_FeatureRecord FeatureRecord[1];
609 } GSUB_FeatureList;
611 typedef struct {
612 WORD FeatureParams; /* Reserved */
613 WORD LookupCount;
614 WORD LookupListIndex[1];
615 } GSUB_Feature;
617 typedef struct {
618 WORD LookupCount;
619 WORD Lookup[1];
620 } GSUB_LookupList;
622 typedef struct {
623 WORD LookupType;
624 WORD LookupFlag;
625 WORD SubTableCount;
626 WORD SubTable[1];
627 } GSUB_LookupTable;
629 typedef struct {
630 WORD CoverageFormat;
631 WORD GlyphCount;
632 WORD GlyphArray[1];
633 } GSUB_CoverageFormat1;
635 typedef struct {
636 WORD Start;
637 WORD End;
638 WORD StartCoverageIndex;
639 } GSUB_RangeRecord;
641 typedef struct {
642 WORD CoverageFormat;
643 WORD RangeCount;
644 GSUB_RangeRecord RangeRecord[1];
645 } GSUB_CoverageFormat2;
647 typedef struct {
648 WORD SubstFormat; /* = 1 */
649 WORD Coverage;
650 WORD DeltaGlyphID;
651 } GSUB_SingleSubstFormat1;
653 typedef struct {
654 WORD SubstFormat; /* = 2 */
655 WORD Coverage;
656 WORD GlyphCount;
657 WORD Substitute[1];
658 }GSUB_SingleSubstFormat2;
660 #ifdef HAVE_CARBON_CARBON_H
661 static char *find_cache_dir(void)
663 FSRef ref;
664 OSErr err;
665 static char cached_path[MAX_PATH];
666 static const char *wine = "/Wine", *fonts = "/Fonts";
668 if(*cached_path) return cached_path;
670 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
671 if(err != noErr)
673 WARN("can't create cached data folder\n");
674 return NULL;
676 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
677 if(err != noErr)
679 WARN("can't create cached data path\n");
680 *cached_path = '\0';
681 return NULL;
683 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
685 ERR("Could not create full path\n");
686 *cached_path = '\0';
687 return NULL;
689 strcat(cached_path, wine);
691 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
693 WARN("Couldn't mkdir %s\n", cached_path);
694 *cached_path = '\0';
695 return NULL;
697 strcat(cached_path, fonts);
698 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
700 WARN("Couldn't mkdir %s\n", cached_path);
701 *cached_path = '\0';
702 return NULL;
704 return cached_path;
707 /******************************************************************
708 * expand_mac_font
710 * Extracts individual TrueType font files from a Mac suitcase font
711 * and saves them into the user's caches directory (see
712 * find_cache_dir()).
713 * Returns a NULL terminated array of filenames.
715 * We do this because they are apps that try to read ttf files
716 * themselves and they don't like Mac suitcase files.
718 static char **expand_mac_font(const char *path)
720 FSRef ref;
721 SInt16 res_ref;
722 OSStatus s;
723 unsigned int idx;
724 const char *out_dir;
725 const char *filename;
726 int output_len;
727 struct {
728 char **array;
729 unsigned int size, max_size;
730 } ret;
732 TRACE("path %s\n", path);
734 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
735 if(s != noErr)
737 WARN("failed to get ref\n");
738 return NULL;
741 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
742 if(s != noErr)
744 TRACE("no data fork, so trying resource fork\n");
745 res_ref = FSOpenResFile(&ref, fsRdPerm);
746 if(res_ref == -1)
748 TRACE("unable to open resource fork\n");
749 return NULL;
753 ret.size = 0;
754 ret.max_size = 10;
755 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
756 if(!ret.array)
758 CloseResFile(res_ref);
759 return NULL;
762 out_dir = find_cache_dir();
764 filename = strrchr(path, '/');
765 if(!filename) filename = path;
766 else filename++;
768 /* output filename has the form out_dir/filename_%04x.ttf */
769 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
771 UseResFile(res_ref);
772 idx = 1;
773 while(1)
775 FamRec *fam_rec;
776 unsigned short *num_faces_ptr, num_faces, face;
777 AsscEntry *assoc;
778 Handle fond;
779 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
781 fond = Get1IndResource(fond_res, idx);
782 if(!fond) break;
783 TRACE("got fond resource %d\n", idx);
784 HLock(fond);
786 fam_rec = *(FamRec**)fond;
787 num_faces_ptr = (unsigned short *)(fam_rec + 1);
788 num_faces = GET_BE_WORD(*num_faces_ptr);
789 num_faces++;
790 assoc = (AsscEntry*)(num_faces_ptr + 1);
791 TRACE("num faces %04x\n", num_faces);
792 for(face = 0; face < num_faces; face++, assoc++)
794 Handle sfnt;
795 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
796 unsigned short size, font_id;
797 char *output;
799 size = GET_BE_WORD(assoc->fontSize);
800 font_id = GET_BE_WORD(assoc->fontID);
801 if(size != 0)
803 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
804 continue;
807 TRACE("trying to load sfnt id %04x\n", font_id);
808 sfnt = GetResource(sfnt_res, font_id);
809 if(!sfnt)
811 TRACE("can't get sfnt resource %04x\n", font_id);
812 continue;
815 output = HeapAlloc(GetProcessHeap(), 0, output_len);
816 if(output)
818 int fd;
820 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
822 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
823 if(fd != -1 || errno == EEXIST)
825 if(fd != -1)
827 unsigned char *sfnt_data;
829 HLock(sfnt);
830 sfnt_data = *(unsigned char**)sfnt;
831 write(fd, sfnt_data, GetHandleSize(sfnt));
832 HUnlock(sfnt);
833 close(fd);
835 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
837 ret.max_size *= 2;
838 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
840 ret.array[ret.size++] = output;
842 else
844 WARN("unable to create %s\n", output);
845 HeapFree(GetProcessHeap(), 0, output);
848 ReleaseResource(sfnt);
850 HUnlock(fond);
851 ReleaseResource(fond);
852 idx++;
854 CloseResFile(res_ref);
856 return ret.array;
859 #endif /* HAVE_CARBON_CARBON_H */
861 static inline BOOL is_win9x(void)
863 return GetVersion() & 0x80000000;
866 This function builds an FT_Fixed from a double. It fails if the absolute
867 value of the float number is greater than 32768.
869 static inline FT_Fixed FT_FixedFromFloat(double f)
871 return f * 0x10000;
875 This function builds an FT_Fixed from a FIXED. It simply put f.value
876 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
878 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
880 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
883 static BOOL is_hinting_enabled(void)
885 static int enabled = -1;
887 if (enabled == -1)
889 /* Use the >= 2.2.0 function if available */
890 if (pFT_Get_TrueType_Engine_Type)
892 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
893 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
895 else enabled = FALSE;
896 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
898 return enabled;
901 static BOOL is_subpixel_rendering_enabled( void )
903 #ifdef FT_LCD_FILTER_H
904 static int enabled = -1;
905 if (enabled == -1)
907 enabled = (pFT_Library_SetLcdFilter &&
908 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
909 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
911 return enabled;
912 #else
913 return FALSE;
914 #endif
918 static const struct list *get_face_list_from_family(const Family *family)
920 if (!list_empty(&family->faces))
921 return &family->faces;
922 else
923 return family->replacement;
926 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
928 Family *family;
929 Face *face;
930 const WCHAR *file;
932 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
934 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
936 const struct list *face_list;
937 if(face_name && strcmpiW(face_name, family->FamilyName))
938 continue;
939 face_list = get_face_list_from_family(family);
940 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
942 if (!face->file)
943 continue;
944 file = strrchrW(face->file, '/');
945 if(!file)
946 file = face->file;
947 else
948 file++;
949 if(strcmpiW(file, file_name)) continue;
950 face->refcount++;
951 return face;
954 return NULL;
957 static Family *find_family_from_name(const WCHAR *name)
959 Family *family;
961 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
963 if(!strcmpiW(family->FamilyName, name))
964 return family;
967 return NULL;
970 static Family *find_family_from_any_name(const WCHAR *name)
972 Family *family;
974 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
976 if(!strcmpiW(family->FamilyName, name))
977 return family;
978 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
979 return family;
982 return NULL;
985 static void DumpSubstList(void)
987 FontSubst *psub;
989 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
991 if(psub->from.charset != -1 || psub->to.charset != -1)
992 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
993 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
994 else
995 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
996 debugstr_w(psub->to.name));
1000 static LPWSTR strdupW(LPCWSTR p)
1002 LPWSTR ret;
1003 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1004 ret = HeapAlloc(GetProcessHeap(), 0, len);
1005 memcpy(ret, p, len);
1006 return ret;
1009 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1010 INT from_charset)
1012 FontSubst *element;
1014 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1016 if(!strcmpiW(element->from.name, from_name) &&
1017 (element->from.charset == from_charset ||
1018 element->from.charset == -1))
1019 return element;
1022 return NULL;
1025 #define ADD_FONT_SUBST_FORCE 1
1027 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1029 FontSubst *from_exist, *to_exist;
1031 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1033 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1035 list_remove(&from_exist->entry);
1036 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1037 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1038 HeapFree(GetProcessHeap(), 0, from_exist);
1039 from_exist = NULL;
1042 if(!from_exist)
1044 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1046 if(to_exist)
1048 HeapFree(GetProcessHeap(), 0, subst->to.name);
1049 subst->to.name = strdupW(to_exist->to.name);
1052 list_add_tail(subst_list, &subst->entry);
1054 return TRUE;
1057 HeapFree(GetProcessHeap(), 0, subst->from.name);
1058 HeapFree(GetProcessHeap(), 0, subst->to.name);
1059 HeapFree(GetProcessHeap(), 0, subst);
1060 return FALSE;
1063 static WCHAR *towstr(UINT cp, const char *str)
1065 int len;
1066 WCHAR *wstr;
1068 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1069 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1070 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1071 return wstr;
1074 static char *strWtoA(UINT cp, const WCHAR *str)
1076 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1077 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1078 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1079 return ret;
1082 static void split_subst_info(NameCs *nc, LPSTR str)
1084 CHAR *p = strrchr(str, ',');
1086 nc->charset = -1;
1087 if(p && *(p+1)) {
1088 nc->charset = strtol(p+1, NULL, 10);
1089 *p = '\0';
1091 nc->name = towstr(CP_ACP, str);
1094 static void LoadSubstList(void)
1096 FontSubst *psub;
1097 HKEY hkey;
1098 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1099 LPSTR value;
1100 LPVOID data;
1102 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1103 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1104 &hkey) == ERROR_SUCCESS) {
1106 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1107 &valuelen, &datalen, NULL, NULL);
1109 valuelen++; /* returned value doesn't include room for '\0' */
1110 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1111 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1113 dlen = datalen;
1114 vlen = valuelen;
1115 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1116 &dlen) == ERROR_SUCCESS) {
1117 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1119 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1120 split_subst_info(&psub->from, value);
1121 split_subst_info(&psub->to, data);
1123 /* Win 2000 doesn't allow mapping between different charsets
1124 or mapping of DEFAULT_CHARSET */
1125 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1126 psub->to.charset == DEFAULT_CHARSET) {
1127 HeapFree(GetProcessHeap(), 0, psub->to.name);
1128 HeapFree(GetProcessHeap(), 0, psub->from.name);
1129 HeapFree(GetProcessHeap(), 0, psub);
1130 } else {
1131 add_font_subst(&font_subst_list, psub, 0);
1133 /* reset dlen and vlen */
1134 dlen = datalen;
1135 vlen = valuelen;
1137 HeapFree(GetProcessHeap(), 0, data);
1138 HeapFree(GetProcessHeap(), 0, value);
1139 RegCloseKey(hkey);
1144 static const LANGID mac_langid_table[] =
1146 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
1147 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
1148 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
1149 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
1150 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
1151 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
1152 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
1153 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
1154 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
1155 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
1156 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
1157 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
1158 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
1159 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
1160 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
1161 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
1162 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
1163 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
1164 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
1165 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1166 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
1167 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
1168 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
1169 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
1170 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
1171 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
1172 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
1173 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
1174 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
1175 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
1176 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
1177 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
1178 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
1179 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1180 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
1181 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
1182 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
1183 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
1184 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
1185 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
1186 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
1187 0, /* TT_MAC_LANGID_YIDDISH */
1188 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
1189 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
1190 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
1191 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
1192 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
1193 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
1194 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
1195 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
1196 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1197 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
1198 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
1199 0, /* TT_MAC_LANGID_MOLDAVIAN */
1200 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
1201 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
1202 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
1203 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
1204 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1205 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
1206 0, /* TT_MAC_LANGID_KURDISH */
1207 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
1208 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
1209 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
1210 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
1211 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
1212 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
1213 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
1214 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
1215 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
1216 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
1217 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
1218 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
1219 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
1220 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
1221 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
1222 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
1223 0, /* TT_MAC_LANGID_BURMESE */
1224 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
1225 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
1226 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
1227 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
1228 0, /* TT_MAC_LANGID_TAGALOG */
1229 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1230 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1231 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
1232 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
1233 0, /* TT_MAC_LANGID_GALLA */
1234 0, /* TT_MAC_LANGID_SOMALI */
1235 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
1236 0, /* TT_MAC_LANGID_RUANDA */
1237 0, /* TT_MAC_LANGID_RUNDI */
1238 0, /* TT_MAC_LANGID_CHEWA */
1239 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
1240 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
1241 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1242 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1243 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
1244 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
1245 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
1246 0, /* TT_MAC_LANGID_LATIN */
1247 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
1248 0, /* TT_MAC_LANGID_GUARANI */
1249 0, /* TT_MAC_LANGID_AYMARA */
1250 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
1251 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
1252 0, /* TT_MAC_LANGID_DZONGKHA */
1253 0, /* TT_MAC_LANGID_JAVANESE */
1254 0, /* TT_MAC_LANGID_SUNDANESE */
1255 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
1256 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
1257 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
1258 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
1259 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1260 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
1261 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
1262 0, /* TT_MAC_LANGID_TONGAN */
1263 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1264 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
1265 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1268 static inline WORD get_mac_code_page( const FT_SfntName *name )
1270 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
1271 return 10000 + name->encoding_id;
1274 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
1276 LANGID name_lang;
1277 int res = 0;
1279 switch (name->platform_id)
1281 case TT_PLATFORM_MICROSOFT:
1282 res += 5; /* prefer the Microsoft name */
1283 switch (name->encoding_id)
1285 case TT_MS_ID_UNICODE_CS:
1286 case TT_MS_ID_SYMBOL_CS:
1287 name_lang = name->language_id;
1288 break;
1289 default:
1290 return 0;
1292 break;
1293 case TT_PLATFORM_MACINTOSH:
1294 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
1295 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1296 name_lang = mac_langid_table[name->language_id];
1297 break;
1298 case TT_PLATFORM_APPLE_UNICODE:
1299 res += 2; /* prefer Unicode encodings */
1300 switch (name->encoding_id)
1302 case TT_APPLE_ID_DEFAULT:
1303 case TT_APPLE_ID_ISO_10646:
1304 case TT_APPLE_ID_UNICODE_2_0:
1305 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1306 name_lang = mac_langid_table[name->language_id];
1307 break;
1308 default:
1309 return 0;
1311 break;
1312 default:
1313 return 0;
1315 if (name_lang == lang) res += 30;
1316 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
1317 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
1318 return res;
1321 static WCHAR *copy_name_table_string( const FT_SfntName *name )
1323 WCHAR *ret;
1324 WORD codepage;
1325 int i;
1327 switch (name->platform_id)
1329 case TT_PLATFORM_APPLE_UNICODE:
1330 case TT_PLATFORM_MICROSOFT:
1331 ret = HeapAlloc( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
1332 for (i = 0; i < name->string_len / 2; i++)
1333 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
1334 ret[i] = 0;
1335 return ret;
1336 case TT_PLATFORM_MACINTOSH:
1337 codepage = get_mac_code_page( name );
1338 i = MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, NULL, 0 );
1339 ret = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(WCHAR) );
1340 MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, ret, i );
1341 ret[i] = 0;
1342 return ret;
1344 return NULL;
1347 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
1349 FT_SfntName name;
1350 FT_UInt num_names, name_index;
1351 int res, best_lang = 0, best_index = -1;
1353 if (!FT_IS_SFNT(ft_face)) return NULL;
1355 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
1357 for (name_index = 0; name_index < num_names; name_index++)
1359 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
1360 if (name.name_id != name_id) continue;
1361 res = match_name_table_language( &name, language_id );
1362 if (res > best_lang)
1364 best_lang = res;
1365 best_index = name_index;
1369 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
1371 WCHAR *ret = copy_name_table_string( &name );
1372 TRACE( "name %u found platform %u lang %04x %s\n",
1373 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
1374 return ret;
1376 return NULL;
1379 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1381 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1382 if (f1->scalable) return TRUE;
1383 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1384 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1387 static void release_family( Family *family )
1389 if (--family->refcount) return;
1390 assert( list_empty( &family->faces ));
1391 list_remove( &family->entry );
1392 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1393 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1394 HeapFree( GetProcessHeap(), 0, family );
1397 static void release_face( Face *face )
1399 if (--face->refcount) return;
1400 if (face->family)
1402 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1403 list_remove( &face->entry );
1404 release_family( face->family );
1406 HeapFree( GetProcessHeap(), 0, face->file );
1407 HeapFree( GetProcessHeap(), 0, face->StyleName );
1408 HeapFree( GetProcessHeap(), 0, face->FullName );
1409 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1410 HeapFree( GetProcessHeap(), 0, face );
1413 static inline int style_order(const Face *face)
1415 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1417 case NTM_REGULAR:
1418 return 0;
1419 case NTM_BOLD:
1420 return 1;
1421 case NTM_ITALIC:
1422 return 2;
1423 case NTM_BOLD | NTM_ITALIC:
1424 return 3;
1425 default:
1426 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1427 debugstr_w(face->family->FamilyName),
1428 debugstr_w(face->StyleName),
1429 face->ntmFlags);
1430 return 9999;
1434 static BOOL insert_face_in_family_list( Face *face, Family *family )
1436 Face *cursor;
1438 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1440 if (faces_equal( face, cursor ))
1442 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1443 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1444 cursor->font_version, face->font_version);
1446 if (face->file && face->dev == cursor->dev && face->ino == cursor->ino)
1448 cursor->refcount++;
1449 TRACE("Font %s already in list, refcount now %d\n",
1450 debugstr_w(face->file), cursor->refcount);
1451 return FALSE;
1453 if (face->font_version <= cursor->font_version)
1455 TRACE("Original font %s is newer so skipping %s\n",
1456 debugstr_w(cursor->file), debugstr_w(face->file));
1457 return FALSE;
1459 else
1461 TRACE("Replacing original %s with %s\n",
1462 debugstr_w(cursor->file), debugstr_w(face->file));
1463 list_add_before( &cursor->entry, &face->entry );
1464 face->family = family;
1465 family->refcount++;
1466 face->refcount++;
1467 release_face( cursor );
1468 return TRUE;
1471 else
1472 TRACE("Adding new %s\n", debugstr_w(face->file));
1474 if (style_order( face ) < style_order( cursor )) break;
1477 list_add_before( &cursor->entry, &face->entry );
1478 face->family = family;
1479 family->refcount++;
1480 face->refcount++;
1481 return TRUE;
1484 /****************************************************************
1485 * NB This function stores the ptrs to the strings to save copying.
1486 * Don't free them after calling.
1488 static Family *create_family( WCHAR *name, WCHAR *english_name )
1490 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1491 family->refcount = 1;
1492 family->FamilyName = name;
1493 family->EnglishName = english_name;
1494 list_init( &family->faces );
1495 family->replacement = &family->faces;
1496 list_add_tail( &font_list, &family->entry );
1498 return family;
1501 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1503 DWORD type, size = sizeof(DWORD);
1505 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1506 type != REG_DWORD || size != sizeof(DWORD))
1508 *data = 0;
1509 return ERROR_BAD_CONFIGURATION;
1511 return ERROR_SUCCESS;
1514 static inline LONG reg_load_ftlong(HKEY hkey, const WCHAR *value, FT_Long *data)
1516 DWORD dw;
1517 LONG ret = reg_load_dword(hkey, value, &dw);
1518 *data = dw;
1519 return ret;
1522 static inline LONG reg_load_ftshort(HKEY hkey, const WCHAR *value, FT_Short *data)
1524 DWORD dw;
1525 LONG ret = reg_load_dword(hkey, value, &dw);
1526 *data = dw;
1527 return ret;
1530 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1532 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1535 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1537 DWORD needed, strike_index = 0;
1538 HKEY hkey_strike;
1540 /* If we have a File Name key then this is a real font, not just the parent
1541 key of a bunch of non-scalable strikes */
1542 needed = buffer_size;
1543 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1545 Face *face;
1546 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1547 face->cached_enum_data = NULL;
1548 face->family = NULL;
1550 face->refcount = 1;
1551 face->file = strdupW( buffer );
1552 face->StyleName = strdupW(face_name);
1554 needed = buffer_size;
1555 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1556 face->FullName = strdupW( buffer );
1557 else
1558 face->FullName = NULL;
1560 reg_load_ftlong(hkey_face, face_index_value, &face->face_index);
1561 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1562 reg_load_ftlong(hkey_face, face_version_value, &face->font_version);
1563 reg_load_dword(hkey_face, face_flags_value, &face->flags);
1565 needed = sizeof(face->fs);
1566 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1568 if(reg_load_ftshort(hkey_face, face_height_value, &face->size.height) != ERROR_SUCCESS)
1570 face->scalable = TRUE;
1571 memset(&face->size, 0, sizeof(face->size));
1573 else
1575 face->scalable = FALSE;
1576 reg_load_ftshort(hkey_face, face_width_value, &face->size.width);
1577 reg_load_ftlong(hkey_face, face_size_value, &face->size.size);
1578 reg_load_ftlong(hkey_face, face_x_ppem_value, &face->size.x_ppem);
1579 reg_load_ftlong(hkey_face, face_y_ppem_value, &face->size.y_ppem);
1580 reg_load_ftshort(hkey_face, face_internal_leading_value, &face->size.internal_leading);
1582 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1583 face->size.height, face->size.width, face->size.size >> 6,
1584 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1587 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1588 face->fs.fsCsb[0], face->fs.fsCsb[1],
1589 face->fs.fsUsb[0], face->fs.fsUsb[1],
1590 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1592 if (insert_face_in_family_list(face, family))
1593 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1595 release_face( face );
1598 /* load bitmap strikes */
1600 needed = buffer_size;
1601 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1603 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1605 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1606 RegCloseKey(hkey_strike);
1608 needed = buffer_size;
1612 /* move vertical fonts after their horizontal counterpart */
1613 /* assumes that font_list is already sorted by family name */
1614 static void reorder_vertical_fonts(void)
1616 Family *family, *next, *vert_family;
1617 struct list *ptr, *vptr;
1618 struct list vertical_families = LIST_INIT( vertical_families );
1620 LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
1622 if (family->FamilyName[0] != '@') continue;
1623 list_remove( &family->entry );
1624 list_add_tail( &vertical_families, &family->entry );
1627 ptr = list_head( &font_list );
1628 vptr = list_head( &vertical_families );
1629 while (ptr && vptr)
1631 family = LIST_ENTRY( ptr, Family, entry );
1632 vert_family = LIST_ENTRY( vptr, Family, entry );
1633 if (strcmpiW( family->FamilyName, vert_family->FamilyName + 1 ) > 0)
1635 list_remove( vptr );
1636 list_add_before( ptr, vptr );
1637 vptr = list_head( &vertical_families );
1639 else ptr = list_next( &font_list, ptr );
1641 list_move_tail( &font_list, &vertical_families );
1644 static void load_font_list_from_cache(HKEY hkey_font_cache)
1646 DWORD size, family_index = 0;
1647 Family *family;
1648 HKEY hkey_family;
1649 WCHAR buffer[4096];
1651 size = sizeof(buffer);
1652 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1654 WCHAR *english_family = NULL;
1655 WCHAR *family_name = strdupW( buffer );
1656 DWORD face_index = 0;
1658 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1659 TRACE("opened family key %s\n", debugstr_w(family_name));
1660 size = sizeof(buffer);
1661 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1662 english_family = strdupW( buffer );
1664 family = create_family(family_name, english_family);
1666 if(english_family)
1668 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1669 subst->from.name = strdupW(english_family);
1670 subst->from.charset = -1;
1671 subst->to.name = strdupW(family_name);
1672 subst->to.charset = -1;
1673 add_font_subst(&font_subst_list, subst, 0);
1676 size = sizeof(buffer);
1677 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1679 WCHAR *face_name = strdupW( buffer );
1680 HKEY hkey_face;
1682 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1684 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1685 RegCloseKey(hkey_face);
1687 HeapFree( GetProcessHeap(), 0, face_name );
1688 size = sizeof(buffer);
1690 RegCloseKey(hkey_family);
1691 release_family( family );
1692 size = sizeof(buffer);
1695 reorder_vertical_fonts();
1698 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1700 LONG ret;
1701 HKEY hkey_wine_fonts;
1703 /* We don't want to create the fonts key as volatile, so open this first */
1704 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1705 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1706 if(ret != ERROR_SUCCESS)
1708 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1709 return ret;
1712 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1713 KEY_ALL_ACCESS, NULL, hkey, disposition);
1714 RegCloseKey(hkey_wine_fonts);
1715 return ret;
1718 static void add_face_to_cache(Face *face)
1720 HKEY hkey_family, hkey_face;
1721 WCHAR *face_key_name;
1723 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1724 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1725 if(face->family->EnglishName)
1726 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1727 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1729 if(face->scalable)
1730 face_key_name = face->StyleName;
1731 else
1733 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1734 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1735 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1737 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1738 &hkey_face, NULL);
1739 if(!face->scalable)
1740 HeapFree(GetProcessHeap(), 0, face_key_name);
1742 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1743 (strlenW(face->file) + 1) * sizeof(WCHAR));
1744 if (face->FullName)
1745 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1746 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1748 reg_save_dword(hkey_face, face_index_value, face->face_index);
1749 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1750 reg_save_dword(hkey_face, face_version_value, face->font_version);
1751 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1753 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1755 if(!face->scalable)
1757 reg_save_dword(hkey_face, face_height_value, face->size.height);
1758 reg_save_dword(hkey_face, face_width_value, face->size.width);
1759 reg_save_dword(hkey_face, face_size_value, face->size.size);
1760 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1761 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1762 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1764 RegCloseKey(hkey_face);
1765 RegCloseKey(hkey_family);
1768 static void remove_face_from_cache( Face *face )
1770 HKEY hkey_family;
1772 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1774 if (face->scalable)
1776 RegDeleteKeyW( hkey_family, face->StyleName );
1778 else
1780 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1781 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1782 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1783 RegDeleteKeyW( hkey_family, face_key_name );
1784 HeapFree(GetProcessHeap(), 0, face_key_name);
1786 RegCloseKey(hkey_family);
1789 static WCHAR *prepend_at(WCHAR *family)
1791 WCHAR *str;
1793 if (!family)
1794 return NULL;
1796 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1797 str[0] = '@';
1798 strcpyW(str + 1, family);
1799 HeapFree(GetProcessHeap(), 0, family);
1800 return str;
1803 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1805 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) );
1806 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1808 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1809 if (!*name)
1811 *name = *english;
1812 *english = NULL;
1814 else if (!strcmpiW( *name, *english ))
1816 HeapFree( GetProcessHeap(), 0, *english );
1817 *english = NULL;
1820 if (vertical)
1822 *name = prepend_at( *name );
1823 *english = prepend_at( *english );
1827 static Family *get_family( FT_Face ft_face, BOOL vertical )
1829 Family *family;
1830 WCHAR *name, *english_name;
1832 get_family_names( ft_face, &name, &english_name, vertical );
1834 family = find_family_from_name( name );
1836 if (!family)
1838 family = create_family( name, english_name );
1839 if (english_name)
1841 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1842 subst->from.name = strdupW( english_name );
1843 subst->from.charset = -1;
1844 subst->to.name = strdupW( name );
1845 subst->to.charset = -1;
1846 add_font_subst( &font_subst_list, subst, 0 );
1849 else
1851 HeapFree( GetProcessHeap(), 0, name );
1852 HeapFree( GetProcessHeap(), 0, english_name );
1853 family->refcount++;
1856 return family;
1859 static inline FT_Fixed get_font_version( FT_Face ft_face )
1861 FT_Fixed version = 0;
1862 TT_Header *header;
1864 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1865 if (header) version = header->Font_Revision;
1867 return version;
1870 static inline DWORD get_ntm_flags( FT_Face ft_face )
1872 DWORD flags = 0;
1873 FT_ULong table_size = 0;
1875 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1876 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1877 if (flags == 0) flags = NTM_REGULAR;
1879 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1880 flags |= NTM_PS_OPENTYPE;
1882 return flags;
1885 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1887 My_FT_Bitmap_Size *size;
1888 FT_WinFNT_HeaderRec winfnt_header;
1890 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1891 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1892 size->height, size->width, size->size >> 6,
1893 size->x_ppem >> 6, size->y_ppem >> 6);
1894 face_size->height = size->height;
1895 face_size->width = size->width;
1896 face_size->size = size->size;
1897 face_size->x_ppem = size->x_ppem;
1898 face_size->y_ppem = size->y_ppem;
1900 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
1901 face_size->internal_leading = winfnt_header.internal_leading;
1902 if (winfnt_header.external_leading > 0 &&
1903 (face_size->height ==
1904 winfnt_header.pixel_height + winfnt_header.external_leading))
1905 face_size->height = winfnt_header.pixel_height;
1909 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1911 TT_OS2 *os2;
1912 FT_UInt dummy;
1913 CHARSETINFO csi;
1914 FT_WinFNT_HeaderRec winfnt_header;
1915 int i;
1917 memset( fs, 0, sizeof(*fs) );
1919 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1920 if (os2)
1922 fs->fsUsb[0] = os2->ulUnicodeRange1;
1923 fs->fsUsb[1] = os2->ulUnicodeRange2;
1924 fs->fsUsb[2] = os2->ulUnicodeRange3;
1925 fs->fsUsb[3] = os2->ulUnicodeRange4;
1927 if (os2->version == 0)
1929 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1930 fs->fsCsb[0] = FS_LATIN1;
1931 else
1932 fs->fsCsb[0] = FS_SYMBOL;
1934 else
1936 fs->fsCsb[0] = os2->ulCodePageRange1;
1937 fs->fsCsb[1] = os2->ulCodePageRange2;
1940 else
1942 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1944 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1945 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1946 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1947 *fs = csi.fs;
1951 if (fs->fsCsb[0] == 0)
1953 /* let's see if we can find any interesting cmaps */
1954 for (i = 0; i < ft_face->num_charmaps; i++)
1956 switch (ft_face->charmaps[i]->encoding)
1958 case FT_ENCODING_UNICODE:
1959 case FT_ENCODING_APPLE_ROMAN:
1960 fs->fsCsb[0] |= FS_LATIN1;
1961 break;
1962 case FT_ENCODING_MS_SYMBOL:
1963 fs->fsCsb[0] |= FS_SYMBOL;
1964 break;
1965 default:
1966 break;
1972 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1973 DWORD flags )
1975 struct stat st;
1976 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1978 face->refcount = 1;
1979 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1980 if (!face->StyleName) face->StyleName = towstr( CP_ACP, ft_face->style_name );
1982 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1983 if (flags & ADDFONT_VERTICAL_FONT)
1984 face->FullName = prepend_at( face->FullName );
1986 face->dev = 0;
1987 face->ino = 0;
1988 if (file)
1990 face->file = towstr( CP_UNIXCP, file );
1991 face->font_data_ptr = NULL;
1992 face->font_data_size = 0;
1993 if (!stat( file, &st ))
1995 face->dev = st.st_dev;
1996 face->ino = st.st_ino;
1999 else
2001 face->file = NULL;
2002 face->font_data_ptr = font_data_ptr;
2003 face->font_data_size = font_data_size;
2006 face->face_index = face_index;
2007 get_fontsig( ft_face, &face->fs );
2008 face->ntmFlags = get_ntm_flags( ft_face );
2009 face->font_version = get_font_version( ft_face );
2011 if (FT_IS_SCALABLE( ft_face ))
2013 memset( &face->size, 0, sizeof(face->size) );
2014 face->scalable = TRUE;
2016 else
2018 get_bitmap_size( ft_face, &face->size );
2019 face->scalable = FALSE;
2022 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
2023 face->flags = flags;
2024 face->family = NULL;
2025 face->cached_enum_data = NULL;
2027 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2028 face->fs.fsCsb[0], face->fs.fsCsb[1],
2029 face->fs.fsUsb[0], face->fs.fsUsb[1],
2030 face->fs.fsUsb[2], face->fs.fsUsb[3]);
2032 return face;
2035 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
2036 FT_Long face_index, DWORD flags )
2038 Face *face;
2039 Family *family;
2041 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
2042 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
2043 if (strlenW(family->FamilyName) >= LF_FACESIZE)
2045 WARN("Ignoring %s because name is too long\n", debugstr_w(family->FamilyName));
2046 release_face( face );
2047 release_family( family );
2048 return;
2051 if (insert_face_in_family_list( face, family ))
2053 if (flags & ADDFONT_ADD_TO_CACHE)
2054 add_face_to_cache( face );
2056 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
2057 debugstr_w(face->StyleName));
2059 release_face( face );
2060 release_family( family );
2063 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
2064 FT_Long face_index, BOOL allow_bitmap )
2066 FT_Error err;
2067 TT_OS2 *pOS2;
2068 FT_Face ft_face;
2070 if (file)
2072 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2073 err = pFT_New_Face(library, file, face_index, &ft_face);
2075 else
2077 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2078 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2081 if (err != 0)
2083 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2084 return NULL;
2087 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2088 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
2090 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2091 goto fail;
2094 if (!FT_IS_SFNT( ft_face ))
2096 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2098 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2099 goto fail;
2102 else
2104 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2105 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2106 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2108 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2109 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2110 goto fail;
2113 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2114 we don't want to load these. */
2115 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2117 FT_ULong len = 0;
2119 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2121 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2122 goto fail;
2127 if (!ft_face->family_name || !ft_face->style_name)
2129 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2130 goto fail;
2133 return ft_face;
2134 fail:
2135 pFT_Done_Face( ft_face );
2136 return NULL;
2139 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
2141 FT_Face ft_face;
2142 FT_Long face_index = 0, num_faces;
2143 INT ret = 0;
2145 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2146 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
2148 #ifdef HAVE_CARBON_CARBON_H
2149 if(file)
2151 char **mac_list = expand_mac_font(file);
2152 if(mac_list)
2154 BOOL had_one = FALSE;
2155 char **cursor;
2156 for(cursor = mac_list; *cursor; cursor++)
2158 had_one = TRUE;
2159 AddFontToList(*cursor, NULL, 0, flags);
2160 HeapFree(GetProcessHeap(), 0, *cursor);
2162 HeapFree(GetProcessHeap(), 0, mac_list);
2163 if(had_one)
2164 return 1;
2167 #endif /* HAVE_CARBON_CARBON_H */
2169 do {
2170 const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
2171 FONTSIGNATURE fs;
2173 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2174 if (!ft_face) return 0;
2176 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2178 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
2179 pFT_Done_Face(ft_face);
2180 return 0;
2183 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
2184 ++ret;
2186 get_fontsig(ft_face, &fs);
2187 if (fs.fsCsb[0] & FS_DBCS_MASK)
2189 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
2190 flags | ADDFONT_VERTICAL_FONT);
2191 ++ret;
2194 num_faces = ft_face->num_faces;
2195 pFT_Done_Face(ft_face);
2196 } while(num_faces > ++face_index);
2197 return ret;
2200 static int remove_font_resource( const char *file, DWORD flags )
2202 Family *family, *family_next;
2203 Face *face, *face_next;
2204 struct stat st;
2205 int count = 0;
2207 if (stat( file, &st ) == -1) return 0;
2208 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2210 family->refcount++;
2211 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2213 if (!face->file) continue;
2214 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2215 if (st.st_dev == face->dev && st.st_ino == face->ino)
2217 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2218 release_face( face );
2219 count++;
2222 release_family( family );
2224 return count;
2227 static void DumpFontList(void)
2229 Family *family;
2230 Face *face;
2232 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2233 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2234 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2235 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2236 if(!face->scalable)
2237 TRACE(" %d", face->size.height);
2238 TRACE("\n");
2243 static BOOL map_font_family(const WCHAR *orig, const WCHAR *repl)
2245 Family *family = find_family_from_any_name(repl);
2246 if (family != NULL)
2248 Family *new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2249 if (new_family != NULL)
2251 TRACE("mapping %s to %s\n", debugstr_w(repl), debugstr_w(orig));
2252 new_family->FamilyName = strdupW(orig);
2253 new_family->EnglishName = NULL;
2254 list_init(&new_family->faces);
2255 new_family->replacement = &family->faces;
2256 list_add_tail(&font_list, &new_family->entry);
2257 return TRUE;
2260 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl));
2261 return FALSE;
2264 /***********************************************************
2265 * The replacement list is a way to map an entire font
2266 * family onto another family. For example adding
2268 * [HKCU\Software\Wine\Fonts\Replacements]
2269 * "Wingdings"="Winedings"
2271 * would enumerate the Winedings font both as Winedings and
2272 * Wingdings. However if a real Wingdings font is present the
2273 * replacement does not take place.
2276 static void LoadReplaceList(void)
2278 HKEY hkey;
2279 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2280 LPWSTR value;
2281 LPVOID data;
2283 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2284 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2286 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2287 &valuelen, &datalen, NULL, NULL);
2289 valuelen++; /* returned value doesn't include room for '\0' */
2290 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2291 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2293 dlen = datalen;
2294 vlen = valuelen;
2295 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data, &dlen) == ERROR_SUCCESS)
2297 /* "NewName"="Oldname" */
2298 if(!find_family_from_any_name(value))
2300 if (type == REG_MULTI_SZ)
2302 WCHAR *replace = data;
2303 while(*replace)
2305 if (map_font_family(value, replace))
2306 break;
2307 replace += strlenW(replace) + 1;
2310 else
2311 map_font_family(value, data);
2313 else
2314 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2316 /* reset dlen and vlen */
2317 dlen = datalen;
2318 vlen = valuelen;
2320 HeapFree(GetProcessHeap(), 0, data);
2321 HeapFree(GetProcessHeap(), 0, value);
2322 RegCloseKey(hkey);
2326 static const WCHAR *font_links_list[] =
2328 Lucida_Sans_Unicode,
2329 Microsoft_Sans_Serif,
2330 Tahoma
2333 static const struct font_links_defaults_list
2335 /* Keyed off substitution for "MS Shell Dlg" */
2336 const WCHAR *shelldlg;
2337 /* Maximum of four substitutes, plus terminating NULL pointer */
2338 const WCHAR *substitutes[5];
2339 } font_links_defaults_list[] =
2341 /* Non East-Asian */
2342 { Tahoma, /* FIXME unverified ordering */
2343 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2345 /* Below lists are courtesy of
2346 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2348 /* Japanese */
2349 { MS_UI_Gothic,
2350 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2352 /* Chinese Simplified */
2353 { SimSun,
2354 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2356 /* Korean */
2357 { Gulim,
2358 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2360 /* Chinese Traditional */
2361 { PMingLiU,
2362 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2367 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2369 SYSTEM_LINKS *font_link;
2371 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2373 if(!strcmpiW(font_link->font_name, name))
2374 return font_link;
2377 return NULL;
2380 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2382 const WCHAR *value;
2383 int i;
2384 FontSubst *psub;
2385 Family *family;
2386 Face *face;
2387 const WCHAR *file;
2389 if (values)
2391 SYSTEM_LINKS *font_link;
2393 psub = get_font_subst(&font_subst_list, name, -1);
2394 /* Don't store fonts that are only substitutes for other fonts */
2395 if(psub)
2397 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2398 return;
2401 font_link = find_font_link(name);
2402 if (font_link == NULL)
2404 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2405 font_link->font_name = strdupW(name);
2406 list_init(&font_link->links);
2407 list_add_tail(&system_links, &font_link->entry);
2410 memset(&font_link->fs, 0, sizeof font_link->fs);
2411 for (i = 0; values[i] != NULL; i++)
2413 const struct list *face_list;
2414 CHILD_FONT *child_font;
2416 value = values[i];
2417 if (!strcmpiW(name,value))
2418 continue;
2419 psub = get_font_subst(&font_subst_list, value, -1);
2420 if(psub)
2421 value = psub->to.name;
2422 family = find_family_from_name(value);
2423 if (!family)
2424 continue;
2425 file = NULL;
2426 /* Use first extant filename for this Family */
2427 face_list = get_face_list_from_family(family);
2428 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2430 if (!face->file)
2431 continue;
2432 file = strrchrW(face->file, '/');
2433 if (!file)
2434 file = face->file;
2435 else
2436 file++;
2437 break;
2439 if (!file)
2440 continue;
2441 face = find_face_from_filename(file, value);
2442 if(!face)
2444 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2445 continue;
2448 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2449 child_font->face = face;
2450 child_font->font = NULL;
2451 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2452 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2453 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2454 child_font->face->face_index);
2455 list_add_tail(&font_link->links, &child_font->entry);
2457 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2463 /*************************************************************
2464 * init_system_links
2466 static BOOL init_system_links(void)
2468 HKEY hkey;
2469 BOOL ret = FALSE;
2470 DWORD type, max_val, max_data, val_len, data_len, index;
2471 WCHAR *value, *data;
2472 WCHAR *entry, *next;
2473 SYSTEM_LINKS *font_link, *system_font_link;
2474 CHILD_FONT *child_font;
2475 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2476 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2477 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2478 Face *face;
2479 FontSubst *psub;
2480 UINT i, j;
2482 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2484 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2485 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2486 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2487 val_len = max_val + 1;
2488 data_len = max_data;
2489 index = 0;
2490 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2492 psub = get_font_subst(&font_subst_list, value, -1);
2493 /* Don't store fonts that are only substitutes for other fonts */
2494 if(psub)
2496 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2497 goto next;
2499 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2500 font_link->font_name = strdupW(value);
2501 memset(&font_link->fs, 0, sizeof font_link->fs);
2502 list_init(&font_link->links);
2503 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2505 WCHAR *face_name;
2506 CHILD_FONT *child_font;
2508 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2510 next = entry + strlenW(entry) + 1;
2512 face_name = strchrW(entry, ',');
2513 if(face_name)
2515 *face_name++ = 0;
2516 while(isspaceW(*face_name))
2517 face_name++;
2519 psub = get_font_subst(&font_subst_list, face_name, -1);
2520 if(psub)
2521 face_name = psub->to.name;
2523 face = find_face_from_filename(entry, face_name);
2524 if(!face)
2526 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2527 continue;
2530 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2531 child_font->face = face;
2532 child_font->font = NULL;
2533 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2534 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2535 TRACE("Adding file %s index %ld\n",
2536 debugstr_w(child_font->face->file), child_font->face->face_index);
2537 list_add_tail(&font_link->links, &child_font->entry);
2539 list_add_tail(&system_links, &font_link->entry);
2540 next:
2541 val_len = max_val + 1;
2542 data_len = max_data;
2545 HeapFree(GetProcessHeap(), 0, value);
2546 HeapFree(GetProcessHeap(), 0, data);
2547 RegCloseKey(hkey);
2551 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2552 if (!psub) {
2553 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2554 goto skip_internal;
2557 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2559 const FontSubst *psub2;
2560 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2562 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2564 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2565 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2567 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2568 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2570 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2572 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2576 skip_internal:
2578 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2579 that Tahoma has */
2581 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2582 system_font_link->font_name = strdupW(System);
2583 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2584 list_init(&system_font_link->links);
2586 face = find_face_from_filename(tahoma_ttf, Tahoma);
2587 if(face)
2589 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2590 child_font->face = face;
2591 child_font->font = NULL;
2592 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2593 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2594 TRACE("Found Tahoma in %s index %ld\n",
2595 debugstr_w(child_font->face->file), child_font->face->face_index);
2596 list_add_tail(&system_font_link->links, &child_font->entry);
2598 font_link = find_font_link(Tahoma);
2599 if (font_link != NULL)
2601 CHILD_FONT *font_link_entry;
2602 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2604 CHILD_FONT *new_child;
2605 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2606 new_child->face = font_link_entry->face;
2607 new_child->font = NULL;
2608 new_child->face->refcount++;
2609 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2610 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2611 list_add_tail(&system_font_link->links, &new_child->entry);
2614 list_add_tail(&system_links, &system_font_link->entry);
2615 return ret;
2618 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2620 DIR *dir;
2621 struct dirent *dent;
2622 char path[MAX_PATH];
2624 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2626 dir = opendir(dirname);
2627 if(!dir) {
2628 WARN("Can't open directory %s\n", debugstr_a(dirname));
2629 return FALSE;
2631 while((dent = readdir(dir)) != NULL) {
2632 struct stat statbuf;
2634 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2635 continue;
2637 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2639 sprintf(path, "%s/%s", dirname, dent->d_name);
2641 if(stat(path, &statbuf) == -1)
2643 WARN("Can't stat %s\n", debugstr_a(path));
2644 continue;
2646 if(S_ISDIR(statbuf.st_mode))
2647 ReadFontDir(path, external_fonts);
2648 else
2650 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2651 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2652 AddFontToList(path, NULL, 0, addfont_flags);
2655 closedir(dir);
2656 return TRUE;
2659 #ifdef SONAME_LIBFONTCONFIG
2661 static BOOL fontconfig_enabled;
2663 static UINT parse_aa_pattern( FcPattern *pattern )
2665 FcBool antialias;
2666 int rgba;
2667 UINT aa_flags = 0;
2669 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2670 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2672 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2674 switch (rgba)
2676 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2677 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2678 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2679 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2680 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2683 return aa_flags;
2686 static void init_fontconfig(void)
2688 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2690 if (!fc_handle)
2692 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2693 return;
2696 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2697 LOAD_FUNCPTR(FcConfigSubstitute);
2698 LOAD_FUNCPTR(FcFontList);
2699 LOAD_FUNCPTR(FcFontSetDestroy);
2700 LOAD_FUNCPTR(FcInit);
2701 LOAD_FUNCPTR(FcObjectSetAdd);
2702 LOAD_FUNCPTR(FcObjectSetCreate);
2703 LOAD_FUNCPTR(FcObjectSetDestroy);
2704 LOAD_FUNCPTR(FcPatternCreate);
2705 LOAD_FUNCPTR(FcPatternDestroy);
2706 LOAD_FUNCPTR(FcPatternGetBool);
2707 LOAD_FUNCPTR(FcPatternGetInteger);
2708 LOAD_FUNCPTR(FcPatternGetString);
2709 #undef LOAD_FUNCPTR
2711 if (pFcInit())
2713 FcPattern *pattern = pFcPatternCreate();
2714 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2715 default_aa_flags = parse_aa_pattern( pattern );
2716 pFcPatternDestroy( pattern );
2717 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2718 fontconfig_enabled = TRUE;
2722 static void load_fontconfig_fonts(void)
2724 FcPattern *pat;
2725 FcObjectSet *os;
2726 FcFontSet *fontset;
2727 int i, len;
2728 char *file;
2729 const char *ext;
2731 if (!fontconfig_enabled) return;
2733 pat = pFcPatternCreate();
2734 os = pFcObjectSetCreate();
2735 pFcObjectSetAdd(os, FC_FILE);
2736 pFcObjectSetAdd(os, FC_SCALABLE);
2737 pFcObjectSetAdd(os, FC_ANTIALIAS);
2738 pFcObjectSetAdd(os, FC_RGBA);
2739 fontset = pFcFontList(NULL, pat, os);
2740 if(!fontset) return;
2741 for(i = 0; i < fontset->nfont; i++) {
2742 FcBool scalable;
2743 DWORD aa_flags;
2745 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2746 continue;
2748 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2750 /* We're just interested in OT/TT fonts for now, so this hack just
2751 picks up the scalable fonts without extensions .pf[ab] to save time
2752 loading every other font */
2754 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2756 TRACE("not scalable\n");
2757 continue;
2760 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2761 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2763 len = strlen( file );
2764 if(len < 4) continue;
2765 ext = &file[ len - 3 ];
2766 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2767 AddFontToList(file, NULL, 0,
2768 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2770 pFcFontSetDestroy(fontset);
2771 pFcObjectSetDestroy(os);
2772 pFcPatternDestroy(pat);
2775 #elif defined(HAVE_CARBON_CARBON_H)
2777 static void load_mac_font_callback(const void *value, void *context)
2779 CFStringRef pathStr = value;
2780 CFIndex len;
2781 char* path;
2783 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2784 path = HeapAlloc(GetProcessHeap(), 0, len);
2785 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2787 TRACE("font file %s\n", path);
2788 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2790 HeapFree(GetProcessHeap(), 0, path);
2793 static void load_mac_fonts(void)
2795 CFStringRef removeDupesKey;
2796 CFBooleanRef removeDupesValue;
2797 CFDictionaryRef options;
2798 CTFontCollectionRef col;
2799 CFArrayRef descs;
2800 CFMutableSetRef paths;
2801 CFIndex i;
2803 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2804 removeDupesValue = kCFBooleanTrue;
2805 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2806 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2807 col = CTFontCollectionCreateFromAvailableFonts(options);
2808 if (options) CFRelease(options);
2809 if (!col)
2811 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2812 return;
2815 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2816 CFRelease(col);
2817 if (!descs)
2819 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2820 return;
2823 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2824 if (!paths)
2826 WARN("CFSetCreateMutable failed\n");
2827 CFRelease(descs);
2828 return;
2831 for (i = 0; i < CFArrayGetCount(descs); i++)
2833 CTFontDescriptorRef desc;
2834 CTFontRef font;
2835 ATSFontRef atsFont;
2836 OSStatus status;
2837 FSRef fsref;
2838 CFURLRef url;
2839 CFStringRef ext;
2840 CFStringRef path;
2842 desc = CFArrayGetValueAtIndex(descs, i);
2844 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2845 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2846 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2847 if (!font) continue;
2849 atsFont = CTFontGetPlatformFont(font, NULL);
2850 if (!atsFont)
2852 CFRelease(font);
2853 continue;
2856 status = ATSFontGetFileReference(atsFont, &fsref);
2857 CFRelease(font);
2858 if (status != noErr) continue;
2860 url = CFURLCreateFromFSRef(NULL, &fsref);
2861 if (!url) continue;
2863 ext = CFURLCopyPathExtension(url);
2864 if (ext)
2866 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2867 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2868 CFRelease(ext);
2869 if (skip)
2871 CFRelease(url);
2872 continue;
2876 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2877 CFRelease(url);
2878 if (!path) continue;
2880 CFSetAddValue(paths, path);
2881 CFRelease(path);
2884 CFRelease(descs);
2886 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2887 CFRelease(paths);
2890 #endif
2892 static char *get_data_dir_path( LPCWSTR file )
2894 char *unix_name = NULL;
2895 const char *data_dir = wine_get_data_dir();
2897 if (!data_dir) data_dir = wine_get_build_dir();
2899 if (data_dir)
2901 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2903 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2904 strcpy(unix_name, data_dir);
2905 strcat(unix_name, "/fonts/");
2907 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2909 return unix_name;
2912 static BOOL load_font_from_data_dir(LPCWSTR file)
2914 BOOL ret = FALSE;
2915 char *unix_name = get_data_dir_path( file );
2917 if (unix_name)
2919 EnterCriticalSection( &freetype_cs );
2920 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2921 LeaveCriticalSection( &freetype_cs );
2922 HeapFree(GetProcessHeap(), 0, unix_name);
2924 return ret;
2927 static char *get_winfonts_dir_path(LPCWSTR file)
2929 static const WCHAR slashW[] = {'\\','\0'};
2930 WCHAR windowsdir[MAX_PATH];
2932 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2933 strcatW(windowsdir, fontsW);
2934 strcatW(windowsdir, slashW);
2935 strcatW(windowsdir, file);
2936 return wine_get_unix_file_name( windowsdir );
2939 static void load_system_fonts(void)
2941 HKEY hkey;
2942 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2943 const WCHAR * const *value;
2944 DWORD dlen, type;
2945 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2946 char *unixname;
2948 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2949 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2950 strcatW(windowsdir, fontsW);
2951 for(value = SystemFontValues; *value; value++) {
2952 dlen = sizeof(data);
2953 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2954 type == REG_SZ) {
2955 BOOL added = FALSE;
2957 sprintfW(pathW, fmtW, windowsdir, data);
2958 if((unixname = wine_get_unix_file_name(pathW))) {
2959 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2960 HeapFree(GetProcessHeap(), 0, unixname);
2962 if (!added)
2963 load_font_from_data_dir(data);
2966 RegCloseKey(hkey);
2970 /*************************************************************
2972 * This adds registry entries for any externally loaded fonts
2973 * (fonts from fontconfig or FontDirs). It also deletes entries
2974 * of no longer existing fonts.
2977 static void update_reg_entries(void)
2979 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2980 LPWSTR valueW;
2981 DWORD len;
2982 Family *family;
2983 Face *face;
2984 WCHAR *file, *path;
2985 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2987 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2988 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2989 ERR("Can't create Windows font reg key\n");
2990 goto end;
2993 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2994 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2995 ERR("Can't create Windows font reg key\n");
2996 goto end;
2999 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
3000 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
3001 ERR("Can't create external font reg key\n");
3002 goto end;
3005 /* enumerate the fonts and add external ones to the two keys */
3007 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
3008 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
3009 char *buffer;
3010 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
3012 if(face->FullName)
3014 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
3015 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3016 strcpyW(valueW, face->FullName);
3018 else
3020 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
3021 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3022 strcpyW(valueW, family->FamilyName);
3025 buffer = strWtoA( CP_UNIXCP, face->file );
3026 path = wine_get_dos_file_name( buffer );
3027 HeapFree( GetProcessHeap(), 0, buffer );
3029 if (path)
3030 file = path;
3031 else if ((file = strrchrW(face->file, '/')))
3032 file++;
3033 else
3034 file = face->file;
3036 len = strlenW(file) + 1;
3037 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3038 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3039 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3041 HeapFree(GetProcessHeap(), 0, path);
3042 HeapFree(GetProcessHeap(), 0, valueW);
3045 end:
3046 if(external_key) RegCloseKey(external_key);
3047 if(win9x_key) RegCloseKey(win9x_key);
3048 if(winnt_key) RegCloseKey(winnt_key);
3051 static void delete_external_font_keys(void)
3053 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3054 DWORD dlen, vlen, datalen, valuelen, i, type;
3055 LPWSTR valueW;
3056 LPVOID data;
3058 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3059 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3060 ERR("Can't create Windows font reg key\n");
3061 goto end;
3064 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3065 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3066 ERR("Can't create Windows font reg key\n");
3067 goto end;
3070 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3071 ERR("Can't create external font reg key\n");
3072 goto end;
3075 /* Delete all external fonts added last time */
3077 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3078 &valuelen, &datalen, NULL, NULL);
3079 valuelen++; /* returned value doesn't include room for '\0' */
3080 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3081 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3083 dlen = datalen * sizeof(WCHAR);
3084 vlen = valuelen;
3085 i = 0;
3086 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3087 &dlen) == ERROR_SUCCESS) {
3089 RegDeleteValueW(winnt_key, valueW);
3090 RegDeleteValueW(win9x_key, valueW);
3091 /* reset dlen and vlen */
3092 dlen = datalen;
3093 vlen = valuelen;
3095 HeapFree(GetProcessHeap(), 0, data);
3096 HeapFree(GetProcessHeap(), 0, valueW);
3098 /* Delete the old external fonts key */
3099 RegCloseKey(external_key);
3100 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3102 end:
3103 if(win9x_key) RegCloseKey(win9x_key);
3104 if(winnt_key) RegCloseKey(winnt_key);
3107 /*************************************************************
3108 * WineEngAddFontResourceEx
3111 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3113 INT ret = 0;
3115 GDI_CheckNotLock();
3117 if (ft_handle) /* do it only if we have freetype up and running */
3119 char *unixname;
3121 EnterCriticalSection( &freetype_cs );
3123 if((unixname = wine_get_unix_file_name(file)))
3125 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3127 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3128 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3129 HeapFree(GetProcessHeap(), 0, unixname);
3131 if (!ret && !strchrW(file, '\\')) {
3132 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3133 if ((unixname = get_winfonts_dir_path( file )))
3135 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3136 HeapFree(GetProcessHeap(), 0, unixname);
3138 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3139 if (!ret && (unixname = get_data_dir_path( file )))
3141 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3142 HeapFree(GetProcessHeap(), 0, unixname);
3146 LeaveCriticalSection( &freetype_cs );
3148 return ret;
3151 /*************************************************************
3152 * WineEngAddFontMemResourceEx
3155 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3157 GDI_CheckNotLock();
3159 if (ft_handle) /* do it only if we have freetype up and running */
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, 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 *pcFonts = 0;
3184 return 0;
3187 /*************************************************************
3188 * WineEngRemoveFontResourceEx
3191 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3193 INT ret = 0;
3195 GDI_CheckNotLock();
3197 if (ft_handle) /* do it only if we have freetype up and running */
3199 char *unixname;
3201 EnterCriticalSection( &freetype_cs );
3203 if ((unixname = wine_get_unix_file_name(file)))
3205 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3207 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3208 ret = remove_font_resource( unixname, addfont_flags );
3209 HeapFree(GetProcessHeap(), 0, unixname);
3211 if (!ret && !strchrW(file, '\\'))
3213 if ((unixname = get_winfonts_dir_path( file )))
3215 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3216 HeapFree(GetProcessHeap(), 0, unixname);
3218 if (!ret && (unixname = get_data_dir_path( file )))
3220 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3221 HeapFree(GetProcessHeap(), 0, unixname);
3225 LeaveCriticalSection( &freetype_cs );
3227 return ret;
3230 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3232 WCHAR *fullname;
3233 char *unix_name;
3234 int file_len;
3236 if (!font_file) return NULL;
3238 file_len = strlenW( font_file );
3240 if (font_path && font_path[0])
3242 int path_len = strlenW( font_path );
3243 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3244 if (!fullname) return NULL;
3245 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3246 fullname[path_len] = '\\';
3247 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3249 else
3251 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3252 if (!len) return NULL;
3253 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3254 if (!fullname) return NULL;
3255 GetFullPathNameW( font_file, len, fullname, NULL );
3258 unix_name = wine_get_unix_file_name( fullname );
3259 HeapFree( GetProcessHeap(), 0, fullname );
3260 return unix_name;
3263 #include <pshpack1.h>
3264 struct fontdir
3266 WORD num_of_resources;
3267 WORD res_id;
3268 WORD dfVersion;
3269 DWORD dfSize;
3270 CHAR dfCopyright[60];
3271 WORD dfType;
3272 WORD dfPoints;
3273 WORD dfVertRes;
3274 WORD dfHorizRes;
3275 WORD dfAscent;
3276 WORD dfInternalLeading;
3277 WORD dfExternalLeading;
3278 BYTE dfItalic;
3279 BYTE dfUnderline;
3280 BYTE dfStrikeOut;
3281 WORD dfWeight;
3282 BYTE dfCharSet;
3283 WORD dfPixWidth;
3284 WORD dfPixHeight;
3285 BYTE dfPitchAndFamily;
3286 WORD dfAvgWidth;
3287 WORD dfMaxWidth;
3288 BYTE dfFirstChar;
3289 BYTE dfLastChar;
3290 BYTE dfDefaultChar;
3291 BYTE dfBreakChar;
3292 WORD dfWidthBytes;
3293 DWORD dfDevice;
3294 DWORD dfFace;
3295 DWORD dfReserved;
3296 CHAR szFaceName[LF_FACESIZE];
3299 #include <poppack.h>
3301 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3302 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3304 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3306 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3307 Face *face;
3308 WCHAR *name, *english_name;
3309 ENUMLOGFONTEXW elf;
3310 NEWTEXTMETRICEXW ntm;
3311 DWORD type;
3313 if (!ft_face) return FALSE;
3314 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3315 get_family_names( ft_face, &name, &english_name, FALSE );
3316 pFT_Done_Face( ft_face );
3318 GetEnumStructs( face, name, &elf, &ntm, &type );
3319 release_face( face );
3320 HeapFree( GetProcessHeap(), 0, name );
3321 HeapFree( GetProcessHeap(), 0, english_name );
3323 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3325 memset( fd, 0, sizeof(*fd) );
3327 fd->num_of_resources = 1;
3328 fd->res_id = 0;
3329 fd->dfVersion = 0x200;
3330 fd->dfSize = sizeof(*fd);
3331 strcpy( fd->dfCopyright, "Wine fontdir" );
3332 fd->dfType = 0x4003; /* 0x0080 set if private */
3333 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3334 fd->dfVertRes = 72;
3335 fd->dfHorizRes = 72;
3336 fd->dfAscent = ntm.ntmTm.tmAscent;
3337 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3338 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3339 fd->dfItalic = ntm.ntmTm.tmItalic;
3340 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3341 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3342 fd->dfWeight = ntm.ntmTm.tmWeight;
3343 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3344 fd->dfPixWidth = 0;
3345 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3346 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3347 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3348 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3349 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3350 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3351 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3352 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3353 fd->dfWidthBytes = 0;
3354 fd->dfDevice = 0;
3355 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3356 fd->dfReserved = 0;
3357 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3359 return TRUE;
3362 #define NE_FFLAGS_LIBMODULE 0x8000
3363 #define NE_OSFLAGS_WINDOWS 0x02
3365 static const char dos_string[0x40] = "This is a TrueType resource file";
3366 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3368 #include <pshpack2.h>
3370 struct ne_typeinfo
3372 WORD type_id;
3373 WORD count;
3374 DWORD res;
3377 struct ne_nameinfo
3379 WORD off;
3380 WORD len;
3381 WORD flags;
3382 WORD id;
3383 DWORD res;
3386 struct rsrc_tab
3388 WORD align;
3389 struct ne_typeinfo fontdir_type;
3390 struct ne_nameinfo fontdir_name;
3391 struct ne_typeinfo scalable_type;
3392 struct ne_nameinfo scalable_name;
3393 WORD end_of_rsrc;
3394 BYTE fontdir_res_name[8];
3397 #include <poppack.h>
3399 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3401 BOOL ret = FALSE;
3402 HANDLE file;
3403 DWORD size, written;
3404 BYTE *ptr, *start;
3405 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3406 char *font_fileA, *last_part, *ext;
3407 IMAGE_DOS_HEADER dos;
3408 IMAGE_OS2_HEADER ne =
3410 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3411 0, 0, 0, 0, 0, 0,
3412 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3413 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3415 struct rsrc_tab rsrc_tab =
3418 { 0x8007, 1, 0 },
3419 { 0, 0, 0x0c50, 0x2c, 0 },
3420 { 0x80cc, 1, 0 },
3421 { 0, 0, 0x0c50, 0x8001, 0 },
3423 { 7,'F','O','N','T','D','I','R'}
3426 memset( &dos, 0, sizeof(dos) );
3427 dos.e_magic = IMAGE_DOS_SIGNATURE;
3428 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3430 /* import name is last part\0, resident name is last part without extension
3431 non-resident name is "FONTRES:" + lfFaceName */
3433 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3434 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3435 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3437 last_part = strrchr( font_fileA, '\\' );
3438 if (last_part) last_part++;
3439 else last_part = font_fileA;
3440 import_name_len = strlen( last_part ) + 1;
3442 ext = strchr( last_part, '.' );
3443 if (ext) res_name_len = ext - last_part;
3444 else res_name_len = import_name_len - 1;
3446 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3448 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3449 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3450 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3451 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3452 ne.ne_cbenttab = 2;
3453 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3455 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3456 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3457 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3458 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3460 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3461 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3463 if (!ptr)
3465 HeapFree( GetProcessHeap(), 0, font_fileA );
3466 return FALSE;
3469 memcpy( ptr, &dos, sizeof(dos) );
3470 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3471 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3473 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3474 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3476 ptr = start + dos.e_lfanew + ne.ne_restab;
3477 *ptr++ = res_name_len;
3478 memcpy( ptr, last_part, res_name_len );
3480 ptr = start + dos.e_lfanew + ne.ne_imptab;
3481 *ptr++ = import_name_len;
3482 memcpy( ptr, last_part, import_name_len );
3484 ptr = start + ne.ne_nrestab;
3485 *ptr++ = non_res_name_len;
3486 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3487 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3489 ptr = start + (rsrc_tab.scalable_name.off << 4);
3490 memcpy( ptr, font_fileA, font_file_len );
3492 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3493 memcpy( ptr, fontdir, fontdir->dfSize );
3495 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3496 if (file != INVALID_HANDLE_VALUE)
3498 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3499 ret = TRUE;
3500 CloseHandle( file );
3503 HeapFree( GetProcessHeap(), 0, start );
3504 HeapFree( GetProcessHeap(), 0, font_fileA );
3506 return ret;
3509 /*************************************************************
3510 * WineEngCreateScalableFontResource
3513 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3514 LPCWSTR font_file, LPCWSTR font_path )
3516 char *unix_name = get_ttf_file_name( font_file, font_path );
3517 struct fontdir fontdir;
3518 BOOL ret = FALSE;
3520 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3521 SetLastError( ERROR_INVALID_PARAMETER );
3522 else
3524 if (hidden) fontdir.dfType |= 0x80;
3525 ret = create_fot( resource, font_file, &fontdir );
3528 HeapFree( GetProcessHeap(), 0, unix_name );
3529 return ret;
3532 static const struct nls_update_font_list
3534 UINT ansi_cp, oem_cp;
3535 const char *oem, *fixed, *system;
3536 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3537 /* these are for font substitutes */
3538 const char *shelldlg, *tmsrmn;
3539 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3540 *helv_0, *tmsrmn_0;
3541 const struct subst
3543 const char *from, *to;
3544 } arial_0, courier_new_0, times_new_roman_0;
3545 } nls_update_font_list[] =
3547 /* Latin 1 (United States) */
3548 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3549 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3550 "Tahoma","Times New Roman",
3551 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3552 { 0 }, { 0 }, { 0 }
3554 /* Latin 1 (Multilingual) */
3555 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3556 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3557 "Tahoma","Times New Roman", /* FIXME unverified */
3558 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3559 { 0 }, { 0 }, { 0 }
3561 /* Eastern Europe */
3562 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3563 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3564 "Tahoma","Times New Roman", /* FIXME unverified */
3565 "Fixedsys,238", "System,238",
3566 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3567 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3568 { "Arial CE,0", "Arial,238" },
3569 { "Courier New CE,0", "Courier New,238" },
3570 { "Times New Roman CE,0", "Times New Roman,238" }
3572 /* Cyrillic */
3573 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3574 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3575 "Tahoma","Times New Roman", /* FIXME unverified */
3576 "Fixedsys,204", "System,204",
3577 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3578 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3579 { "Arial Cyr,0", "Arial,204" },
3580 { "Courier New Cyr,0", "Courier New,204" },
3581 { "Times New Roman Cyr,0", "Times New Roman,204" }
3583 /* Greek */
3584 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3585 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3586 "Tahoma","Times New Roman", /* FIXME unverified */
3587 "Fixedsys,161", "System,161",
3588 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3589 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3590 { "Arial Greek,0", "Arial,161" },
3591 { "Courier New Greek,0", "Courier New,161" },
3592 { "Times New Roman Greek,0", "Times New Roman,161" }
3594 /* Turkish */
3595 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3596 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3597 "Tahoma","Times New Roman", /* FIXME unverified */
3598 "Fixedsys,162", "System,162",
3599 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3600 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3601 { "Arial Tur,0", "Arial,162" },
3602 { "Courier New Tur,0", "Courier New,162" },
3603 { "Times New Roman Tur,0", "Times New Roman,162" }
3605 /* Hebrew */
3606 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3607 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3608 "Tahoma","Times New Roman", /* FIXME unverified */
3609 "Fixedsys,177", "System,177",
3610 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3611 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3612 { 0 }, { 0 }, { 0 }
3614 /* Arabic */
3615 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3616 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3617 "Microsoft Sans Serif","Times New Roman",
3618 "Fixedsys,178", "System,178",
3619 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3620 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3621 { 0 }, { 0 }, { 0 }
3623 /* Baltic */
3624 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3625 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3626 "Tahoma","Times New Roman", /* FIXME unverified */
3627 "Fixedsys,186", "System,186",
3628 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3629 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3630 { "Arial Baltic,0", "Arial,186" },
3631 { "Courier New Baltic,0", "Courier New,186" },
3632 { "Times New Roman Baltic,0", "Times New Roman,186" }
3634 /* Vietnamese */
3635 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3636 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3637 "Tahoma","Times New Roman", /* FIXME unverified */
3638 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3639 { 0 }, { 0 }, { 0 }
3641 /* Thai */
3642 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3643 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3644 "Tahoma","Times New Roman", /* FIXME unverified */
3645 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3646 { 0 }, { 0 }, { 0 }
3648 /* Japanese */
3649 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3650 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3651 "MS UI Gothic","MS Serif",
3652 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3653 { 0 }, { 0 }, { 0 }
3655 /* Chinese Simplified */
3656 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3657 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3658 "SimSun", "NSimSun",
3659 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3660 { 0 }, { 0 }, { 0 }
3662 /* Korean */
3663 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3664 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3665 "Gulim", "Batang",
3666 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3667 { 0 }, { 0 }, { 0 }
3669 /* Chinese Traditional */
3670 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3671 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3672 "PMingLiU", "MingLiU",
3673 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3674 { 0 }, { 0 }, { 0 }
3678 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3680 return ( ansi_cp == 932 /* CP932 for Japanese */
3681 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3682 || ansi_cp == 949 /* CP949 for Korean */
3683 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3686 static inline HKEY create_fonts_NT_registry_key(void)
3688 HKEY hkey = 0;
3690 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3691 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3692 return hkey;
3695 static inline HKEY create_fonts_9x_registry_key(void)
3697 HKEY hkey = 0;
3699 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3700 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3701 return hkey;
3704 static inline HKEY create_config_fonts_registry_key(void)
3706 HKEY hkey = 0;
3708 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3709 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3710 return hkey;
3713 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3715 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3717 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3718 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3719 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3720 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3723 static void set_value_key(HKEY hkey, const char *name, const char *value)
3725 if (value)
3726 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3727 else if (name)
3728 RegDeleteValueA(hkey, name);
3731 static void update_font_association_info(UINT current_ansi_codepage)
3733 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3734 static const char *assoc_charset_subkey = "Associated Charset";
3736 if (is_dbcs_ansi_cp(current_ansi_codepage))
3738 HKEY hkey;
3739 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3741 HKEY hsubkey;
3742 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3744 switch (current_ansi_codepage)
3746 case 932:
3747 set_value_key(hsubkey, "ANSI(00)", "NO");
3748 set_value_key(hsubkey, "OEM(FF)", "NO");
3749 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3750 break;
3751 case 936:
3752 case 949:
3753 case 950:
3754 set_value_key(hsubkey, "ANSI(00)", "YES");
3755 set_value_key(hsubkey, "OEM(FF)", "YES");
3756 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3757 break;
3759 RegCloseKey(hsubkey);
3762 /* TODO: Associated DefaultFonts */
3764 RegCloseKey(hkey);
3767 else
3768 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3771 static void update_font_info(void)
3773 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3774 char buf[40], cpbuf[40];
3775 DWORD len, type;
3776 HKEY hkey = 0;
3777 UINT i, ansi_cp = 0, oem_cp = 0;
3778 DWORD screen_dpi = 96, font_dpi = 0;
3779 BOOL done = FALSE;
3781 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3782 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3783 &hkey) == ERROR_SUCCESS)
3785 reg_load_dword(hkey, logpixels, &screen_dpi);
3786 RegCloseKey(hkey);
3789 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3790 return;
3792 reg_load_dword(hkey, logpixels, &font_dpi);
3794 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3795 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3796 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3797 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3798 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3800 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3801 if (is_dbcs_ansi_cp(ansi_cp))
3802 use_default_fallback = TRUE;
3804 buf[0] = 0;
3805 len = sizeof(buf);
3806 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3808 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3810 RegCloseKey(hkey);
3811 return;
3813 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3814 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3816 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3817 ansi_cp, oem_cp, screen_dpi);
3819 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3820 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3821 RegCloseKey(hkey);
3823 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3825 HKEY hkey;
3827 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3828 nls_update_font_list[i].oem_cp == oem_cp)
3830 hkey = create_config_fonts_registry_key();
3831 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3832 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3833 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3834 RegCloseKey(hkey);
3836 hkey = create_fonts_NT_registry_key();
3837 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3838 RegCloseKey(hkey);
3840 hkey = create_fonts_9x_registry_key();
3841 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3842 RegCloseKey(hkey);
3844 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3846 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3847 strlen(nls_update_font_list[i].shelldlg)+1);
3848 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3849 strlen(nls_update_font_list[i].tmsrmn)+1);
3851 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3852 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3853 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3854 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3855 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3856 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3857 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3858 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3860 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3861 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3862 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3864 RegCloseKey(hkey);
3866 done = TRUE;
3868 else
3870 /* Delete the FontSubstitutes from other locales */
3871 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3873 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3874 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3875 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3876 RegCloseKey(hkey);
3880 if (!done)
3881 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3883 /* update locale dependent font association info in registry.
3884 update only when codepages changed, not logpixels. */
3885 if (strcmp(buf, cpbuf) != 0)
3886 update_font_association_info(ansi_cp);
3889 static BOOL init_freetype(void)
3891 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3892 if(!ft_handle) {
3893 WINE_MESSAGE(
3894 "Wine cannot find the FreeType font library. To enable Wine to\n"
3895 "use TrueType fonts please install a version of FreeType greater than\n"
3896 "or equal to 2.0.5.\n"
3897 "http://www.freetype.org\n");
3898 return FALSE;
3901 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
3903 LOAD_FUNCPTR(FT_Done_Face)
3904 LOAD_FUNCPTR(FT_Get_Char_Index)
3905 LOAD_FUNCPTR(FT_Get_First_Char)
3906 LOAD_FUNCPTR(FT_Get_Next_Char)
3907 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3908 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3909 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3910 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3911 LOAD_FUNCPTR(FT_Init_FreeType)
3912 LOAD_FUNCPTR(FT_Library_Version)
3913 LOAD_FUNCPTR(FT_Load_Glyph)
3914 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3915 LOAD_FUNCPTR(FT_Matrix_Multiply)
3916 #ifndef FT_MULFIX_INLINED
3917 LOAD_FUNCPTR(FT_MulFix)
3918 #endif
3919 LOAD_FUNCPTR(FT_New_Face)
3920 LOAD_FUNCPTR(FT_New_Memory_Face)
3921 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3922 LOAD_FUNCPTR(FT_Outline_Get_CBox)
3923 LOAD_FUNCPTR(FT_Outline_Transform)
3924 LOAD_FUNCPTR(FT_Outline_Translate)
3925 LOAD_FUNCPTR(FT_Render_Glyph)
3926 LOAD_FUNCPTR(FT_Select_Charmap)
3927 LOAD_FUNCPTR(FT_Set_Charmap)
3928 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3929 LOAD_FUNCPTR(FT_Vector_Transform)
3930 LOAD_FUNCPTR(FT_Vector_Unit)
3931 #undef LOAD_FUNCPTR
3932 /* Don't warn if these ones are missing */
3933 pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
3934 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3935 #ifdef FT_LCD_FILTER_H
3936 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3937 #endif
3939 if(pFT_Init_FreeType(&library) != 0) {
3940 ERR("Can't init FreeType library\n");
3941 wine_dlclose(ft_handle, NULL, 0);
3942 ft_handle = NULL;
3943 return FALSE;
3945 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3947 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3948 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3949 ((FT_Version.minor << 8) & 0x00ff00) |
3950 ((FT_Version.patch ) & 0x0000ff);
3952 font_driver = &freetype_funcs;
3953 return TRUE;
3955 sym_not_found:
3956 WINE_MESSAGE(
3957 "Wine cannot find certain functions that it needs inside the FreeType\n"
3958 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3959 "FreeType to at least version 2.1.4.\n"
3960 "http://www.freetype.org\n");
3961 wine_dlclose(ft_handle, NULL, 0);
3962 ft_handle = NULL;
3963 return FALSE;
3966 static void init_font_list(void)
3968 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3969 static const WCHAR pathW[] = {'P','a','t','h',0};
3970 HKEY hkey;
3971 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3972 WCHAR windowsdir[MAX_PATH];
3973 char *unixname;
3974 const char *data_dir;
3976 delete_external_font_keys();
3978 /* load the system bitmap fonts */
3979 load_system_fonts();
3981 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3982 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3983 strcatW(windowsdir, fontsW);
3984 if((unixname = wine_get_unix_file_name(windowsdir)))
3986 ReadFontDir(unixname, FALSE);
3987 HeapFree(GetProcessHeap(), 0, unixname);
3990 /* load the system truetype fonts */
3991 data_dir = wine_get_data_dir();
3992 if (!data_dir) data_dir = wine_get_build_dir();
3993 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3995 strcpy(unixname, data_dir);
3996 strcat(unixname, "/fonts/");
3997 ReadFontDir(unixname, TRUE);
3998 HeapFree(GetProcessHeap(), 0, unixname);
4001 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4002 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4003 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4004 will skip these. */
4005 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
4006 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
4007 &hkey) == ERROR_SUCCESS)
4009 LPWSTR data, valueW;
4010 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4011 &valuelen, &datalen, NULL, NULL);
4013 valuelen++; /* returned value doesn't include room for '\0' */
4014 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
4015 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
4016 if (valueW && data)
4018 dlen = datalen * sizeof(WCHAR);
4019 vlen = valuelen;
4020 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
4021 &dlen) == ERROR_SUCCESS)
4023 if(data[0] && (data[1] == ':'))
4025 if((unixname = wine_get_unix_file_name(data)))
4027 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4028 HeapFree(GetProcessHeap(), 0, unixname);
4031 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4033 WCHAR pathW[MAX_PATH];
4034 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4035 BOOL added = FALSE;
4037 sprintfW(pathW, fmtW, windowsdir, data);
4038 if((unixname = wine_get_unix_file_name(pathW)))
4040 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4041 HeapFree(GetProcessHeap(), 0, unixname);
4043 if (!added)
4044 load_font_from_data_dir(data);
4046 /* reset dlen and vlen */
4047 dlen = datalen;
4048 vlen = valuelen;
4051 HeapFree(GetProcessHeap(), 0, data);
4052 HeapFree(GetProcessHeap(), 0, valueW);
4053 RegCloseKey(hkey);
4056 #ifdef SONAME_LIBFONTCONFIG
4057 load_fontconfig_fonts();
4058 #elif defined(HAVE_CARBON_CARBON_H)
4059 load_mac_fonts();
4060 #endif
4062 /* then look in any directories that we've specified in the config file */
4063 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4064 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4066 DWORD len;
4067 LPWSTR valueW;
4068 LPSTR valueA, ptr;
4070 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4072 len += sizeof(WCHAR);
4073 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4074 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4076 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4077 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4078 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4079 TRACE( "got font path %s\n", debugstr_a(valueA) );
4080 ptr = valueA;
4081 while (ptr)
4083 const char* home;
4084 LPSTR next = strchr( ptr, ':' );
4085 if (next) *next++ = 0;
4086 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4087 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4089 strcpy( unixname, home );
4090 strcat( unixname, ptr + 1 );
4091 ReadFontDir( unixname, TRUE );
4092 HeapFree( GetProcessHeap(), 0, unixname );
4094 else
4095 ReadFontDir( ptr, TRUE );
4096 ptr = next;
4098 HeapFree( GetProcessHeap(), 0, valueA );
4100 HeapFree( GetProcessHeap(), 0, valueW );
4102 RegCloseKey(hkey);
4106 static BOOL move_to_front(const WCHAR *name)
4108 Family *family, *cursor2;
4109 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4111 if(!strcmpiW(family->FamilyName, name))
4113 list_remove(&family->entry);
4114 list_add_head(&font_list, &family->entry);
4115 return TRUE;
4118 return FALSE;
4121 static BOOL set_default(const WCHAR **name_list)
4123 while (*name_list)
4125 if (move_to_front(*name_list)) return TRUE;
4126 name_list++;
4129 return FALSE;
4132 static void reorder_font_list(void)
4134 set_default( default_serif_list );
4135 set_default( default_fixed_list );
4136 set_default( default_sans_list );
4139 /*************************************************************
4140 * WineEngInit
4142 * Initialize FreeType library and create a list of available faces
4144 BOOL WineEngInit(void)
4146 DWORD disposition;
4147 HANDLE font_mutex;
4149 /* update locale dependent font info in registry */
4150 update_font_info();
4152 if(!init_freetype()) return FALSE;
4154 #ifdef SONAME_LIBFONTCONFIG
4155 init_fontconfig();
4156 #endif
4158 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4160 ERR("Failed to create font mutex\n");
4161 return FALSE;
4163 WaitForSingleObject(font_mutex, INFINITE);
4165 create_font_cache_key(&hkey_font_cache, &disposition);
4167 if(disposition == REG_CREATED_NEW_KEY)
4168 init_font_list();
4169 else
4170 load_font_list_from_cache(hkey_font_cache);
4172 reorder_font_list();
4174 DumpFontList();
4175 LoadSubstList();
4176 DumpSubstList();
4177 LoadReplaceList();
4179 if(disposition == REG_CREATED_NEW_KEY)
4180 update_reg_entries();
4182 init_system_links();
4184 ReleaseMutex(font_mutex);
4185 return TRUE;
4188 /* Some fonts have large usWinDescent values, as a result of storing signed short
4189 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
4190 some font generation tools. */
4191 static inline USHORT get_fixed_windescent(USHORT windescent)
4193 return abs((SHORT)windescent);
4196 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4198 TT_OS2 *pOS2;
4199 TT_HoriHeader *pHori;
4201 LONG ppem;
4202 const LONG MAX_PPEM = (1 << 16) - 1;
4204 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4205 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4207 if(height == 0) height = 16;
4209 /* Calc. height of EM square:
4211 * For +ve lfHeight we have
4212 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4213 * Re-arranging gives:
4214 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4216 * For -ve lfHeight we have
4217 * |lfHeight| = ppem
4218 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4219 * with il = winAscent + winDescent - units_per_em]
4223 if(height > 0) {
4224 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
4225 if(pOS2->usWinAscent + windescent == 0)
4226 ppem = MulDiv(ft_face->units_per_EM, height,
4227 pHori->Ascender - pHori->Descender);
4228 else
4229 ppem = MulDiv(ft_face->units_per_EM, height,
4230 pOS2->usWinAscent + windescent);
4231 if(ppem > MAX_PPEM) {
4232 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4233 ppem = 1;
4236 else if(height >= -MAX_PPEM)
4237 ppem = -height;
4238 else {
4239 WARN("Ignoring too large height %d\n", height);
4240 ppem = 1;
4243 return ppem;
4246 static struct font_mapping *map_font_file( const char *name )
4248 struct font_mapping *mapping;
4249 struct stat st;
4250 int fd;
4252 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4253 if (fstat( fd, &st ) == -1) goto error;
4255 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4257 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4259 mapping->refcount++;
4260 close( fd );
4261 return mapping;
4264 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4265 goto error;
4267 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4268 close( fd );
4270 if (mapping->data == MAP_FAILED)
4272 HeapFree( GetProcessHeap(), 0, mapping );
4273 return NULL;
4275 mapping->refcount = 1;
4276 mapping->dev = st.st_dev;
4277 mapping->ino = st.st_ino;
4278 mapping->size = st.st_size;
4279 list_add_tail( &mappings_list, &mapping->entry );
4280 return mapping;
4282 error:
4283 close( fd );
4284 return NULL;
4287 static void unmap_font_file( struct font_mapping *mapping )
4289 if (!--mapping->refcount)
4291 list_remove( &mapping->entry );
4292 munmap( mapping->data, mapping->size );
4293 HeapFree( GetProcessHeap(), 0, mapping );
4297 static LONG load_VDMX(GdiFont*, LONG);
4299 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4301 FT_Error err;
4302 FT_Face ft_face;
4303 void *data_ptr;
4304 DWORD data_size;
4306 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4308 if (face->file)
4310 char *filename = strWtoA( CP_UNIXCP, face->file );
4311 font->mapping = map_font_file( filename );
4312 HeapFree( GetProcessHeap(), 0, filename );
4313 if (!font->mapping)
4315 WARN("failed to map %s\n", debugstr_w(face->file));
4316 return 0;
4318 data_ptr = font->mapping->data;
4319 data_size = font->mapping->size;
4321 else
4323 data_ptr = face->font_data_ptr;
4324 data_size = face->font_data_size;
4327 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4328 if(err) {
4329 ERR("FT_New_Face rets %d\n", err);
4330 return 0;
4333 /* set it here, as load_VDMX needs it */
4334 font->ft_face = ft_face;
4336 if(FT_IS_SCALABLE(ft_face)) {
4337 /* load the VDMX table if we have one */
4338 font->ppem = load_VDMX(font, height);
4339 if(font->ppem == 0)
4340 font->ppem = calc_ppem_for_height(ft_face, height);
4341 TRACE("height %d => ppem %d\n", height, font->ppem);
4343 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4344 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4345 } else {
4346 font->ppem = height;
4347 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4348 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4350 return ft_face;
4354 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4356 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4357 a single face with the requested charset. The idea is to check if
4358 the selected font supports the current ANSI codepage, if it does
4359 return the corresponding charset, else return the first charset */
4361 CHARSETINFO csi;
4362 int acp = GetACP(), i;
4363 DWORD fs0;
4365 *cp = acp;
4366 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4368 const SYSTEM_LINKS *font_link;
4370 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4371 return csi.ciCharset;
4373 font_link = find_font_link(family_name);
4374 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4375 return csi.ciCharset;
4378 for(i = 0; i < 32; i++) {
4379 fs0 = 1L << i;
4380 if(face->fs.fsCsb[0] & fs0) {
4381 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4382 *cp = csi.ciACP;
4383 return csi.ciCharset;
4385 else
4386 FIXME("TCI failing on %x\n", fs0);
4390 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4391 face->fs.fsCsb[0], debugstr_w(face->file));
4392 *cp = acp;
4393 return DEFAULT_CHARSET;
4396 static GdiFont *alloc_font(void)
4398 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4399 ret->refcount = 1;
4400 ret->gmsize = 1;
4401 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4402 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4403 ret->potm = NULL;
4404 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4405 ret->total_kern_pairs = (DWORD)-1;
4406 ret->kern_pairs = NULL;
4407 list_init(&ret->child_fonts);
4408 return ret;
4411 static void free_font(GdiFont *font)
4413 CHILD_FONT *child, *child_next;
4414 DWORD i;
4416 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4418 list_remove(&child->entry);
4419 if(child->font)
4420 free_font(child->font);
4421 release_face( child->face );
4422 HeapFree(GetProcessHeap(), 0, child);
4425 if (font->ft_face) pFT_Done_Face(font->ft_face);
4426 if (font->mapping) unmap_font_file( font->mapping );
4427 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4428 HeapFree(GetProcessHeap(), 0, font->potm);
4429 HeapFree(GetProcessHeap(), 0, font->name);
4430 for (i = 0; i < font->gmsize; i++)
4431 HeapFree(GetProcessHeap(),0,font->gm[i]);
4432 HeapFree(GetProcessHeap(), 0, font->gm);
4433 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4434 HeapFree(GetProcessHeap(), 0, font);
4438 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4440 FT_Face ft_face = font->ft_face;
4441 FT_ULong len;
4442 FT_Error err;
4444 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4446 if(!buf)
4447 len = 0;
4448 else
4449 len = cbData;
4451 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4453 /* make sure value of len is the value freetype says it needs */
4454 if (buf && len)
4456 FT_ULong needed = 0;
4457 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4458 if( !err && needed < len) len = needed;
4460 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4461 if (err)
4463 TRACE("Can't find table %c%c%c%c\n",
4464 /* bytes were reversed */
4465 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4466 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4467 return GDI_ERROR;
4469 return len;
4472 /*************************************************************
4473 * load_VDMX
4475 * load the vdmx entry for the specified height
4478 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4479 ( ( (FT_ULong)_x4 << 24 ) | \
4480 ( (FT_ULong)_x3 << 16 ) | \
4481 ( (FT_ULong)_x2 << 8 ) | \
4482 (FT_ULong)_x1 )
4484 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4486 typedef struct {
4487 WORD version;
4488 WORD numRecs;
4489 WORD numRatios;
4490 } VDMX_Header;
4492 typedef struct {
4493 BYTE bCharSet;
4494 BYTE xRatio;
4495 BYTE yStartRatio;
4496 BYTE yEndRatio;
4497 } Ratios;
4499 typedef struct {
4500 WORD recs;
4501 BYTE startsz;
4502 BYTE endsz;
4503 } VDMX_group;
4505 typedef struct {
4506 WORD yPelHeight;
4507 WORD yMax;
4508 WORD yMin;
4509 } VDMX_vTable;
4511 static LONG load_VDMX(GdiFont *font, LONG height)
4513 VDMX_Header hdr;
4514 VDMX_group group;
4515 BYTE devXRatio, devYRatio;
4516 USHORT numRecs, numRatios;
4517 DWORD result, offset = -1;
4518 LONG ppem = 0;
4519 int i;
4521 result = get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
4523 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4524 return ppem;
4526 /* FIXME: need the real device aspect ratio */
4527 devXRatio = 1;
4528 devYRatio = 1;
4530 numRecs = GET_BE_WORD(hdr.numRecs);
4531 numRatios = GET_BE_WORD(hdr.numRatios);
4533 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
4534 for(i = 0; i < numRatios; i++) {
4535 Ratios ratio;
4537 offset = sizeof(hdr) + (i * sizeof(Ratios));
4538 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4539 offset = -1;
4541 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4543 if (!ratio.bCharSet) continue;
4545 if((ratio.xRatio == 0 &&
4546 ratio.yStartRatio == 0 &&
4547 ratio.yEndRatio == 0) ||
4548 (devXRatio == ratio.xRatio &&
4549 devYRatio >= ratio.yStartRatio &&
4550 devYRatio <= ratio.yEndRatio))
4552 WORD group_offset;
4554 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
4555 get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
4556 offset = GET_BE_WORD(group_offset);
4557 break;
4561 if(offset == -1) return 0;
4563 if(get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
4564 USHORT recs;
4565 BYTE startsz, endsz;
4566 WORD *vTable;
4568 recs = GET_BE_WORD(group.recs);
4569 startsz = group.startsz;
4570 endsz = group.endsz;
4572 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4574 vTable = HeapAlloc(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
4575 result = get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
4576 if(result == GDI_ERROR) {
4577 FIXME("Failed to retrieve vTable\n");
4578 goto end;
4581 if(height > 0) {
4582 for(i = 0; i < recs; i++) {
4583 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4584 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4585 ppem = GET_BE_WORD(vTable[i * 3]);
4587 if(yMax + -yMin == height) {
4588 font->yMax = yMax;
4589 font->yMin = yMin;
4590 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4591 break;
4593 if(yMax + -yMin > height) {
4594 if(--i < 0) {
4595 ppem = 0;
4596 goto end; /* failed */
4598 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4599 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4600 ppem = GET_BE_WORD(vTable[i * 3]);
4601 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4602 break;
4605 if(!font->yMax) {
4606 ppem = 0;
4607 TRACE("ppem not found for height %d\n", height);
4609 } else {
4610 ppem = -height;
4611 if(ppem < startsz || ppem > endsz)
4613 ppem = 0;
4614 goto end;
4617 for(i = 0; i < recs; i++) {
4618 USHORT yPelHeight;
4619 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4621 if(yPelHeight > ppem)
4623 ppem = 0;
4624 break; /* failed */
4627 if(yPelHeight == ppem) {
4628 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4629 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4630 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4631 break;
4635 end:
4636 HeapFree(GetProcessHeap(), 0, vTable);
4639 return ppem;
4642 static void dump_gdi_font_list(void)
4644 GdiFont *font;
4646 TRACE("---------- Font Cache ----------\n");
4647 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4648 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4649 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4652 static void grab_font( GdiFont *font )
4654 if (!font->refcount++)
4656 list_remove( &font->unused_entry );
4657 unused_font_count--;
4661 static void release_font( GdiFont *font )
4663 if (!font) return;
4664 if (!--font->refcount)
4666 TRACE( "font %p\n", font );
4668 /* add it to the unused list */
4669 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4670 if (unused_font_count > UNUSED_CACHE_SIZE)
4672 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4673 TRACE( "freeing %p\n", font );
4674 list_remove( &font->entry );
4675 list_remove( &font->unused_entry );
4676 free_font( font );
4678 else unused_font_count++;
4680 if (TRACE_ON(font)) dump_gdi_font_list();
4684 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4686 if(font->font_desc.hash != fd->hash) return TRUE;
4687 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4688 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4689 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4690 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4693 static void calc_hash(FONT_DESC *pfd)
4695 DWORD hash = 0, *ptr, two_chars;
4696 WORD *pwc;
4697 unsigned int i;
4699 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4700 hash ^= *ptr;
4701 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4702 hash ^= *ptr;
4703 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4704 two_chars = *ptr;
4705 pwc = (WCHAR *)&two_chars;
4706 if(!*pwc) break;
4707 *pwc = toupperW(*pwc);
4708 pwc++;
4709 *pwc = toupperW(*pwc);
4710 hash ^= two_chars;
4711 if(!*pwc) break;
4713 hash ^= !pfd->can_use_bitmap;
4714 pfd->hash = hash;
4717 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4719 GdiFont *ret;
4720 FONT_DESC fd;
4722 fd.lf = *plf;
4723 fd.matrix = *pmat;
4724 fd.can_use_bitmap = can_use_bitmap;
4725 calc_hash(&fd);
4727 /* try the in-use list */
4728 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4730 if(fontcmp(ret, &fd)) continue;
4731 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4732 list_remove( &ret->entry );
4733 list_add_head( &gdi_font_list, &ret->entry );
4734 grab_font( ret );
4735 return ret;
4737 return NULL;
4740 static void add_to_cache(GdiFont *font)
4742 static DWORD cache_num = 1;
4744 font->cache_num = cache_num++;
4745 list_add_head(&gdi_font_list, &font->entry);
4746 TRACE( "font %p\n", font );
4749 /*************************************************************
4750 * create_child_font_list
4752 static BOOL create_child_font_list(GdiFont *font)
4754 BOOL ret = FALSE;
4755 SYSTEM_LINKS *font_link;
4756 CHILD_FONT *font_link_entry, *new_child;
4757 FontSubst *psub;
4758 WCHAR* font_name;
4760 psub = get_font_subst(&font_subst_list, font->name, -1);
4761 font_name = psub ? psub->to.name : font->name;
4762 font_link = find_font_link(font_name);
4763 if (font_link != NULL)
4765 TRACE("found entry in system list\n");
4766 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4768 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4769 new_child->face = font_link_entry->face;
4770 new_child->font = NULL;
4771 new_child->face->refcount++;
4772 list_add_tail(&font->child_fonts, &new_child->entry);
4773 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4775 ret = TRUE;
4778 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4779 * Sans Serif. This is how asian windows get default fallbacks for fonts
4781 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4782 font->charset != OEM_CHARSET &&
4783 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4785 font_link = find_font_link(szDefaultFallbackLink);
4786 if (font_link != NULL)
4788 TRACE("found entry in default fallback list\n");
4789 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4791 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4792 new_child->face = font_link_entry->face;
4793 new_child->font = NULL;
4794 new_child->face->refcount++;
4795 list_add_tail(&font->child_fonts, &new_child->entry);
4796 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4798 ret = TRUE;
4802 return ret;
4805 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4807 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4809 if (pFT_Set_Charmap)
4811 FT_Int i;
4812 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4814 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4816 for (i = 0; i < ft_face->num_charmaps; i++)
4818 if (ft_face->charmaps[i]->encoding == encoding)
4820 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4821 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4823 switch (ft_face->charmaps[i]->platform_id)
4825 default:
4826 cmap_def = ft_face->charmaps[i];
4827 break;
4828 case 0: /* Apple Unicode */
4829 cmap0 = ft_face->charmaps[i];
4830 break;
4831 case 1: /* Macintosh */
4832 cmap1 = ft_face->charmaps[i];
4833 break;
4834 case 2: /* ISO */
4835 cmap2 = ft_face->charmaps[i];
4836 break;
4837 case 3: /* Microsoft */
4838 cmap3 = ft_face->charmaps[i];
4839 break;
4843 if (cmap3) /* prefer Microsoft cmap table */
4844 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4845 else if (cmap1)
4846 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4847 else if (cmap2)
4848 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4849 else if (cmap0)
4850 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4851 else if (cmap_def)
4852 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4854 return ft_err == FT_Err_Ok;
4857 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4861 /*************************************************************
4862 * freetype_CreateDC
4864 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4865 LPCWSTR output, const DEVMODEW *devmode )
4867 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4869 if (!physdev) return FALSE;
4870 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4871 return TRUE;
4875 /*************************************************************
4876 * freetype_DeleteDC
4878 static BOOL freetype_DeleteDC( PHYSDEV dev )
4880 struct freetype_physdev *physdev = get_freetype_dev( dev );
4881 release_font( physdev->font );
4882 HeapFree( GetProcessHeap(), 0, physdev );
4883 return TRUE;
4886 static FT_Encoding pick_charmap( FT_Face face, int charset )
4888 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4889 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4890 const FT_Encoding *encs = regular_order;
4892 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4894 while (*encs != 0)
4896 if (select_charmap( face, *encs )) break;
4897 encs++;
4899 return *encs;
4902 #define GASP_GRIDFIT 0x01
4903 #define GASP_DOGRAY 0x02
4904 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4906 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4908 DWORD size;
4909 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4910 WORD *alloced = NULL, *ptr = buf;
4911 WORD num_recs, version;
4912 BOOL ret = FALSE;
4914 *flags = 0;
4915 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4916 if (size == GDI_ERROR) return FALSE;
4917 if (size < 4 * sizeof(WORD)) return FALSE;
4918 if (size > sizeof(buf))
4920 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4921 if (!ptr) return FALSE;
4924 get_font_data( font, GASP_TAG, 0, ptr, size );
4926 version = GET_BE_WORD( *ptr++ );
4927 num_recs = GET_BE_WORD( *ptr++ );
4929 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4931 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4932 goto done;
4935 while (num_recs--)
4937 *flags = GET_BE_WORD( *(ptr + 1) );
4938 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4939 ptr += 2;
4941 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4942 ret = TRUE;
4944 done:
4945 HeapFree( GetProcessHeap(), 0, alloced );
4946 return ret;
4949 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4951 const GSUB_ScriptList *script;
4952 const GSUB_Script *deflt = NULL;
4953 int i;
4954 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4956 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4957 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4959 const GSUB_Script *scr;
4960 int offset;
4962 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4963 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4965 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4966 return scr;
4967 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4968 deflt = scr;
4970 return deflt;
4973 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4975 int i;
4976 int offset;
4977 const GSUB_LangSys *Lang;
4979 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4981 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4983 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4984 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4986 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4987 return Lang;
4989 offset = GET_BE_WORD(script->DefaultLangSys);
4990 if (offset)
4992 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4993 return Lang;
4995 return NULL;
4998 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5000 int i;
5001 const GSUB_FeatureList *feature;
5002 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5004 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5005 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5007 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5008 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5010 const GSUB_Feature *feat;
5011 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5012 return feat;
5015 return NULL;
5018 static const char* get_opentype_script(const GdiFont *font)
5021 * I am not sure if this is the correct way to generate our script tag
5024 switch (font->charset)
5026 case ANSI_CHARSET: return "latn";
5027 case BALTIC_CHARSET: return "latn"; /* ?? */
5028 case CHINESEBIG5_CHARSET: return "hani";
5029 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5030 case GB2312_CHARSET: return "hani";
5031 case GREEK_CHARSET: return "grek";
5032 case HANGUL_CHARSET: return "hang";
5033 case RUSSIAN_CHARSET: return "cyrl";
5034 case SHIFTJIS_CHARSET: return "kana";
5035 case TURKISH_CHARSET: return "latn"; /* ?? */
5036 case VIETNAMESE_CHARSET: return "latn";
5037 case JOHAB_CHARSET: return "latn"; /* ?? */
5038 case ARABIC_CHARSET: return "arab";
5039 case HEBREW_CHARSET: return "hebr";
5040 case THAI_CHARSET: return "thai";
5041 default: return "latn";
5045 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
5047 const GSUB_Header *header;
5048 const GSUB_Script *script;
5049 const GSUB_LangSys *language;
5050 const GSUB_Feature *feature;
5052 if (!font->GSUB_Table)
5053 return NULL;
5055 header = font->GSUB_Table;
5057 script = GSUB_get_script_table(header, get_opentype_script(font));
5058 if (!script)
5060 TRACE("Script not found\n");
5061 return NULL;
5063 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5064 if (!language)
5066 TRACE("Language not found\n");
5067 return NULL;
5069 feature = GSUB_get_feature(header, language, "vrt2");
5070 if (!feature)
5071 feature = GSUB_get_feature(header, language, "vert");
5072 if (!feature)
5074 TRACE("vrt2/vert feature not found\n");
5075 return NULL;
5077 return feature;
5080 /*************************************************************
5081 * freetype_SelectFont
5083 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5085 struct freetype_physdev *physdev = get_freetype_dev( dev );
5086 GdiFont *ret;
5087 Face *face, *best, *best_bitmap;
5088 Family *family, *last_resort_family;
5089 const struct list *face_list;
5090 INT height, width = 0;
5091 unsigned int score = 0, new_score;
5092 signed int diff = 0, newdiff;
5093 BOOL bd, it, can_use_bitmap, want_vertical;
5094 LOGFONTW lf;
5095 CHARSETINFO csi;
5096 FMAT2 dcmat;
5097 FontSubst *psub = NULL;
5098 DC *dc = get_dc_ptr( dev->hdc );
5099 const SYSTEM_LINKS *font_link;
5101 if (!hfont) /* notification that the font has been changed by another driver */
5103 release_font( physdev->font );
5104 physdev->font = NULL;
5105 release_dc_ptr( dc );
5106 return 0;
5109 GetObjectW( hfont, sizeof(lf), &lf );
5110 lf.lfWidth = abs(lf.lfWidth);
5112 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5114 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5115 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5116 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5117 lf.lfEscapement);
5119 if(dc->GraphicsMode == GM_ADVANCED)
5121 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5122 /* Try to avoid not necessary glyph transformations */
5123 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5125 lf.lfHeight *= fabs(dcmat.eM11);
5126 lf.lfWidth *= fabs(dcmat.eM11);
5127 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5130 else
5132 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5133 font scaling abilities. */
5134 dcmat.eM11 = dcmat.eM22 = 1.0;
5135 dcmat.eM21 = dcmat.eM12 = 0;
5136 lf.lfOrientation = lf.lfEscapement;
5137 if (dc->vport2WorldValid)
5139 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5140 lf.lfOrientation = -lf.lfOrientation;
5141 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5142 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5146 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5147 dcmat.eM21, dcmat.eM22);
5149 GDI_CheckNotLock();
5150 EnterCriticalSection( &freetype_cs );
5152 /* check the cache first */
5153 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5154 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5155 goto done;
5158 TRACE("not in cache\n");
5159 ret = alloc_font();
5161 ret->font_desc.matrix = dcmat;
5162 ret->font_desc.lf = lf;
5163 ret->font_desc.can_use_bitmap = can_use_bitmap;
5164 calc_hash(&ret->font_desc);
5166 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5167 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5168 original value lfCharSet. Note this is a special case for
5169 Symbol and doesn't happen at least for "Wingdings*" */
5171 if(!strcmpiW(lf.lfFaceName, SymbolW))
5172 lf.lfCharSet = SYMBOL_CHARSET;
5174 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5175 switch(lf.lfCharSet) {
5176 case DEFAULT_CHARSET:
5177 csi.fs.fsCsb[0] = 0;
5178 break;
5179 default:
5180 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5181 csi.fs.fsCsb[0] = 0;
5182 break;
5186 family = NULL;
5187 if(lf.lfFaceName[0] != '\0') {
5188 CHILD_FONT *font_link_entry;
5189 LPWSTR FaceName = lf.lfFaceName;
5191 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5193 if(psub) {
5194 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5195 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5196 if (psub->to.charset != -1)
5197 lf.lfCharSet = psub->to.charset;
5200 /* We want a match on name and charset or just name if
5201 charset was DEFAULT_CHARSET. If the latter then
5202 we fixup the returned charset later in get_nearest_charset
5203 where we'll either use the charset of the current ansi codepage
5204 or if that's unavailable the first charset that the font supports.
5206 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5207 if (!strcmpiW(family->FamilyName, FaceName) ||
5208 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
5210 font_link = find_font_link(family->FamilyName);
5211 face_list = get_face_list_from_family(family);
5212 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5213 if (!(face->scalable || can_use_bitmap))
5214 continue;
5215 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5216 goto found;
5217 if (font_link != NULL &&
5218 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5219 goto found;
5220 if (!csi.fs.fsCsb[0])
5221 goto found;
5226 /* Search by full face name. */
5227 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5228 face_list = get_face_list_from_family(family);
5229 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5230 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
5231 (face->scalable || can_use_bitmap))
5233 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5234 goto found_face;
5235 font_link = find_font_link(family->FamilyName);
5236 if (font_link != NULL &&
5237 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5238 goto found_face;
5244 * Try check the SystemLink list first for a replacement font.
5245 * We may find good replacements there.
5247 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5249 if(!strcmpiW(font_link->font_name, FaceName) ||
5250 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
5252 TRACE("found entry in system list\n");
5253 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5255 const SYSTEM_LINKS *links;
5257 face = font_link_entry->face;
5258 if (!(face->scalable || can_use_bitmap))
5259 continue;
5260 family = face->family;
5261 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5262 goto found;
5263 links = find_font_link(family->FamilyName);
5264 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5265 goto found;
5271 psub = NULL; /* substitution is no more relevant */
5273 /* If requested charset was DEFAULT_CHARSET then try using charset
5274 corresponding to the current ansi codepage */
5275 if (!csi.fs.fsCsb[0])
5277 INT acp = GetACP();
5278 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5279 FIXME("TCI failed on codepage %d\n", acp);
5280 csi.fs.fsCsb[0] = 0;
5281 } else
5282 lf.lfCharSet = csi.ciCharset;
5285 want_vertical = (lf.lfFaceName[0] == '@');
5287 /* Face families are in the top 4 bits of lfPitchAndFamily,
5288 so mask with 0xF0 before testing */
5290 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5291 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5292 strcpyW(lf.lfFaceName, defFixed);
5293 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5294 strcpyW(lf.lfFaceName, defSerif);
5295 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5296 strcpyW(lf.lfFaceName, defSans);
5297 else
5298 strcpyW(lf.lfFaceName, defSans);
5299 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5300 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5301 font_link = find_font_link(family->FamilyName);
5302 face_list = get_face_list_from_family(family);
5303 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5304 if (!(face->scalable || can_use_bitmap))
5305 continue;
5306 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5307 goto found;
5308 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5309 goto found;
5314 last_resort_family = NULL;
5315 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5316 font_link = find_font_link(family->FamilyName);
5317 face_list = get_face_list_from_family(family);
5318 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5319 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5320 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5321 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5322 if(face->scalable)
5323 goto found;
5324 if(can_use_bitmap && !last_resort_family)
5325 last_resort_family = family;
5330 if(last_resort_family) {
5331 family = last_resort_family;
5332 csi.fs.fsCsb[0] = 0;
5333 goto found;
5336 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5337 face_list = get_face_list_from_family(family);
5338 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5339 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5340 csi.fs.fsCsb[0] = 0;
5341 WARN("just using first face for now\n");
5342 goto found;
5344 if(can_use_bitmap && !last_resort_family)
5345 last_resort_family = family;
5348 if(!last_resort_family) {
5349 FIXME("can't find a single appropriate font - bailing\n");
5350 free_font(ret);
5351 ret = NULL;
5352 goto done;
5355 WARN("could only find a bitmap font - this will probably look awful!\n");
5356 family = last_resort_family;
5357 csi.fs.fsCsb[0] = 0;
5359 found:
5360 it = lf.lfItalic ? 1 : 0;
5361 bd = lf.lfWeight > 550 ? 1 : 0;
5363 height = lf.lfHeight;
5365 face = best = best_bitmap = NULL;
5366 font_link = find_font_link(family->FamilyName);
5367 face_list = get_face_list_from_family(family);
5368 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5370 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5371 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5372 !csi.fs.fsCsb[0])
5374 BOOL italic, bold;
5376 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5377 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5378 new_score = (italic ^ it) + (bold ^ bd);
5379 if(!best || new_score <= score)
5381 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5382 italic, bold, it, bd);
5383 score = new_score;
5384 best = face;
5385 if(best->scalable && score == 0) break;
5386 if(!best->scalable)
5388 if(height > 0)
5389 newdiff = height - (signed int)(best->size.height);
5390 else
5391 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5392 if(!best_bitmap || new_score < score ||
5393 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5395 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5396 diff = newdiff;
5397 best_bitmap = best;
5398 if(score == 0 && diff == 0) break;
5404 if(best)
5405 face = best->scalable ? best : best_bitmap;
5406 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5407 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5409 found_face:
5410 height = lf.lfHeight;
5412 ret->fs = face->fs;
5414 if(csi.fs.fsCsb[0]) {
5415 ret->charset = lf.lfCharSet;
5416 ret->codepage = csi.ciACP;
5418 else
5419 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5421 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5422 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5424 ret->aveWidth = height ? lf.lfWidth : 0;
5426 if(!face->scalable) {
5427 /* Windows uses integer scaling factors for bitmap fonts */
5428 INT scale, scaled_height;
5429 GdiFont *cachedfont;
5431 /* FIXME: rotation of bitmap fonts is ignored */
5432 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5433 if (ret->aveWidth)
5434 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5435 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5436 dcmat.eM11 = dcmat.eM22 = 1.0;
5437 /* As we changed the matrix, we need to search the cache for the font again,
5438 * otherwise we might explode the cache. */
5439 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5440 TRACE("Found cached font after non-scalable matrix rescale!\n");
5441 free_font( ret );
5442 ret = cachedfont;
5443 goto done;
5445 calc_hash(&ret->font_desc);
5447 if (height != 0) height = diff;
5448 height += face->size.height;
5450 scale = (height + face->size.height - 1) / face->size.height;
5451 scaled_height = scale * face->size.height;
5452 /* Only jump to the next height if the difference <= 25% original height */
5453 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5454 /* The jump between unscaled and doubled is delayed by 1 */
5455 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5456 ret->scale_y = scale;
5458 width = face->size.x_ppem >> 6;
5459 height = face->size.y_ppem >> 6;
5461 else
5462 ret->scale_y = 1.0;
5463 TRACE("font scale y: %f\n", ret->scale_y);
5465 ret->ft_face = OpenFontFace(ret, face, width, height);
5467 if (!ret->ft_face)
5469 free_font( ret );
5470 ret = NULL;
5471 goto done;
5474 ret->ntmFlags = face->ntmFlags;
5476 pick_charmap( ret->ft_face, ret->charset );
5478 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5479 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5480 ret->underline = lf.lfUnderline ? 0xff : 0;
5481 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5482 create_child_font_list(ret);
5484 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5486 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5487 if (length != GDI_ERROR)
5489 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5490 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5491 TRACE("Loaded GSUB table of %i bytes\n",length);
5492 ret->vert_feature = get_GSUB_vert_feature(ret);
5493 if (!ret->vert_feature)
5495 TRACE("Vertical feature not found\n");
5496 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5497 ret->GSUB_Table = NULL;
5501 ret->aa_flags = HIWORD( face->flags );
5503 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5505 add_to_cache(ret);
5506 done:
5507 if (ret)
5509 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5511 switch (lf.lfQuality)
5513 case NONANTIALIASED_QUALITY:
5514 case ANTIALIASED_QUALITY:
5515 next->funcs->pSelectFont( dev, hfont, aa_flags );
5516 break;
5517 case CLEARTYPE_QUALITY:
5518 case CLEARTYPE_NATURAL_QUALITY:
5519 default:
5520 if (!*aa_flags) *aa_flags = ret->aa_flags;
5521 next->funcs->pSelectFont( dev, hfont, aa_flags );
5523 /* fixup the antialiasing flags for that font */
5524 switch (*aa_flags)
5526 case WINE_GGO_HRGB_BITMAP:
5527 case WINE_GGO_HBGR_BITMAP:
5528 case WINE_GGO_VRGB_BITMAP:
5529 case WINE_GGO_VBGR_BITMAP:
5530 if (is_subpixel_rendering_enabled()) break;
5531 *aa_flags = GGO_GRAY4_BITMAP;
5532 /* fall through */
5533 case GGO_GRAY2_BITMAP:
5534 case GGO_GRAY4_BITMAP:
5535 case GGO_GRAY8_BITMAP:
5536 case WINE_GGO_GRAY16_BITMAP:
5537 if (is_hinting_enabled())
5539 WORD gasp_flags;
5540 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5542 TRACE( "font %s %d aa disabled by GASP\n",
5543 debugstr_w(lf.lfFaceName), lf.lfHeight );
5544 *aa_flags = GGO_BITMAP;
5549 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5550 release_font( physdev->font );
5551 physdev->font = ret;
5553 LeaveCriticalSection( &freetype_cs );
5554 release_dc_ptr( dc );
5555 return ret ? hfont : 0;
5558 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5560 HRSRC rsrc;
5561 HGLOBAL hMem;
5562 WCHAR *p;
5563 int i;
5565 id += IDS_FIRST_SCRIPT;
5566 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5567 if (!rsrc) return 0;
5568 hMem = LoadResource( gdi32_module, rsrc );
5569 if (!hMem) return 0;
5571 p = LockResource( hMem );
5572 id &= 0x000f;
5573 while (id--) p += *p + 1;
5575 i = min(LF_FACESIZE - 1, *p);
5576 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5577 buffer[i] = 0;
5578 return i;
5581 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
5583 return (ansi_cp == 874 /* Thai */
5584 || ansi_cp == 1255 /* Hebrew */
5585 || ansi_cp == 1256 /* Arabic */
5589 /***************************************************
5590 * create_enum_charset_list
5592 * This function creates charset enumeration list because in DEFAULT_CHARSET
5593 * case, the ANSI codepage's charset takes precedence over other charsets.
5594 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5595 * This function works as a filter other than DEFAULT_CHARSET case.
5597 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5599 CHARSETINFO csi;
5600 DWORD n = 0;
5602 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5603 csi.fs.fsCsb[0] != 0) {
5604 list->element[n].mask = csi.fs.fsCsb[0];
5605 list->element[n].charset = csi.ciCharset;
5606 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5607 n++;
5609 else { /* charset is DEFAULT_CHARSET or invalid. */
5610 INT acp, i;
5611 DWORD mask = 0;
5613 /* Set the current codepage's charset as the first element. */
5614 acp = GetACP();
5615 if (!is_complex_script_ansi_cp(acp) &&
5616 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5617 csi.fs.fsCsb[0] != 0) {
5618 list->element[n].mask = csi.fs.fsCsb[0];
5619 list->element[n].charset = csi.ciCharset;
5620 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5621 mask |= csi.fs.fsCsb[0];
5622 n++;
5625 /* Fill out left elements. */
5626 for (i = 0; i < 32; i++) {
5627 FONTSIGNATURE fs;
5628 fs.fsCsb[0] = 1L << i;
5629 fs.fsCsb[1] = 0;
5630 if (fs.fsCsb[0] & mask)
5631 continue; /* skip, already added. */
5632 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5633 continue; /* skip, this is an invalid fsCsb bit. */
5635 list->element[n].mask = fs.fsCsb[0];
5636 list->element[n].charset = csi.ciCharset;
5637 load_script_name( i, list->element[n].name );
5638 mask |= fs.fsCsb[0];
5639 n++;
5642 /* add catch all mask for remaining bits */
5643 if (~mask)
5645 list->element[n].mask = ~mask;
5646 list->element[n].charset = DEFAULT_CHARSET;
5647 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5648 n++;
5651 list->total = n;
5653 return n;
5656 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5657 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5659 GdiFont *font;
5660 LONG width, height;
5662 if (face->cached_enum_data)
5664 TRACE("Cached\n");
5665 *pelf = face->cached_enum_data->elf;
5666 *pntm = face->cached_enum_data->ntm;
5667 *ptype = face->cached_enum_data->type;
5668 return;
5671 font = alloc_font();
5673 if(face->scalable) {
5674 height = 100;
5675 width = 0;
5676 } else {
5677 height = face->size.y_ppem >> 6;
5678 width = face->size.x_ppem >> 6;
5680 font->scale_y = 1.0;
5682 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5684 free_font(font);
5685 return;
5688 font->name = strdupW( family_name );
5689 font->ntmFlags = face->ntmFlags;
5691 if (get_outline_text_metrics(font))
5693 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5695 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5696 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5697 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5699 lstrcpynW(pelf->elfLogFont.lfFaceName,
5700 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5701 LF_FACESIZE);
5702 lstrcpynW(pelf->elfFullName,
5703 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5704 LF_FULLFACESIZE);
5705 lstrcpynW(pelf->elfStyle,
5706 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5707 LF_FACESIZE);
5709 else
5711 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5713 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5714 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5715 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5717 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5718 if (face->FullName)
5719 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5720 else
5721 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5722 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5725 pntm->ntmTm.ntmFlags = face->ntmFlags;
5726 pntm->ntmFontSig = face->fs;
5728 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5730 pelf->elfLogFont.lfEscapement = 0;
5731 pelf->elfLogFont.lfOrientation = 0;
5732 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5733 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5734 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5735 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5736 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5737 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5738 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5739 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5740 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5741 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5742 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5744 *ptype = 0;
5745 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5746 *ptype |= TRUETYPE_FONTTYPE;
5747 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5748 *ptype |= DEVICE_FONTTYPE;
5749 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5750 *ptype |= RASTER_FONTTYPE;
5752 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5753 if (face->cached_enum_data)
5755 face->cached_enum_data->elf = *pelf;
5756 face->cached_enum_data->ntm = *pntm;
5757 face->cached_enum_data->type = *ptype;
5760 free_font(font);
5763 static BOOL family_matches(Family *family, const WCHAR *face_name)
5765 Face *face;
5766 const struct list *face_list;
5768 if (!strcmpiW(face_name, family->FamilyName)) return TRUE;
5770 face_list = get_face_list_from_family(family);
5771 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5772 if (face->FullName && !strcmpiW(face_name, face->FullName)) return TRUE;
5774 return FALSE;
5777 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
5779 if (!strcmpiW(face_name, family_name)) return TRUE;
5781 return (face->FullName && !strcmpiW(face_name, face->FullName));
5784 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5785 FONTENUMPROCW proc, LPARAM lparam, const WCHAR *subst)
5787 ENUMLOGFONTEXW elf;
5788 NEWTEXTMETRICEXW ntm;
5789 DWORD type = 0;
5790 DWORD i;
5792 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5793 for(i = 0; i < list->total; i++) {
5794 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5795 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5796 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5797 i = list->total; /* break out of loop after enumeration */
5799 else
5801 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5802 /* use the DEFAULT_CHARSET case only if no other charset is present */
5803 if (list->element[i].charset == DEFAULT_CHARSET &&
5804 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5805 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5806 strcpyW(elf.elfScript, list->element[i].name);
5807 if (!elf.elfScript[0])
5808 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5810 /* Font Replacement */
5811 if (family != face->family)
5813 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5814 if (face->FullName)
5815 strcpyW(elf.elfFullName, face->FullName);
5816 else
5817 strcpyW(elf.elfFullName, family->FamilyName);
5819 if (subst)
5820 strcpyW(elf.elfLogFont.lfFaceName, subst);
5821 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5822 debugstr_w(elf.elfLogFont.lfFaceName),
5823 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5824 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5825 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5826 ntm.ntmTm.ntmFlags);
5827 /* release section before callback (FIXME) */
5828 LeaveCriticalSection( &freetype_cs );
5829 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5830 EnterCriticalSection( &freetype_cs );
5832 return TRUE;
5835 /*************************************************************
5836 * freetype_EnumFonts
5838 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5840 Family *family;
5841 Face *face;
5842 const struct list *face_list;
5843 LOGFONTW lf;
5844 struct enum_charset_list enum_charsets;
5846 if (!plf)
5848 lf.lfCharSet = DEFAULT_CHARSET;
5849 lf.lfPitchAndFamily = 0;
5850 lf.lfFaceName[0] = 0;
5851 plf = &lf;
5854 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5856 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5858 GDI_CheckNotLock();
5859 EnterCriticalSection( &freetype_cs );
5860 if(plf->lfFaceName[0]) {
5861 WCHAR *face_name = plf->lfFaceName;
5862 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5864 if(psub) {
5865 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5866 debugstr_w(psub->to.name));
5867 face_name = psub->to.name;
5870 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5871 if (!family_matches(family, face_name)) continue;
5872 face_list = get_face_list_from_family(family);
5873 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5874 if (!face_matches(family->FamilyName, face, face_name)) continue;
5875 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, psub ? psub->from.name : NULL)) return FALSE;
5878 } else {
5879 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5880 face_list = get_face_list_from_family(family);
5881 face = LIST_ENTRY(list_head(face_list), Face, entry);
5882 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam, NULL)) return FALSE;
5885 LeaveCriticalSection( &freetype_cs );
5886 return TRUE;
5889 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5891 pt->x.value = vec->x >> 6;
5892 pt->x.fract = (vec->x & 0x3f) << 10;
5893 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5894 pt->y.value = vec->y >> 6;
5895 pt->y.fract = (vec->y & 0x3f) << 10;
5896 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5899 /***************************************************
5900 * According to the MSDN documentation on WideCharToMultiByte,
5901 * certain codepages cannot set the default_used parameter.
5902 * This returns TRUE if the codepage can set that parameter, false else
5903 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5905 static BOOL codepage_sets_default_used(UINT codepage)
5907 switch (codepage)
5909 case CP_UTF7:
5910 case CP_UTF8:
5911 case CP_SYMBOL:
5912 return FALSE;
5913 default:
5914 return TRUE;
5919 * GSUB Table handling functions
5922 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5924 const GSUB_CoverageFormat1* cf1;
5926 cf1 = table;
5928 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5930 int count = GET_BE_WORD(cf1->GlyphCount);
5931 int i;
5932 TRACE("Coverage Format 1, %i glyphs\n",count);
5933 for (i = 0; i < count; i++)
5934 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5935 return i;
5936 return -1;
5938 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5940 const GSUB_CoverageFormat2* cf2;
5941 int i;
5942 int count;
5943 cf2 = (const GSUB_CoverageFormat2*)cf1;
5945 count = GET_BE_WORD(cf2->RangeCount);
5946 TRACE("Coverage Format 2, %i ranges\n",count);
5947 for (i = 0; i < count; i++)
5949 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5950 return -1;
5951 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5952 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5954 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5955 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5958 return -1;
5960 else
5961 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5963 return -1;
5966 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5968 int i;
5969 int offset;
5970 const GSUB_LookupList *lookup;
5971 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5973 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5974 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5976 const GSUB_LookupTable *look;
5977 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5978 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5979 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5980 if (GET_BE_WORD(look->LookupType) != 1)
5981 FIXME("We only handle SubType 1\n");
5982 else
5984 int j;
5986 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5988 const GSUB_SingleSubstFormat1 *ssf1;
5989 offset = GET_BE_WORD(look->SubTable[j]);
5990 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5991 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5993 int offset = GET_BE_WORD(ssf1->Coverage);
5994 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5995 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5997 TRACE(" Glyph 0x%x ->",glyph);
5998 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5999 TRACE(" 0x%x\n",glyph);
6002 else
6004 const GSUB_SingleSubstFormat2 *ssf2;
6005 INT index;
6006 INT offset;
6008 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
6009 offset = GET_BE_WORD(ssf1->Coverage);
6010 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
6011 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
6012 TRACE(" Coverage index %i\n",index);
6013 if (index != -1)
6015 TRACE(" Glyph is 0x%x ->",glyph);
6016 glyph = GET_BE_WORD(ssf2->Substitute[index]);
6017 TRACE("0x%x\n",glyph);
6023 return glyph;
6027 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
6029 const GSUB_Header *header;
6030 const GSUB_Feature *feature;
6032 if (!font->GSUB_Table)
6033 return glyph;
6035 header = font->GSUB_Table;
6036 feature = font->vert_feature;
6038 return GSUB_apply_feature(header, feature, glyph);
6041 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
6043 FT_UInt glyphId;
6045 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6046 WCHAR wc = (WCHAR)glyph;
6047 BOOL default_used;
6048 BOOL *default_used_pointer;
6049 FT_UInt ret;
6050 char buf;
6051 default_used_pointer = NULL;
6052 default_used = FALSE;
6053 if (codepage_sets_default_used(font->codepage))
6054 default_used_pointer = &default_used;
6055 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6057 if (font->codepage == CP_SYMBOL && wc < 0x100)
6058 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6059 else
6060 ret = 0;
6062 else
6063 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6064 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6065 return ret;
6068 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6070 if (glyph < 0x100) glyph += 0xf000;
6071 /* there is a number of old pre-Unicode "broken" TTFs, which
6072 do have symbols at U+00XX instead of U+f0XX */
6073 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6074 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6076 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6078 return glyphId;
6081 /* helper for freetype_GetGlyphIndices */
6082 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6084 WCHAR wc = (WCHAR)glyph;
6085 BOOL default_used = FALSE;
6086 BOOL *default_used_pointer = NULL;
6087 FT_UInt ret;
6088 char buf;
6090 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6091 return get_glyph_index(font, glyph);
6093 if (codepage_sets_default_used(font->codepage))
6094 default_used_pointer = &default_used;
6095 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6096 || default_used)
6098 if (font->codepage == CP_SYMBOL && wc < 0x100)
6099 ret = (unsigned char)wc;
6100 else
6101 ret = 0;
6103 else
6104 ret = (unsigned char)buf;
6105 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6106 return ret;
6109 static FT_UInt get_default_char_index(GdiFont *font)
6111 FT_UInt default_char;
6113 if (FT_IS_SFNT(font->ft_face))
6115 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6116 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6118 else
6120 TEXTMETRICW textm;
6121 get_text_metrics(font, &textm);
6122 default_char = textm.tmDefaultChar;
6125 return default_char;
6128 /*************************************************************
6129 * freetype_GetGlyphIndices
6131 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6133 struct freetype_physdev *physdev = get_freetype_dev( dev );
6134 int i;
6135 WORD default_char;
6136 BOOL got_default = FALSE;
6138 if (!physdev->font)
6140 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6141 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6144 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6146 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6147 got_default = TRUE;
6150 GDI_CheckNotLock();
6151 EnterCriticalSection( &freetype_cs );
6153 for(i = 0; i < count; i++)
6155 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6156 if (pgi[i] == 0)
6158 if (!got_default)
6160 default_char = get_default_char_index(physdev->font);
6161 got_default = TRUE;
6163 pgi[i] = default_char;
6165 else
6166 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6168 LeaveCriticalSection( &freetype_cs );
6169 return count;
6172 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6174 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6175 return !memcmp(matrix, &identity, sizeof(FMAT2));
6178 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6180 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6181 return !memcmp(matrix, &identity, sizeof(MAT2));
6184 static void synthesize_bold_glyph(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6186 FT_Error err;
6187 static UINT once;
6189 switch(glyph->format) {
6190 case FT_GLYPH_FORMAT_OUTLINE:
6192 FT_Pos strength;
6193 FT_BBox bbox;
6194 if(!pFT_Outline_Embolden)
6195 break;
6197 strength = MulDiv(ppem, 1 << 6, 24);
6198 err = pFT_Outline_Embolden(&glyph->outline, strength);
6199 if(err) {
6200 TRACE("FT_Ouline_Embolden returns %d, ignored\n", err);
6201 break;
6204 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6205 metrics->width = bbox.xMax - bbox.xMin;
6206 metrics->height = bbox.yMax - bbox.yMin;
6207 metrics->horiBearingX = bbox.xMin;
6208 metrics->horiBearingY = bbox.yMax;
6209 metrics->horiAdvance += (1 << 6);
6210 metrics->vertAdvance += (1 << 6);
6211 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6212 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6213 break;
6215 default:
6216 if (!once++)
6217 WARN("Emboldening format 0x%x is not supported\n", glyph->format);
6218 return;
6222 static inline BYTE get_max_level( UINT format )
6224 switch( format )
6226 case GGO_GRAY2_BITMAP: return 4;
6227 case GGO_GRAY4_BITMAP: return 16;
6228 case GGO_GRAY8_BITMAP: return 64;
6230 return 255;
6233 extern const unsigned short vertical_orientation_table[];
6235 static BOOL check_unicode_tategaki(WCHAR uchar)
6237 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6239 /* We only reach this code if typographical substitution did not occur */
6240 /* Type: U or Type: Tu */
6241 return (orientation == 1 || orientation == 3);
6244 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6246 TTPOLYGONHEADER *pph;
6247 TTPOLYCURVE *ppc;
6248 unsigned int needed = 0, point = 0, contour, first_pt;
6249 unsigned int pph_start, cpfx;
6250 DWORD type;
6252 for (contour = 0; contour < outline->n_contours; contour++)
6254 /* Ignore contours containing one point */
6255 if (point == outline->contours[contour])
6257 point++;
6258 continue;
6261 pph_start = needed;
6262 pph = (TTPOLYGONHEADER *)(buf + needed);
6263 first_pt = point;
6264 if (buf)
6266 pph->dwType = TT_POLYGON_TYPE;
6267 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6269 needed += sizeof(*pph);
6270 point++;
6271 while (point <= outline->contours[contour])
6273 ppc = (TTPOLYCURVE *)(buf + needed);
6274 type = outline->tags[point] & FT_Curve_Tag_On ?
6275 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6276 cpfx = 0;
6279 if (buf)
6280 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6281 cpfx++;
6282 point++;
6283 } while (point <= outline->contours[contour] &&
6284 (outline->tags[point] & FT_Curve_Tag_On) ==
6285 (outline->tags[point-1] & FT_Curve_Tag_On));
6286 /* At the end of a contour Windows adds the start point, but
6287 only for Beziers */
6288 if (point > outline->contours[contour] &&
6289 !(outline->tags[point-1] & FT_Curve_Tag_On))
6291 if (buf)
6292 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6293 cpfx++;
6295 else if (point <= outline->contours[contour] &&
6296 outline->tags[point] & FT_Curve_Tag_On)
6298 /* add closing pt for bezier */
6299 if (buf)
6300 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6301 cpfx++;
6302 point++;
6304 if (buf)
6306 ppc->wType = type;
6307 ppc->cpfx = cpfx;
6309 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6311 if (buf)
6312 pph->cb = needed - pph_start;
6314 return needed;
6317 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6319 /* Convert the quadratic Beziers to cubic Beziers.
6320 The parametric eqn for a cubic Bezier is, from PLRM:
6321 r(t) = at^3 + bt^2 + ct + r0
6322 with the control points:
6323 r1 = r0 + c/3
6324 r2 = r1 + (c + b)/3
6325 r3 = r0 + c + b + a
6327 A quadratic Bezier has the form:
6328 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6330 So equating powers of t leads to:
6331 r1 = 2/3 p1 + 1/3 p0
6332 r2 = 2/3 p1 + 1/3 p2
6333 and of course r0 = p0, r3 = p2
6335 int contour, point = 0, first_pt;
6336 TTPOLYGONHEADER *pph;
6337 TTPOLYCURVE *ppc;
6338 DWORD pph_start, cpfx, type;
6339 FT_Vector cubic_control[4];
6340 unsigned int needed = 0;
6342 for (contour = 0; contour < outline->n_contours; contour++)
6344 pph_start = needed;
6345 pph = (TTPOLYGONHEADER *)(buf + needed);
6346 first_pt = point;
6347 if (buf)
6349 pph->dwType = TT_POLYGON_TYPE;
6350 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6352 needed += sizeof(*pph);
6353 point++;
6354 while (point <= outline->contours[contour])
6356 ppc = (TTPOLYCURVE *)(buf + needed);
6357 type = outline->tags[point] & FT_Curve_Tag_On ?
6358 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6359 cpfx = 0;
6362 if (type == TT_PRIM_LINE)
6364 if (buf)
6365 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6366 cpfx++;
6367 point++;
6369 else
6371 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6372 so cpfx = 3n */
6374 /* FIXME: Possible optimization in endpoint calculation
6375 if there are two consecutive curves */
6376 cubic_control[0] = outline->points[point-1];
6377 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
6379 cubic_control[0].x += outline->points[point].x + 1;
6380 cubic_control[0].y += outline->points[point].y + 1;
6381 cubic_control[0].x >>= 1;
6382 cubic_control[0].y >>= 1;
6384 if (point+1 > outline->contours[contour])
6385 cubic_control[3] = outline->points[first_pt];
6386 else
6388 cubic_control[3] = outline->points[point+1];
6389 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
6391 cubic_control[3].x += outline->points[point].x + 1;
6392 cubic_control[3].y += outline->points[point].y + 1;
6393 cubic_control[3].x >>= 1;
6394 cubic_control[3].y >>= 1;
6397 /* r1 = 1/3 p0 + 2/3 p1
6398 r2 = 1/3 p2 + 2/3 p1 */
6399 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6400 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6401 cubic_control[2] = cubic_control[1];
6402 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6403 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6404 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6405 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6406 if (buf)
6408 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6409 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6410 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6412 cpfx += 3;
6413 point++;
6415 } while (point <= outline->contours[contour] &&
6416 (outline->tags[point] & FT_Curve_Tag_On) ==
6417 (outline->tags[point-1] & FT_Curve_Tag_On));
6418 /* At the end of a contour Windows adds the start point,
6419 but only for Beziers and we've already done that.
6421 if (point <= outline->contours[contour] &&
6422 outline->tags[point] & FT_Curve_Tag_On)
6424 /* This is the closing pt of a bezier, but we've already
6425 added it, so just inc point and carry on */
6426 point++;
6428 if (buf)
6430 ppc->wType = type;
6431 ppc->cpfx = cpfx;
6433 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6435 if (buf)
6436 pph->cb = needed - pph_start;
6438 return needed;
6441 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6443 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6444 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6445 const MAT2* lpmat)
6447 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6448 GLYPHMETRICS gm;
6449 FT_Face ft_face = incoming_font->ft_face;
6450 GdiFont *font = incoming_font;
6451 FT_Glyph_Metrics metrics;
6452 FT_UInt glyph_index;
6453 DWORD width, height, pitch, needed = 0;
6454 FT_Bitmap ft_bitmap;
6455 FT_Error err;
6456 INT left, right, top = 0, bottom = 0, adv;
6457 INT origin_x = 0, origin_y = 0;
6458 FT_Angle angle = 0;
6459 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6460 double widthRatio = 1.0;
6461 FT_Matrix transMat = identityMat;
6462 FT_Matrix transMatUnrotated;
6463 FT_Matrix transMatTategaki;
6464 BOOL needsTransform = FALSE;
6465 BOOL tategaki = (font->name[0] == '@');
6466 BOOL vertical_metrics;
6467 UINT original_index;
6468 LONG avgAdvance = 0;
6469 FT_Fixed em_scale;
6471 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6472 buflen, buf, lpmat);
6474 TRACE("font transform %f %f %f %f\n",
6475 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6476 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6478 if(format & GGO_GLYPH_INDEX) {
6479 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6480 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6481 as glyph index. "Treasure Adventure Game" depends on this. */
6482 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6483 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6484 } else
6485 glyph_index = glyph;
6486 original_index = glyph_index;
6487 format &= ~GGO_GLYPH_INDEX;
6488 /* TODO: Window also turns off tategaki for glyphs passed in by index
6489 if their unicode code points fall outside of the range that is
6490 rotated. */
6491 } else {
6492 BOOL vert;
6493 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6494 ft_face = font->ft_face;
6495 original_index = glyph_index;
6496 if (!vert && tategaki)
6497 tategaki = check_unicode_tategaki(glyph);
6500 if(format & GGO_UNHINTED) {
6501 load_flags |= FT_LOAD_NO_HINTING;
6502 format &= ~GGO_UNHINTED;
6505 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6506 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6507 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6508 font->gmsize * sizeof(GM*));
6509 } else {
6510 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6511 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6513 *lpgm = FONT_GM(font,original_index)->gm;
6514 *abc = FONT_GM(font,original_index)->abc;
6515 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6516 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6517 lpgm->gmCellIncX, lpgm->gmCellIncY);
6518 return 1; /* FIXME */
6522 if (!font->gm[original_index / GM_BLOCK_SIZE])
6523 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6525 /* Scaling factor */
6526 if (font->aveWidth)
6528 TEXTMETRICW tm;
6530 get_text_metrics(font, &tm);
6532 widthRatio = (double)font->aveWidth;
6533 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6535 else
6536 widthRatio = font->scale_y;
6538 /* Scaling transform */
6539 if (widthRatio != 1.0 || font->scale_y != 1.0)
6541 FT_Matrix scaleMat;
6542 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6543 scaleMat.xy = 0;
6544 scaleMat.yx = 0;
6545 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6547 pFT_Matrix_Multiply(&scaleMat, &transMat);
6548 needsTransform = TRUE;
6551 /* Slant transform */
6552 if (font->fake_italic) {
6553 FT_Matrix slantMat;
6555 slantMat.xx = (1 << 16);
6556 slantMat.xy = ((1 << 16) >> 2);
6557 slantMat.yx = 0;
6558 slantMat.yy = (1 << 16);
6559 pFT_Matrix_Multiply(&slantMat, &transMat);
6560 needsTransform = TRUE;
6563 /* Rotation transform */
6564 transMatUnrotated = transMat;
6565 transMatTategaki = transMat;
6566 if(font->orientation || tategaki) {
6567 FT_Matrix rotationMat;
6568 FT_Matrix taterotationMat;
6569 FT_Vector vecAngle;
6571 double orient = font->orientation / 10.0;
6572 double tate_orient = 0.f;
6574 if (tategaki)
6575 tate_orient = ((font->orientation+900)%3600)/10.0;
6576 else
6577 tate_orient = font->orientation/10.0;
6579 if (orient)
6581 angle = FT_FixedFromFloat(orient);
6582 pFT_Vector_Unit(&vecAngle, angle);
6583 rotationMat.xx = vecAngle.x;
6584 rotationMat.xy = -vecAngle.y;
6585 rotationMat.yx = -rotationMat.xy;
6586 rotationMat.yy = rotationMat.xx;
6588 pFT_Matrix_Multiply(&rotationMat, &transMat);
6591 if (tate_orient)
6593 angle = FT_FixedFromFloat(tate_orient);
6594 pFT_Vector_Unit(&vecAngle, angle);
6595 taterotationMat.xx = vecAngle.x;
6596 taterotationMat.xy = -vecAngle.y;
6597 taterotationMat.yx = -taterotationMat.xy;
6598 taterotationMat.yy = taterotationMat.xx;
6599 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6602 needsTransform = TRUE;
6605 /* World transform */
6606 if (!is_identity_FMAT2(&font->font_desc.matrix))
6608 FT_Matrix worldMat;
6609 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6610 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6611 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6612 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6613 pFT_Matrix_Multiply(&worldMat, &transMat);
6614 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6615 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6616 needsTransform = TRUE;
6619 /* Extra transformation specified by caller */
6620 if (!is_identity_MAT2(lpmat))
6622 FT_Matrix extraMat;
6623 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6624 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6625 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6626 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6627 pFT_Matrix_Multiply(&extraMat, &transMat);
6628 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6629 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6630 needsTransform = TRUE;
6633 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6634 /* there is a freetype bug where vertical metrics are only
6635 properly scaled and correct in 2.4.0 or greater */
6636 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6637 vertical_metrics = FALSE;
6639 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6640 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6642 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6644 if(err) {
6645 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6646 return GDI_ERROR;
6649 metrics = ft_face->glyph->metrics;
6650 if(font->fake_bold)
6651 synthesize_bold_glyph(ft_face->glyph, font->ppem, &metrics);
6653 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6654 * by the text metrics. The proper behavior is to clip the glyph metrics to
6655 * fit within the maximums specified in the text metrics. */
6656 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6657 get_bitmap_text_metrics(incoming_font)) {
6658 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6659 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6660 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6661 metrics.horiBearingY = top;
6662 metrics.height = top - bottom;
6664 /* TODO: Are we supposed to clip the width as well...? */
6665 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6668 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6670 if(FT_IS_SCALABLE(incoming_font->ft_face) && !font->fake_bold) {
6671 TEXTMETRICW tm;
6672 if (get_text_metrics(incoming_font, &tm) &&
6673 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6674 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6675 if (avgAdvance &&
6676 (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6677 TRACE("Fixed-pitch full-width character detected\n");
6678 else
6679 avgAdvance = 0; /* cancel this feature */
6683 if(!needsTransform) {
6684 left = (INT)(metrics.horiBearingX) & -64;
6685 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6686 if (!avgAdvance)
6687 adv = (INT)(metrics.horiAdvance + 63) >> 6;
6688 else
6689 adv = (INT)avgAdvance * 2;
6691 top = (metrics.horiBearingY + 63) & -64;
6692 bottom = (metrics.horiBearingY - metrics.height) & -64;
6693 gm.gmCellIncX = adv;
6694 gm.gmCellIncY = 0;
6695 origin_x = left;
6696 origin_y = top;
6697 abc->abcA = origin_x >> 6;
6698 abc->abcB = metrics.width >> 6;
6699 } else {
6700 INT xc, yc;
6701 FT_Vector vec;
6702 FT_Pos lsb;
6704 left = right = 0;
6706 for(xc = 0; xc < 2; xc++) {
6707 for(yc = 0; yc < 2; yc++) {
6708 vec.x = metrics.horiBearingX + xc * metrics.width;
6709 vec.y = metrics.horiBearingY - yc * metrics.height;
6710 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6711 pFT_Vector_Transform(&vec, &transMatTategaki);
6712 if(xc == 0 && yc == 0) {
6713 left = right = vec.x;
6714 top = bottom = vec.y;
6715 } else {
6716 if(vec.x < left) left = vec.x;
6717 else if(vec.x > right) right = vec.x;
6718 if(vec.y < bottom) bottom = vec.y;
6719 else if(vec.y > top) top = vec.y;
6723 left = left & -64;
6724 right = (right + 63) & -64;
6725 bottom = bottom & -64;
6726 top = (top + 63) & -64;
6728 if (tategaki && (font->potm || get_outline_text_metrics(font)))
6730 if (vertical_metrics)
6731 lsb = metrics.horiBearingY + metrics.vertBearingY;
6732 else
6733 lsb = metrics.vertAdvance + (font->potm->otmDescent << 6);
6734 vec.x = lsb;
6735 vec.y = font->potm->otmDescent << 6;
6736 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
6737 pFT_Vector_Transform(&vec, &transMat);
6738 origin_x = (vec.x + left) & -64;
6739 origin_y = (vec.y + top + 63) & -64;
6741 else
6743 origin_x = left;
6744 origin_y = top;
6745 lsb = metrics.horiBearingX;
6748 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6749 if (vertical_metrics)
6750 vec.x = metrics.vertAdvance;
6751 else
6752 vec.x = metrics.horiAdvance;
6753 vec.y = 0;
6754 pFT_Vector_Transform(&vec, &transMat);
6755 gm.gmCellIncY = -((vec.y+63) >> 6);
6756 if (!avgAdvance || vec.y)
6757 gm.gmCellIncX = (vec.x+63) >> 6;
6758 else {
6759 vec.x = incoming_font->ntmAvgWidth;
6760 vec.y = 0;
6761 pFT_Vector_Transform(&vec, &transMat);
6762 gm.gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6765 if (vertical_metrics)
6766 vec.x = metrics.vertAdvance;
6767 else
6768 vec.x = metrics.horiAdvance;
6769 vec.y = 0;
6770 pFT_Vector_Transform(&vec, &transMatUnrotated);
6771 if (!avgAdvance || vec.y)
6772 adv = (vec.x+63) >> 6;
6773 else {
6774 vec.x = incoming_font->ntmAvgWidth;
6775 vec.y = 0;
6776 pFT_Vector_Transform(&vec, &transMatUnrotated);
6777 adv = pFT_MulFix(vec.x, em_scale) * 2;
6780 vec.x = lsb;
6781 vec.y = 0;
6782 pFT_Vector_Transform(&vec, &transMatUnrotated);
6783 abc->abcA = vec.x >> 6;
6785 vec.x = metrics.width;
6786 vec.y = 0;
6787 pFT_Vector_Transform(&vec, &transMatUnrotated);
6788 if (vec.x >= 0)
6789 abc->abcB = vec.x >> 6;
6790 else
6791 abc->abcB = -vec.x >> 6;
6794 width = (right - left) >> 6;
6795 height = (top - bottom) >> 6;
6796 gm.gmBlackBoxX = width ? width : 1;
6797 gm.gmBlackBoxY = height ? height : 1;
6798 gm.gmptGlyphOrigin.x = origin_x >> 6;
6799 gm.gmptGlyphOrigin.y = origin_y >> 6;
6800 if (!abc->abcB) abc->abcB = 1;
6801 abc->abcC = adv - abc->abcA - abc->abcB;
6803 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
6804 wine_dbgstr_point(&gm.gmptGlyphOrigin),
6805 gm.gmCellIncX, gm.gmCellIncY);
6807 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6808 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6810 FONT_GM(font,original_index)->gm = gm;
6811 FONT_GM(font,original_index)->abc = *abc;
6812 FONT_GM(font,original_index)->init = TRUE;
6815 if(format == GGO_METRICS)
6817 *lpgm = gm;
6818 return 1; /* FIXME */
6821 if(ft_face->glyph->format != ft_glyph_format_outline &&
6822 (format == GGO_NATIVE || format == GGO_BEZIER))
6824 TRACE("loaded a bitmap\n");
6825 return GDI_ERROR;
6828 switch(format) {
6829 case GGO_BITMAP:
6830 pitch = ((width + 31) >> 5) << 2;
6831 needed = pitch * height;
6833 if(!buf || !buflen) break;
6834 if (!needed) return GDI_ERROR; /* empty glyph */
6835 if (needed > buflen)
6836 return GDI_ERROR;
6838 switch(ft_face->glyph->format) {
6839 case ft_glyph_format_bitmap:
6841 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6842 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
6843 INT h = min( height, ft_face->glyph->bitmap.rows );
6844 while(h--) {
6845 memcpy(dst, src, w);
6846 src += ft_face->glyph->bitmap.pitch;
6847 dst += pitch;
6849 break;
6852 case ft_glyph_format_outline:
6853 ft_bitmap.width = width;
6854 ft_bitmap.rows = height;
6855 ft_bitmap.pitch = pitch;
6856 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6857 ft_bitmap.buffer = buf;
6859 if(needsTransform)
6860 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6862 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6864 /* Note: FreeType will only set 'black' bits for us. */
6865 memset(buf, 0, needed);
6866 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6867 break;
6869 default:
6870 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6871 return GDI_ERROR;
6873 break;
6875 case GGO_GRAY2_BITMAP:
6876 case GGO_GRAY4_BITMAP:
6877 case GGO_GRAY8_BITMAP:
6878 case WINE_GGO_GRAY16_BITMAP:
6880 unsigned int max_level, row, col;
6881 BYTE *start, *ptr;
6883 pitch = (width + 3) / 4 * 4;
6884 needed = pitch * height;
6886 if(!buf || !buflen) break;
6887 if (!needed) return GDI_ERROR; /* empty glyph */
6888 if (needed > buflen)
6889 return GDI_ERROR;
6891 max_level = get_max_level( format );
6893 switch(ft_face->glyph->format) {
6894 case ft_glyph_format_bitmap:
6896 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6897 INT h = min( height, ft_face->glyph->bitmap.rows );
6898 INT x;
6899 memset( buf, 0, needed );
6900 while(h--) {
6901 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6902 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6903 src += ft_face->glyph->bitmap.pitch;
6904 dst += pitch;
6906 break;
6908 case ft_glyph_format_outline:
6910 ft_bitmap.width = width;
6911 ft_bitmap.rows = height;
6912 ft_bitmap.pitch = pitch;
6913 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6914 ft_bitmap.buffer = buf;
6916 if(needsTransform)
6917 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6919 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6921 memset(ft_bitmap.buffer, 0, buflen);
6923 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6925 if (max_level != 255)
6927 for (row = 0, start = buf; row < height; row++)
6929 for (col = 0, ptr = start; col < width; col++, ptr++)
6930 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6931 start += pitch;
6934 break;
6937 default:
6938 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6939 return GDI_ERROR;
6941 break;
6944 case WINE_GGO_HRGB_BITMAP:
6945 case WINE_GGO_HBGR_BITMAP:
6946 case WINE_GGO_VRGB_BITMAP:
6947 case WINE_GGO_VBGR_BITMAP:
6948 #ifdef FT_LCD_FILTER_H
6950 switch (ft_face->glyph->format)
6952 case FT_GLYPH_FORMAT_BITMAP:
6954 BYTE *src, *dst;
6955 INT src_pitch, x;
6957 pitch = width * 4;
6958 needed = pitch * height;
6960 if (!buf || !buflen) break;
6961 if (!needed) return GDI_ERROR; /* empty glyph */
6962 if (needed > buflen)
6963 return GDI_ERROR;
6965 memset(buf, 0, buflen);
6966 dst = buf;
6967 src = ft_face->glyph->bitmap.buffer;
6968 src_pitch = ft_face->glyph->bitmap.pitch;
6970 height = min( height, ft_face->glyph->bitmap.rows );
6971 while ( height-- )
6973 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6975 if ( src[x / 8] & masks[x % 8] )
6976 ((unsigned int *)dst)[x] = ~0u;
6978 src += src_pitch;
6979 dst += pitch;
6982 break;
6985 case FT_GLYPH_FORMAT_OUTLINE:
6987 unsigned int *dst;
6988 BYTE *src;
6989 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6990 INT x_shift, y_shift;
6991 BOOL rgb;
6992 FT_Render_Mode render_mode =
6993 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6994 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6996 if (!width || !height)
6998 if (!buf || !buflen) break;
6999 return GDI_ERROR;
7002 if ( render_mode == FT_RENDER_MODE_LCD)
7004 gm.gmBlackBoxX += 2;
7005 gm.gmptGlyphOrigin.x -= 1;
7006 left -= (1 << 6);
7008 else
7010 gm.gmBlackBoxY += 2;
7011 gm.gmptGlyphOrigin.y += 1;
7012 top += (1 << 6);
7015 width = gm.gmBlackBoxX;
7016 height = gm.gmBlackBoxY;
7017 pitch = width * 4;
7018 needed = pitch * height;
7020 if (!buf || !buflen) break;
7021 if (needed > buflen)
7022 return GDI_ERROR;
7024 memset(buf, 0, buflen);
7025 dst = buf;
7026 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
7028 if ( needsTransform )
7029 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
7031 if ( pFT_Library_SetLcdFilter )
7032 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
7033 pFT_Render_Glyph (ft_face->glyph, render_mode);
7035 src = ft_face->glyph->bitmap.buffer;
7036 src_pitch = ft_face->glyph->bitmap.pitch;
7037 src_width = ft_face->glyph->bitmap.width;
7038 src_height = ft_face->glyph->bitmap.rows;
7040 if ( render_mode == FT_RENDER_MODE_LCD)
7042 rgb_interval = 1;
7043 hmul = 3;
7044 vmul = 1;
7046 else
7048 rgb_interval = src_pitch;
7049 hmul = 1;
7050 vmul = 3;
7053 x_shift = ft_face->glyph->bitmap_left - (left >> 6);
7054 if ( x_shift < 0 )
7056 src += hmul * -x_shift;
7057 src_width -= hmul * -x_shift;
7059 else if ( x_shift > 0 )
7061 dst += x_shift;
7062 width -= x_shift;
7065 y_shift = (top >> 6) - ft_face->glyph->bitmap_top;
7066 if ( y_shift < 0 )
7068 src += src_pitch * vmul * -y_shift;
7069 src_height -= vmul * -y_shift;
7071 else if ( y_shift > 0 )
7073 dst += y_shift * ( pitch / sizeof(*dst) );
7074 height -= y_shift;
7077 width = min( width, src_width / hmul );
7078 height = min( height, src_height / vmul );
7080 while ( height-- )
7082 for ( x = 0; x < width; x++ )
7084 if ( rgb )
7086 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
7087 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7088 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
7089 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7091 else
7093 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
7094 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7095 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
7096 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7099 src += src_pitch * vmul;
7100 dst += pitch / sizeof(*dst);
7103 break;
7106 default:
7107 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
7108 return GDI_ERROR;
7111 break;
7113 #else
7114 return GDI_ERROR;
7115 #endif
7117 case GGO_NATIVE:
7119 FT_Outline *outline = &ft_face->glyph->outline;
7121 if(buflen == 0) buf = NULL;
7123 if (needsTransform && buf)
7124 pFT_Outline_Transform(outline, &transMatTategaki);
7126 needed = get_native_glyph_outline(outline, buflen, NULL);
7128 if (!buf || !buflen)
7129 break;
7130 if (needed > buflen)
7131 return GDI_ERROR;
7133 get_native_glyph_outline(outline, buflen, buf);
7134 break;
7136 case GGO_BEZIER:
7138 FT_Outline *outline = &ft_face->glyph->outline;
7139 if(buflen == 0) buf = NULL;
7141 if (needsTransform && buf)
7142 pFT_Outline_Transform(outline, &transMat);
7144 needed = get_bezier_glyph_outline(outline, buflen, NULL);
7146 if (!buf || !buflen)
7147 break;
7148 if (needed > buflen)
7149 return GDI_ERROR;
7151 get_bezier_glyph_outline(outline, buflen, buf);
7152 break;
7155 default:
7156 FIXME("Unsupported format %d\n", format);
7157 return GDI_ERROR;
7159 *lpgm = gm;
7160 return needed;
7163 static BOOL get_bitmap_text_metrics(GdiFont *font)
7165 FT_Face ft_face = font->ft_face;
7166 FT_WinFNT_HeaderRec winfnt_header;
7167 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7168 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7169 font->potm->otmSize = size;
7171 #define TM font->potm->otmTextMetrics
7172 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7174 TM.tmHeight = winfnt_header.pixel_height;
7175 TM.tmAscent = winfnt_header.ascent;
7176 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7177 TM.tmInternalLeading = winfnt_header.internal_leading;
7178 TM.tmExternalLeading = winfnt_header.external_leading;
7179 TM.tmAveCharWidth = winfnt_header.avg_width;
7180 TM.tmMaxCharWidth = winfnt_header.max_width;
7181 TM.tmWeight = winfnt_header.weight;
7182 TM.tmOverhang = 0;
7183 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7184 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7185 TM.tmFirstChar = winfnt_header.first_char;
7186 TM.tmLastChar = winfnt_header.last_char;
7187 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7188 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7189 TM.tmItalic = winfnt_header.italic;
7190 TM.tmUnderlined = font->underline;
7191 TM.tmStruckOut = font->strikeout;
7192 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7193 TM.tmCharSet = winfnt_header.charset;
7195 else
7197 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7198 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7199 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7200 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7201 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7202 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7203 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7204 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7205 TM.tmOverhang = 0;
7206 TM.tmDigitizedAspectX = 96; /* FIXME */
7207 TM.tmDigitizedAspectY = 96; /* FIXME */
7208 TM.tmFirstChar = 1;
7209 TM.tmLastChar = 255;
7210 TM.tmDefaultChar = 32;
7211 TM.tmBreakChar = 32;
7212 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7213 TM.tmUnderlined = font->underline;
7214 TM.tmStruckOut = font->strikeout;
7215 /* NB inverted meaning of TMPF_FIXED_PITCH */
7216 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
7217 TM.tmCharSet = font->charset;
7219 #undef TM
7221 return TRUE;
7225 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7227 double scale_x, scale_y;
7229 if (font->aveWidth)
7231 scale_x = (double)font->aveWidth;
7232 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7234 else
7235 scale_x = font->scale_y;
7237 scale_x *= fabs(font->font_desc.matrix.eM11);
7238 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7240 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7241 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7243 SCALE_Y(ptm->tmHeight);
7244 SCALE_Y(ptm->tmAscent);
7245 SCALE_Y(ptm->tmDescent);
7246 SCALE_Y(ptm->tmInternalLeading);
7247 SCALE_Y(ptm->tmExternalLeading);
7248 SCALE_Y(ptm->tmOverhang);
7250 SCALE_X(ptm->tmAveCharWidth);
7251 SCALE_X(ptm->tmMaxCharWidth);
7253 #undef SCALE_X
7254 #undef SCALE_Y
7257 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7259 double scale_x, scale_y;
7261 if (font->aveWidth)
7263 scale_x = (double)font->aveWidth;
7264 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7266 else
7267 scale_x = font->scale_y;
7269 scale_x *= fabs(font->font_desc.matrix.eM11);
7270 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7272 scale_font_metrics(font, &potm->otmTextMetrics);
7274 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7275 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7277 SCALE_Y(potm->otmAscent);
7278 SCALE_Y(potm->otmDescent);
7279 SCALE_Y(potm->otmLineGap);
7280 SCALE_Y(potm->otmsCapEmHeight);
7281 SCALE_Y(potm->otmsXHeight);
7282 SCALE_Y(potm->otmrcFontBox.top);
7283 SCALE_Y(potm->otmrcFontBox.bottom);
7284 SCALE_X(potm->otmrcFontBox.left);
7285 SCALE_X(potm->otmrcFontBox.right);
7286 SCALE_Y(potm->otmMacAscent);
7287 SCALE_Y(potm->otmMacDescent);
7288 SCALE_Y(potm->otmMacLineGap);
7289 SCALE_X(potm->otmptSubscriptSize.x);
7290 SCALE_Y(potm->otmptSubscriptSize.y);
7291 SCALE_X(potm->otmptSubscriptOffset.x);
7292 SCALE_Y(potm->otmptSubscriptOffset.y);
7293 SCALE_X(potm->otmptSuperscriptSize.x);
7294 SCALE_Y(potm->otmptSuperscriptSize.y);
7295 SCALE_X(potm->otmptSuperscriptOffset.x);
7296 SCALE_Y(potm->otmptSuperscriptOffset.y);
7297 SCALE_Y(potm->otmsStrikeoutSize);
7298 SCALE_Y(potm->otmsStrikeoutPosition);
7299 SCALE_Y(potm->otmsUnderscoreSize);
7300 SCALE_Y(potm->otmsUnderscorePosition);
7302 #undef SCALE_X
7303 #undef SCALE_Y
7306 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7308 if(!font->potm)
7310 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7312 /* Make sure that the font has sane width/height ratio */
7313 if (font->aveWidth)
7315 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7317 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7318 font->aveWidth = 0;
7322 *ptm = font->potm->otmTextMetrics;
7323 scale_font_metrics(font, ptm);
7324 return TRUE;
7327 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7329 int i;
7331 for(i = 0; i < ft_face->num_charmaps; i++)
7333 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7334 return TRUE;
7336 return FALSE;
7339 static BOOL get_outline_text_metrics(GdiFont *font)
7341 BOOL ret = FALSE;
7342 FT_Face ft_face = font->ft_face;
7343 UINT needed, lenfam, lensty, lenface, lenfull;
7344 TT_OS2 *pOS2;
7345 TT_HoriHeader *pHori;
7346 TT_Postscript *pPost;
7347 FT_Fixed em_scale;
7348 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7349 char *cp;
7350 INT ascent, descent;
7351 USHORT windescent;
7353 TRACE("font=%p\n", font);
7355 if(!FT_IS_SCALABLE(ft_face))
7356 return FALSE;
7358 needed = sizeof(*font->potm);
7360 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7361 family_nameW = strdupW(font->name);
7363 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7364 if (!style_nameW)
7366 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7367 style_nameW = towstr( CP_ACP, ft_face->style_name );
7369 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7371 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7372 if (!face_nameW)
7374 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7375 face_nameW = strdupW(font->name);
7377 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7378 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7380 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7381 if (!full_nameW)
7383 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7384 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7385 full_nameW = strdupW(fake_nameW);
7387 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7389 /* These names should be read from the TT name table */
7391 /* length of otmpFamilyName */
7392 needed += lenfam;
7394 /* length of otmpFaceName */
7395 needed += lenface;
7397 /* length of otmpStyleName */
7398 needed += lensty;
7400 /* length of otmpFullName */
7401 needed += lenfull;
7404 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7406 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7407 if(!pOS2) {
7408 FIXME("Can't find OS/2 table - not TT font?\n");
7409 goto end;
7412 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7413 if(!pHori) {
7414 FIXME("Can't find HHEA table - not TT font?\n");
7415 goto end;
7418 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7420 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",
7421 pOS2->usWinAscent, pOS2->usWinDescent,
7422 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7423 pOS2->xAvgCharWidth,
7424 ft_face->ascender, ft_face->descender, ft_face->height,
7425 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7426 ft_face->bbox.yMax, ft_face->bbox.yMin);
7428 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7429 font->potm->otmSize = needed;
7431 #define TM font->potm->otmTextMetrics
7433 windescent = get_fixed_windescent(pOS2->usWinDescent);
7434 if(pOS2->usWinAscent + windescent == 0) {
7435 ascent = pHori->Ascender;
7436 descent = -pHori->Descender;
7437 } else {
7438 ascent = pOS2->usWinAscent;
7439 descent = windescent;
7442 font->ntmCellHeight = ascent + descent;
7443 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7445 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7446 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7448 if(font->yMax) {
7449 TM.tmAscent = font->yMax;
7450 TM.tmDescent = -font->yMin;
7451 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7452 } else {
7453 TM.tmAscent = SCALE_Y(ascent);
7454 TM.tmDescent = SCALE_Y(descent);
7455 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7458 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7460 /* MSDN says:
7461 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7463 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7464 ((ascent + descent) -
7465 (pHori->Ascender - pHori->Descender))));
7467 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7468 if (TM.tmAveCharWidth == 0) {
7469 TM.tmAveCharWidth = 1;
7471 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7472 TM.tmWeight = FW_REGULAR;
7473 if (font->fake_bold) {
7474 TM.tmAveCharWidth++;
7475 TM.tmMaxCharWidth++;
7476 TM.tmWeight = FW_BOLD;
7478 else
7480 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7482 if (pOS2->usWeightClass > FW_MEDIUM)
7483 TM.tmWeight = pOS2->usWeightClass;
7485 else if (pOS2->usWeightClass <= FW_MEDIUM)
7486 TM.tmWeight = pOS2->usWeightClass;
7488 TM.tmOverhang = 0;
7489 TM.tmDigitizedAspectX = 96; /* FIXME */
7490 TM.tmDigitizedAspectY = 96; /* FIXME */
7491 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7492 * symbol range to 0 - f0ff
7495 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7497 TM.tmFirstChar = 0;
7498 switch(GetACP())
7500 case 1255: /* Hebrew */
7501 TM.tmLastChar = 0xf896;
7502 break;
7503 case 1257: /* Baltic */
7504 TM.tmLastChar = 0xf8fd;
7505 break;
7506 default:
7507 TM.tmLastChar = 0xf0ff;
7509 TM.tmBreakChar = 0x20;
7510 TM.tmDefaultChar = 0x1f;
7512 else
7514 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7515 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7517 if(pOS2->usFirstCharIndex <= 1)
7518 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7519 else if (pOS2->usFirstCharIndex > 0xff)
7520 TM.tmBreakChar = 0x20;
7521 else
7522 TM.tmBreakChar = pOS2->usFirstCharIndex;
7523 TM.tmDefaultChar = TM.tmBreakChar - 1;
7525 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7526 TM.tmUnderlined = font->underline;
7527 TM.tmStruckOut = font->strikeout;
7529 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7530 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7531 (pOS2->version == 0xFFFFU ||
7532 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7533 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7534 else
7535 TM.tmPitchAndFamily = 0;
7537 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7539 case PAN_FAMILY_SCRIPT:
7540 TM.tmPitchAndFamily |= FF_SCRIPT;
7541 break;
7543 case PAN_FAMILY_DECORATIVE:
7544 TM.tmPitchAndFamily |= FF_DECORATIVE;
7545 break;
7547 case PAN_ANY:
7548 case PAN_NO_FIT:
7549 case PAN_FAMILY_TEXT_DISPLAY:
7550 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7551 /* which is clearly not what the panose spec says. */
7552 default:
7553 if(TM.tmPitchAndFamily == 0 || /* fixed */
7554 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7555 TM.tmPitchAndFamily = FF_MODERN;
7556 else
7558 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7560 case PAN_ANY:
7561 case PAN_NO_FIT:
7562 default:
7563 TM.tmPitchAndFamily |= FF_DONTCARE;
7564 break;
7566 case PAN_SERIF_COVE:
7567 case PAN_SERIF_OBTUSE_COVE:
7568 case PAN_SERIF_SQUARE_COVE:
7569 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7570 case PAN_SERIF_SQUARE:
7571 case PAN_SERIF_THIN:
7572 case PAN_SERIF_BONE:
7573 case PAN_SERIF_EXAGGERATED:
7574 case PAN_SERIF_TRIANGLE:
7575 TM.tmPitchAndFamily |= FF_ROMAN;
7576 break;
7578 case PAN_SERIF_NORMAL_SANS:
7579 case PAN_SERIF_OBTUSE_SANS:
7580 case PAN_SERIF_PERP_SANS:
7581 case PAN_SERIF_FLARED:
7582 case PAN_SERIF_ROUNDED:
7583 TM.tmPitchAndFamily |= FF_SWISS;
7584 break;
7587 break;
7590 if(FT_IS_SCALABLE(ft_face))
7591 TM.tmPitchAndFamily |= TMPF_VECTOR;
7593 if(FT_IS_SFNT(ft_face))
7595 if (font->ntmFlags & NTM_PS_OPENTYPE)
7596 TM.tmPitchAndFamily |= TMPF_DEVICE;
7597 else
7598 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7601 TM.tmCharSet = font->charset;
7603 font->potm->otmFiller = 0;
7604 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7605 font->potm->otmfsSelection = pOS2->fsSelection;
7606 font->potm->otmfsType = pOS2->fsType;
7607 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7608 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7609 font->potm->otmItalicAngle = 0; /* POST table */
7610 font->potm->otmEMSquare = ft_face->units_per_EM;
7611 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7612 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7613 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7614 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7615 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7616 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7617 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7618 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7619 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7620 font->potm->otmMacAscent = TM.tmAscent;
7621 font->potm->otmMacDescent = -TM.tmDescent;
7622 font->potm->otmMacLineGap = font->potm->otmLineGap;
7623 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7624 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7625 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7626 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7627 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7628 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7629 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7630 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7631 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7632 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7633 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7634 if(!pPost) {
7635 font->potm->otmsUnderscoreSize = 0;
7636 font->potm->otmsUnderscorePosition = 0;
7637 } else {
7638 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7639 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7641 #undef SCALE_X
7642 #undef SCALE_Y
7643 #undef TM
7645 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7646 cp = (char*)font->potm + sizeof(*font->potm);
7647 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7648 strcpyW((WCHAR*)cp, family_nameW);
7649 cp += lenfam;
7650 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7651 strcpyW((WCHAR*)cp, style_nameW);
7652 cp += lensty;
7653 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7654 strcpyW((WCHAR*)cp, face_nameW);
7655 cp += lenface;
7656 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7657 strcpyW((WCHAR*)cp, full_nameW);
7658 ret = TRUE;
7660 end:
7661 HeapFree(GetProcessHeap(), 0, style_nameW);
7662 HeapFree(GetProcessHeap(), 0, family_nameW);
7663 HeapFree(GetProcessHeap(), 0, face_nameW);
7664 HeapFree(GetProcessHeap(), 0, full_nameW);
7665 return ret;
7668 /*************************************************************
7669 * freetype_GetGlyphOutline
7671 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7672 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7674 struct freetype_physdev *physdev = get_freetype_dev( dev );
7675 DWORD ret;
7676 ABC abc;
7678 if (!physdev->font)
7680 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7681 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7684 GDI_CheckNotLock();
7685 EnterCriticalSection( &freetype_cs );
7686 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7687 LeaveCriticalSection( &freetype_cs );
7688 return ret;
7691 /*************************************************************
7692 * freetype_GetTextMetrics
7694 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7696 struct freetype_physdev *physdev = get_freetype_dev( dev );
7697 BOOL ret;
7699 if (!physdev->font)
7701 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7702 return dev->funcs->pGetTextMetrics( dev, metrics );
7705 GDI_CheckNotLock();
7706 EnterCriticalSection( &freetype_cs );
7707 ret = get_text_metrics( physdev->font, metrics );
7708 LeaveCriticalSection( &freetype_cs );
7709 return ret;
7712 /*************************************************************
7713 * freetype_GetOutlineTextMetrics
7715 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7717 struct freetype_physdev *physdev = get_freetype_dev( dev );
7718 UINT ret = 0;
7720 if (!physdev->font)
7722 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7723 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7726 TRACE("font=%p\n", physdev->font);
7728 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7730 GDI_CheckNotLock();
7731 EnterCriticalSection( &freetype_cs );
7733 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7735 if(potm && cbSize >= physdev->font->potm->otmSize)
7737 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7738 scale_outline_font_metrics(physdev->font, potm);
7740 ret = physdev->font->potm->otmSize;
7742 LeaveCriticalSection( &freetype_cs );
7743 return ret;
7746 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7748 child->font = alloc_font();
7749 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7750 if(!child->font->ft_face)
7752 free_font(child->font);
7753 child->font = NULL;
7754 return FALSE;
7757 child->font->font_desc = font->font_desc;
7758 child->font->ntmFlags = child->face->ntmFlags;
7759 child->font->orientation = font->orientation;
7760 child->font->scale_y = font->scale_y;
7761 child->font->name = strdupW(child->face->family->FamilyName);
7762 child->font->base_font = font;
7763 TRACE("created child font %p for base %p\n", child->font, font);
7764 return TRUE;
7767 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
7769 FT_UInt g,o;
7770 CHILD_FONT *child_font;
7772 if(font->base_font)
7773 font = font->base_font;
7775 *linked_font = font;
7777 if((*glyph = get_glyph_index(font, c)))
7779 o = *glyph;
7780 *glyph = get_GSUB_vert_glyph(font, *glyph);
7781 *vert = (o != *glyph);
7782 return TRUE;
7785 if (c < 32) goto done; /* don't check linked fonts for control characters */
7787 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7789 if(!child_font->font)
7790 if(!load_child_font(font, child_font))
7791 continue;
7793 if(!child_font->font->ft_face)
7794 continue;
7795 g = get_glyph_index(child_font->font, c);
7796 o = g;
7797 g = get_GSUB_vert_glyph(child_font->font, g);
7798 if(g)
7800 *glyph = g;
7801 *linked_font = child_font->font;
7802 *vert = (o != g);
7803 return TRUE;
7807 done:
7808 *vert = FALSE;
7809 return FALSE;
7812 /*************************************************************
7813 * freetype_GetCharWidth
7815 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7817 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7818 UINT c;
7819 GLYPHMETRICS gm;
7820 ABC abc;
7821 struct freetype_physdev *physdev = get_freetype_dev( dev );
7823 if (!physdev->font)
7825 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7826 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7829 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7831 GDI_CheckNotLock();
7832 EnterCriticalSection( &freetype_cs );
7833 for(c = firstChar; c <= lastChar; c++) {
7834 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7835 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7837 LeaveCriticalSection( &freetype_cs );
7838 return TRUE;
7841 /*************************************************************
7842 * freetype_GetCharABCWidths
7844 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7846 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7847 UINT c;
7848 GLYPHMETRICS gm;
7849 struct freetype_physdev *physdev = get_freetype_dev( dev );
7851 if (!physdev->font)
7853 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7854 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7857 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7859 GDI_CheckNotLock();
7860 EnterCriticalSection( &freetype_cs );
7862 for(c = firstChar; c <= lastChar; c++, buffer++)
7863 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7865 LeaveCriticalSection( &freetype_cs );
7866 return TRUE;
7869 /*************************************************************
7870 * freetype_GetCharABCWidthsI
7872 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7874 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7875 UINT c;
7876 GLYPHMETRICS gm;
7877 struct freetype_physdev *physdev = get_freetype_dev( dev );
7879 if (!physdev->font)
7881 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7882 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7885 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7886 return FALSE;
7888 GDI_CheckNotLock();
7889 EnterCriticalSection( &freetype_cs );
7891 for(c = 0; c < count; c++, buffer++)
7892 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7893 &gm, buffer, 0, NULL, &identity );
7895 LeaveCriticalSection( &freetype_cs );
7896 return TRUE;
7899 /*************************************************************
7900 * freetype_GetTextExtentExPoint
7902 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7904 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7905 INT idx, pos;
7906 ABC abc;
7907 GLYPHMETRICS gm;
7908 struct freetype_physdev *physdev = get_freetype_dev( dev );
7910 if (!physdev->font)
7912 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7913 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7916 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7918 GDI_CheckNotLock();
7919 EnterCriticalSection( &freetype_cs );
7921 for (idx = pos = 0; idx < count; idx++)
7923 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7924 pos += abc.abcA + abc.abcB + abc.abcC;
7925 dxs[idx] = pos;
7928 LeaveCriticalSection( &freetype_cs );
7929 return TRUE;
7932 /*************************************************************
7933 * freetype_GetTextExtentExPointI
7935 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7937 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7938 INT idx, pos;
7939 ABC abc;
7940 GLYPHMETRICS gm;
7941 struct freetype_physdev *physdev = get_freetype_dev( dev );
7943 if (!physdev->font)
7945 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7946 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7949 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7951 GDI_CheckNotLock();
7952 EnterCriticalSection( &freetype_cs );
7954 for (idx = pos = 0; idx < count; idx++)
7956 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7957 &gm, &abc, 0, NULL, &identity );
7958 pos += abc.abcA + abc.abcB + abc.abcC;
7959 dxs[idx] = pos;
7962 LeaveCriticalSection( &freetype_cs );
7963 return TRUE;
7966 /*************************************************************
7967 * freetype_GetFontData
7969 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7971 struct freetype_physdev *physdev = get_freetype_dev( dev );
7973 if (!physdev->font)
7975 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7976 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7979 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7980 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7981 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7983 return get_font_data( physdev->font, table, offset, buf, cbData );
7986 /*************************************************************
7987 * freetype_GetTextFace
7989 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7991 INT n;
7992 struct freetype_physdev *physdev = get_freetype_dev( dev );
7994 if (!physdev->font)
7996 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7997 return dev->funcs->pGetTextFace( dev, count, str );
8000 n = strlenW(physdev->font->name) + 1;
8001 if (str)
8003 lstrcpynW(str, physdev->font->name, count);
8004 n = min(count, n);
8006 return n;
8009 /*************************************************************
8010 * freetype_GetTextCharsetInfo
8012 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
8014 struct freetype_physdev *physdev = get_freetype_dev( dev );
8016 if (!physdev->font)
8018 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
8019 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
8021 if (fs) *fs = physdev->font->fs;
8022 return physdev->font->charset;
8025 /* Retrieve a list of supported Unicode ranges for a given font.
8026 * Can be called with NULL gs to calculate the buffer size. Returns
8027 * the number of ranges found.
8029 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
8031 DWORD num_ranges = 0;
8033 if (face->charmap->encoding == FT_ENCODING_UNICODE)
8035 FT_UInt glyph_code;
8036 FT_ULong char_code, char_code_prev;
8038 glyph_code = 0;
8039 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
8041 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8042 face->num_glyphs, glyph_code, char_code);
8044 if (!glyph_code) return 0;
8046 if (gs)
8048 gs->ranges[0].wcLow = (USHORT)char_code;
8049 gs->ranges[0].cGlyphs = 0;
8050 gs->cGlyphsSupported = 0;
8053 num_ranges = 1;
8054 while (glyph_code)
8056 if (char_code < char_code_prev)
8058 ERR("expected increasing char code from FT_Get_Next_Char\n");
8059 return 0;
8061 if (char_code - char_code_prev > 1)
8063 num_ranges++;
8064 if (gs)
8066 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
8067 gs->ranges[num_ranges - 1].cGlyphs = 1;
8068 gs->cGlyphsSupported++;
8071 else if (gs)
8073 gs->ranges[num_ranges - 1].cGlyphs++;
8074 gs->cGlyphsSupported++;
8076 char_code_prev = char_code;
8077 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
8080 else
8081 FIXME("encoding %u not supported\n", face->charmap->encoding);
8083 return num_ranges;
8086 /*************************************************************
8087 * freetype_GetFontUnicodeRanges
8089 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
8091 struct freetype_physdev *physdev = get_freetype_dev( dev );
8092 DWORD size, num_ranges;
8094 if (!physdev->font)
8096 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
8097 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
8100 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
8101 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
8102 if (glyphset)
8104 glyphset->cbThis = size;
8105 glyphset->cRanges = num_ranges;
8106 glyphset->flAccel = 0;
8108 return size;
8111 /*************************************************************
8112 * freetype_FontIsLinked
8114 static BOOL freetype_FontIsLinked( PHYSDEV dev )
8116 struct freetype_physdev *physdev = get_freetype_dev( dev );
8117 BOOL ret;
8119 if (!physdev->font)
8121 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8122 return dev->funcs->pFontIsLinked( dev );
8125 GDI_CheckNotLock();
8126 EnterCriticalSection( &freetype_cs );
8127 ret = !list_empty(&physdev->font->child_fonts);
8128 LeaveCriticalSection( &freetype_cs );
8129 return ret;
8132 /*************************************************************************
8133 * GetRasterizerCaps (GDI32.@)
8135 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8137 lprs->nSize = sizeof(RASTERIZER_STATUS);
8138 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8139 lprs->nLanguageID = 0;
8140 return TRUE;
8143 /*************************************************************
8144 * freetype_GetFontRealizationInfo
8146 static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
8148 struct freetype_physdev *physdev = get_freetype_dev( dev );
8149 struct font_realization_info *info = ptr;
8151 if (!physdev->font)
8153 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
8154 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
8157 FIXME("(%p, %p): stub!\n", physdev->font, info);
8159 info->flags = 1;
8160 if(FT_IS_SCALABLE(physdev->font->ft_face))
8161 info->flags |= 2;
8163 info->cache_num = physdev->font->cache_num;
8164 info->instance_id = -1;
8165 if (info->size == sizeof(*info))
8167 info->unk = 0;
8168 info->face_index = physdev->font->ft_face->face_index;
8171 return TRUE;
8174 /*************************************************************************
8175 * Kerning support for TrueType fonts
8177 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8179 struct TT_kern_table
8181 USHORT version;
8182 USHORT nTables;
8185 struct TT_kern_subtable
8187 USHORT version;
8188 USHORT length;
8189 union
8191 USHORT word;
8192 struct
8194 USHORT horizontal : 1;
8195 USHORT minimum : 1;
8196 USHORT cross_stream: 1;
8197 USHORT override : 1;
8198 USHORT reserved1 : 4;
8199 USHORT format : 8;
8200 } bits;
8201 } coverage;
8204 struct TT_format0_kern_subtable
8206 USHORT nPairs;
8207 USHORT searchRange;
8208 USHORT entrySelector;
8209 USHORT rangeShift;
8212 struct TT_kern_pair
8214 USHORT left;
8215 USHORT right;
8216 short value;
8219 static DWORD parse_format0_kern_subtable(GdiFont *font,
8220 const struct TT_format0_kern_subtable *tt_f0_ks,
8221 const USHORT *glyph_to_char,
8222 KERNINGPAIR *kern_pair, DWORD cPairs)
8224 USHORT i, nPairs;
8225 const struct TT_kern_pair *tt_kern_pair;
8227 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8229 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8231 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8232 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8233 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8235 if (!kern_pair || !cPairs)
8236 return nPairs;
8238 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8240 nPairs = min(nPairs, cPairs);
8242 for (i = 0; i < nPairs; i++)
8244 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8245 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8246 /* this algorithm appears to better match what Windows does */
8247 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8248 if (kern_pair->iKernAmount < 0)
8250 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8251 kern_pair->iKernAmount -= font->ppem;
8253 else if (kern_pair->iKernAmount > 0)
8255 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8256 kern_pair->iKernAmount += font->ppem;
8258 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8260 TRACE("left %u right %u value %d\n",
8261 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8263 kern_pair++;
8265 TRACE("copied %u entries\n", nPairs);
8266 return nPairs;
8269 /*************************************************************
8270 * freetype_GetKerningPairs
8272 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8274 DWORD length;
8275 void *buf;
8276 const struct TT_kern_table *tt_kern_table;
8277 const struct TT_kern_subtable *tt_kern_subtable;
8278 USHORT i, nTables;
8279 USHORT *glyph_to_char;
8280 GdiFont *font;
8281 struct freetype_physdev *physdev = get_freetype_dev( dev );
8283 if (!(font = physdev->font))
8285 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8286 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8289 GDI_CheckNotLock();
8290 EnterCriticalSection( &freetype_cs );
8291 if (font->total_kern_pairs != (DWORD)-1)
8293 if (cPairs && kern_pair)
8295 cPairs = min(cPairs, font->total_kern_pairs);
8296 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8298 else cPairs = font->total_kern_pairs;
8300 LeaveCriticalSection( &freetype_cs );
8301 return cPairs;
8304 font->total_kern_pairs = 0;
8306 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8308 if (length == GDI_ERROR)
8310 TRACE("no kerning data in the font\n");
8311 LeaveCriticalSection( &freetype_cs );
8312 return 0;
8315 buf = HeapAlloc(GetProcessHeap(), 0, length);
8316 if (!buf)
8318 WARN("Out of memory\n");
8319 LeaveCriticalSection( &freetype_cs );
8320 return 0;
8323 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8325 /* build a glyph index to char code map */
8326 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8327 if (!glyph_to_char)
8329 WARN("Out of memory allocating a glyph index to char code map\n");
8330 HeapFree(GetProcessHeap(), 0, buf);
8331 LeaveCriticalSection( &freetype_cs );
8332 return 0;
8335 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8337 FT_UInt glyph_code;
8338 FT_ULong char_code;
8340 glyph_code = 0;
8341 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8343 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8344 font->ft_face->num_glyphs, glyph_code, char_code);
8346 while (glyph_code)
8348 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8350 /* FIXME: This doesn't match what Windows does: it does some fancy
8351 * things with duplicate glyph index to char code mappings, while
8352 * we just avoid overriding existing entries.
8354 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8355 glyph_to_char[glyph_code] = (USHORT)char_code;
8357 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8360 else
8362 ULONG n;
8364 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
8365 for (n = 0; n <= 65535; n++)
8366 glyph_to_char[n] = (USHORT)n;
8369 tt_kern_table = buf;
8370 nTables = GET_BE_WORD(tt_kern_table->nTables);
8371 TRACE("version %u, nTables %u\n",
8372 GET_BE_WORD(tt_kern_table->version), nTables);
8374 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8376 for (i = 0; i < nTables; i++)
8378 struct TT_kern_subtable tt_kern_subtable_copy;
8380 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8381 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8382 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8384 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8385 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8386 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8388 /* According to the TrueType specification this is the only format
8389 * that will be properly interpreted by Windows and OS/2
8391 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8393 DWORD new_chunk, old_total = font->total_kern_pairs;
8395 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8396 glyph_to_char, NULL, 0);
8397 font->total_kern_pairs += new_chunk;
8399 if (!font->kern_pairs)
8400 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8401 font->total_kern_pairs * sizeof(*font->kern_pairs));
8402 else
8403 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8404 font->total_kern_pairs * sizeof(*font->kern_pairs));
8406 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8407 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8409 else
8410 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8412 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8415 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8416 HeapFree(GetProcessHeap(), 0, buf);
8418 if (cPairs && kern_pair)
8420 cPairs = min(cPairs, font->total_kern_pairs);
8421 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8423 else cPairs = font->total_kern_pairs;
8425 LeaveCriticalSection( &freetype_cs );
8426 return cPairs;
8429 static const struct gdi_dc_funcs freetype_funcs =
8431 NULL, /* pAbortDoc */
8432 NULL, /* pAbortPath */
8433 NULL, /* pAlphaBlend */
8434 NULL, /* pAngleArc */
8435 NULL, /* pArc */
8436 NULL, /* pArcTo */
8437 NULL, /* pBeginPath */
8438 NULL, /* pBlendImage */
8439 NULL, /* pChord */
8440 NULL, /* pCloseFigure */
8441 NULL, /* pCreateCompatibleDC */
8442 freetype_CreateDC, /* pCreateDC */
8443 freetype_DeleteDC, /* pDeleteDC */
8444 NULL, /* pDeleteObject */
8445 NULL, /* pDeviceCapabilities */
8446 NULL, /* pEllipse */
8447 NULL, /* pEndDoc */
8448 NULL, /* pEndPage */
8449 NULL, /* pEndPath */
8450 freetype_EnumFonts, /* pEnumFonts */
8451 NULL, /* pEnumICMProfiles */
8452 NULL, /* pExcludeClipRect */
8453 NULL, /* pExtDeviceMode */
8454 NULL, /* pExtEscape */
8455 NULL, /* pExtFloodFill */
8456 NULL, /* pExtSelectClipRgn */
8457 NULL, /* pExtTextOut */
8458 NULL, /* pFillPath */
8459 NULL, /* pFillRgn */
8460 NULL, /* pFlattenPath */
8461 freetype_FontIsLinked, /* pFontIsLinked */
8462 NULL, /* pFrameRgn */
8463 NULL, /* pGdiComment */
8464 NULL, /* pGetBoundsRect */
8465 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8466 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8467 freetype_GetCharWidth, /* pGetCharWidth */
8468 NULL, /* pGetDeviceCaps */
8469 NULL, /* pGetDeviceGammaRamp */
8470 freetype_GetFontData, /* pGetFontData */
8471 freetype_GetFontRealizationInfo, /* pGetFontRealizationInfo */
8472 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8473 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8474 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8475 NULL, /* pGetICMProfile */
8476 NULL, /* pGetImage */
8477 freetype_GetKerningPairs, /* pGetKerningPairs */
8478 NULL, /* pGetNearestColor */
8479 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8480 NULL, /* pGetPixel */
8481 NULL, /* pGetSystemPaletteEntries */
8482 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8483 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8484 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8485 freetype_GetTextFace, /* pGetTextFace */
8486 freetype_GetTextMetrics, /* pGetTextMetrics */
8487 NULL, /* pGradientFill */
8488 NULL, /* pIntersectClipRect */
8489 NULL, /* pInvertRgn */
8490 NULL, /* pLineTo */
8491 NULL, /* pModifyWorldTransform */
8492 NULL, /* pMoveTo */
8493 NULL, /* pOffsetClipRgn */
8494 NULL, /* pOffsetViewportOrg */
8495 NULL, /* pOffsetWindowOrg */
8496 NULL, /* pPaintRgn */
8497 NULL, /* pPatBlt */
8498 NULL, /* pPie */
8499 NULL, /* pPolyBezier */
8500 NULL, /* pPolyBezierTo */
8501 NULL, /* pPolyDraw */
8502 NULL, /* pPolyPolygon */
8503 NULL, /* pPolyPolyline */
8504 NULL, /* pPolygon */
8505 NULL, /* pPolyline */
8506 NULL, /* pPolylineTo */
8507 NULL, /* pPutImage */
8508 NULL, /* pRealizeDefaultPalette */
8509 NULL, /* pRealizePalette */
8510 NULL, /* pRectangle */
8511 NULL, /* pResetDC */
8512 NULL, /* pRestoreDC */
8513 NULL, /* pRoundRect */
8514 NULL, /* pSaveDC */
8515 NULL, /* pScaleViewportExt */
8516 NULL, /* pScaleWindowExt */
8517 NULL, /* pSelectBitmap */
8518 NULL, /* pSelectBrush */
8519 NULL, /* pSelectClipPath */
8520 freetype_SelectFont, /* pSelectFont */
8521 NULL, /* pSelectPalette */
8522 NULL, /* pSelectPen */
8523 NULL, /* pSetArcDirection */
8524 NULL, /* pSetBkColor */
8525 NULL, /* pSetBkMode */
8526 NULL, /* pSetDCBrushColor */
8527 NULL, /* pSetDCPenColor */
8528 NULL, /* pSetDIBColorTable */
8529 NULL, /* pSetDIBitsToDevice */
8530 NULL, /* pSetDeviceClipping */
8531 NULL, /* pSetDeviceGammaRamp */
8532 NULL, /* pSetLayout */
8533 NULL, /* pSetMapMode */
8534 NULL, /* pSetMapperFlags */
8535 NULL, /* pSetPixel */
8536 NULL, /* pSetPolyFillMode */
8537 NULL, /* pSetROP2 */
8538 NULL, /* pSetRelAbs */
8539 NULL, /* pSetStretchBltMode */
8540 NULL, /* pSetTextAlign */
8541 NULL, /* pSetTextCharacterExtra */
8542 NULL, /* pSetTextColor */
8543 NULL, /* pSetTextJustification */
8544 NULL, /* pSetViewportExt */
8545 NULL, /* pSetViewportOrg */
8546 NULL, /* pSetWindowExt */
8547 NULL, /* pSetWindowOrg */
8548 NULL, /* pSetWorldTransform */
8549 NULL, /* pStartDoc */
8550 NULL, /* pStartPage */
8551 NULL, /* pStretchBlt */
8552 NULL, /* pStretchDIBits */
8553 NULL, /* pStrokeAndFillPath */
8554 NULL, /* pStrokePath */
8555 NULL, /* pUnrealizePalette */
8556 NULL, /* pWidenPath */
8557 NULL, /* wine_get_wgl_driver */
8558 GDI_PRIORITY_FONT_DRV /* priority */
8561 #else /* HAVE_FREETYPE */
8563 /*************************************************************************/
8565 BOOL WineEngInit(void)
8567 return FALSE;
8570 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8572 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8573 return 1;
8576 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8578 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8579 return TRUE;
8582 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8584 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8585 return NULL;
8588 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8589 LPCWSTR font_file, LPCWSTR font_path )
8591 FIXME("stub\n");
8592 return FALSE;
8595 /*************************************************************************
8596 * GetRasterizerCaps (GDI32.@)
8598 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8600 lprs->nSize = sizeof(RASTERIZER_STATUS);
8601 lprs->wFlags = 0;
8602 lprs->nLanguageID = 0;
8603 return TRUE;
8606 #endif /* HAVE_FREETYPE */