msvcp: Add a macro to access the locale field of I/O streams.
[wine.git] / dlls / gdi32 / freetype.c
blobfc19f5110ab791c9e137476ca1be9e1838b65cd7
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_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1516 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1519 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1521 DWORD needed, strike_index = 0;
1522 HKEY hkey_strike;
1524 /* If we have a File Name key then this is a real font, not just the parent
1525 key of a bunch of non-scalable strikes */
1526 needed = buffer_size;
1527 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1529 Face *face;
1530 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1531 face->cached_enum_data = NULL;
1532 face->family = NULL;
1534 face->refcount = 1;
1535 face->file = strdupW( buffer );
1536 face->StyleName = strdupW(face_name);
1538 needed = buffer_size;
1539 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1540 face->FullName = strdupW( buffer );
1541 else
1542 face->FullName = NULL;
1544 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1545 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1546 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1547 reg_load_dword(hkey_face, face_flags_value, (DWORD*)&face->flags);
1549 needed = sizeof(face->fs);
1550 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1552 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1554 face->scalable = TRUE;
1555 memset(&face->size, 0, sizeof(face->size));
1557 else
1559 face->scalable = FALSE;
1560 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1561 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1562 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1563 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1564 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1566 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1567 face->size.height, face->size.width, face->size.size >> 6,
1568 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1571 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1572 face->fs.fsCsb[0], face->fs.fsCsb[1],
1573 face->fs.fsUsb[0], face->fs.fsUsb[1],
1574 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1576 if (insert_face_in_family_list(face, family))
1577 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1579 release_face( face );
1582 /* load bitmap strikes */
1584 needed = buffer_size;
1585 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1587 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1589 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1590 RegCloseKey(hkey_strike);
1592 needed = buffer_size;
1596 /* move vertical fonts after their horizontal counterpart */
1597 /* assumes that font_list is already sorted by family name */
1598 static void reorder_vertical_fonts(void)
1600 Family *family, *next, *vert_family;
1601 struct list *ptr, *vptr;
1602 struct list vertical_families = LIST_INIT( vertical_families );
1604 LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
1606 if (family->FamilyName[0] != '@') continue;
1607 list_remove( &family->entry );
1608 list_add_tail( &vertical_families, &family->entry );
1611 ptr = list_head( &font_list );
1612 vptr = list_head( &vertical_families );
1613 while (ptr && vptr)
1615 family = LIST_ENTRY( ptr, Family, entry );
1616 vert_family = LIST_ENTRY( vptr, Family, entry );
1617 if (strcmpiW( family->FamilyName, vert_family->FamilyName + 1 ) > 0)
1619 list_remove( vptr );
1620 list_add_before( ptr, vptr );
1621 vptr = list_head( &vertical_families );
1623 else ptr = list_next( &font_list, ptr );
1625 list_move_tail( &font_list, &vertical_families );
1628 static void load_font_list_from_cache(HKEY hkey_font_cache)
1630 DWORD size, family_index = 0;
1631 Family *family;
1632 HKEY hkey_family;
1633 WCHAR buffer[4096];
1635 size = sizeof(buffer);
1636 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1638 WCHAR *english_family = NULL;
1639 WCHAR *family_name = strdupW( buffer );
1640 DWORD face_index = 0;
1642 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1643 TRACE("opened family key %s\n", debugstr_w(family_name));
1644 size = sizeof(buffer);
1645 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1646 english_family = strdupW( buffer );
1648 family = create_family(family_name, english_family);
1650 if(english_family)
1652 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1653 subst->from.name = strdupW(english_family);
1654 subst->from.charset = -1;
1655 subst->to.name = strdupW(family_name);
1656 subst->to.charset = -1;
1657 add_font_subst(&font_subst_list, subst, 0);
1660 size = sizeof(buffer);
1661 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1663 WCHAR *face_name = strdupW( buffer );
1664 HKEY hkey_face;
1666 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1668 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1669 RegCloseKey(hkey_face);
1671 HeapFree( GetProcessHeap(), 0, face_name );
1672 size = sizeof(buffer);
1674 RegCloseKey(hkey_family);
1675 release_family( family );
1676 size = sizeof(buffer);
1679 reorder_vertical_fonts();
1682 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1684 LONG ret;
1685 HKEY hkey_wine_fonts;
1687 /* We don't want to create the fonts key as volatile, so open this first */
1688 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1689 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1690 if(ret != ERROR_SUCCESS)
1692 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1693 return ret;
1696 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1697 KEY_ALL_ACCESS, NULL, hkey, disposition);
1698 RegCloseKey(hkey_wine_fonts);
1699 return ret;
1702 static void add_face_to_cache(Face *face)
1704 HKEY hkey_family, hkey_face;
1705 WCHAR *face_key_name;
1707 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1708 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1709 if(face->family->EnglishName)
1710 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1711 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1713 if(face->scalable)
1714 face_key_name = face->StyleName;
1715 else
1717 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1718 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1719 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1721 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1722 &hkey_face, NULL);
1723 if(!face->scalable)
1724 HeapFree(GetProcessHeap(), 0, face_key_name);
1726 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1727 (strlenW(face->file) + 1) * sizeof(WCHAR));
1728 if (face->FullName)
1729 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1730 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1732 reg_save_dword(hkey_face, face_index_value, face->face_index);
1733 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1734 reg_save_dword(hkey_face, face_version_value, face->font_version);
1735 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1737 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1739 if(!face->scalable)
1741 reg_save_dword(hkey_face, face_height_value, face->size.height);
1742 reg_save_dword(hkey_face, face_width_value, face->size.width);
1743 reg_save_dword(hkey_face, face_size_value, face->size.size);
1744 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1745 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1746 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1748 RegCloseKey(hkey_face);
1749 RegCloseKey(hkey_family);
1752 static void remove_face_from_cache( Face *face )
1754 HKEY hkey_family;
1756 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1758 if (face->scalable)
1760 RegDeleteKeyW( hkey_family, face->StyleName );
1762 else
1764 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1765 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1766 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1767 RegDeleteKeyW( hkey_family, face_key_name );
1768 HeapFree(GetProcessHeap(), 0, face_key_name);
1770 RegCloseKey(hkey_family);
1773 static WCHAR *prepend_at(WCHAR *family)
1775 WCHAR *str;
1777 if (!family)
1778 return NULL;
1780 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1781 str[0] = '@';
1782 strcpyW(str + 1, family);
1783 HeapFree(GetProcessHeap(), 0, family);
1784 return str;
1787 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1789 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) );
1790 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1792 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1793 if (!*name)
1795 *name = *english;
1796 *english = NULL;
1798 else if (!strcmpiW( *name, *english ))
1800 HeapFree( GetProcessHeap(), 0, *english );
1801 *english = NULL;
1804 if (vertical)
1806 *name = prepend_at( *name );
1807 *english = prepend_at( *english );
1811 static Family *get_family( FT_Face ft_face, BOOL vertical )
1813 Family *family;
1814 WCHAR *name, *english_name;
1816 get_family_names( ft_face, &name, &english_name, vertical );
1818 family = find_family_from_name( name );
1820 if (!family)
1822 family = create_family( name, english_name );
1823 if (english_name)
1825 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1826 subst->from.name = strdupW( english_name );
1827 subst->from.charset = -1;
1828 subst->to.name = strdupW( name );
1829 subst->to.charset = -1;
1830 add_font_subst( &font_subst_list, subst, 0 );
1833 else
1835 HeapFree( GetProcessHeap(), 0, name );
1836 HeapFree( GetProcessHeap(), 0, english_name );
1837 family->refcount++;
1840 return family;
1843 static inline FT_Fixed get_font_version( FT_Face ft_face )
1845 FT_Fixed version = 0;
1846 TT_Header *header;
1848 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1849 if (header) version = header->Font_Revision;
1851 return version;
1854 static inline DWORD get_ntm_flags( FT_Face ft_face )
1856 DWORD flags = 0;
1857 FT_ULong table_size = 0;
1859 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1860 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1861 if (flags == 0) flags = NTM_REGULAR;
1863 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1864 flags |= NTM_PS_OPENTYPE;
1866 return flags;
1869 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1871 My_FT_Bitmap_Size *size;
1872 FT_WinFNT_HeaderRec winfnt_header;
1874 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1875 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1876 size->height, size->width, size->size >> 6,
1877 size->x_ppem >> 6, size->y_ppem >> 6);
1878 face_size->height = size->height;
1879 face_size->width = size->width;
1880 face_size->size = size->size;
1881 face_size->x_ppem = size->x_ppem;
1882 face_size->y_ppem = size->y_ppem;
1884 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
1885 face_size->internal_leading = winfnt_header.internal_leading;
1886 if (winfnt_header.external_leading > 0 &&
1887 (face_size->height ==
1888 winfnt_header.pixel_height + winfnt_header.external_leading))
1889 face_size->height = winfnt_header.pixel_height;
1893 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1895 TT_OS2 *os2;
1896 FT_UInt dummy;
1897 CHARSETINFO csi;
1898 FT_WinFNT_HeaderRec winfnt_header;
1899 int i;
1901 memset( fs, 0, sizeof(*fs) );
1903 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1904 if (os2)
1906 fs->fsUsb[0] = os2->ulUnicodeRange1;
1907 fs->fsUsb[1] = os2->ulUnicodeRange2;
1908 fs->fsUsb[2] = os2->ulUnicodeRange3;
1909 fs->fsUsb[3] = os2->ulUnicodeRange4;
1911 if (os2->version == 0)
1913 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1914 fs->fsCsb[0] = FS_LATIN1;
1915 else
1916 fs->fsCsb[0] = FS_SYMBOL;
1918 else
1920 fs->fsCsb[0] = os2->ulCodePageRange1;
1921 fs->fsCsb[1] = os2->ulCodePageRange2;
1924 else
1926 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1928 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1929 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1930 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1931 *fs = csi.fs;
1935 if (fs->fsCsb[0] == 0)
1937 /* let's see if we can find any interesting cmaps */
1938 for (i = 0; i < ft_face->num_charmaps; i++)
1940 switch (ft_face->charmaps[i]->encoding)
1942 case FT_ENCODING_UNICODE:
1943 case FT_ENCODING_APPLE_ROMAN:
1944 fs->fsCsb[0] |= FS_LATIN1;
1945 break;
1946 case FT_ENCODING_MS_SYMBOL:
1947 fs->fsCsb[0] |= FS_SYMBOL;
1948 break;
1949 default:
1950 break;
1956 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1957 DWORD flags )
1959 struct stat st;
1960 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1962 face->refcount = 1;
1963 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1964 if (!face->StyleName) face->StyleName = towstr( CP_ACP, ft_face->style_name );
1966 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1967 if (flags & ADDFONT_VERTICAL_FONT)
1968 face->FullName = prepend_at( face->FullName );
1970 face->dev = 0;
1971 face->ino = 0;
1972 if (file)
1974 face->file = towstr( CP_UNIXCP, file );
1975 face->font_data_ptr = NULL;
1976 face->font_data_size = 0;
1977 if (!stat( file, &st ))
1979 face->dev = st.st_dev;
1980 face->ino = st.st_ino;
1983 else
1985 face->file = NULL;
1986 face->font_data_ptr = font_data_ptr;
1987 face->font_data_size = font_data_size;
1990 face->face_index = face_index;
1991 get_fontsig( ft_face, &face->fs );
1992 face->ntmFlags = get_ntm_flags( ft_face );
1993 face->font_version = get_font_version( ft_face );
1995 if (FT_IS_SCALABLE( ft_face ))
1997 memset( &face->size, 0, sizeof(face->size) );
1998 face->scalable = TRUE;
2000 else
2002 get_bitmap_size( ft_face, &face->size );
2003 face->scalable = FALSE;
2006 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
2007 face->flags = flags;
2008 face->family = NULL;
2009 face->cached_enum_data = NULL;
2011 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2012 face->fs.fsCsb[0], face->fs.fsCsb[1],
2013 face->fs.fsUsb[0], face->fs.fsUsb[1],
2014 face->fs.fsUsb[2], face->fs.fsUsb[3]);
2016 return face;
2019 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
2020 FT_Long face_index, DWORD flags )
2022 Face *face;
2023 Family *family;
2025 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
2026 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
2027 if (strlenW(family->FamilyName) >= LF_FACESIZE)
2029 WARN("Ignoring %s because name is too long\n", debugstr_w(family->FamilyName));
2030 release_face( face );
2031 release_family( family );
2032 return;
2035 if (insert_face_in_family_list( face, family ))
2037 if (flags & ADDFONT_ADD_TO_CACHE)
2038 add_face_to_cache( face );
2040 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
2041 debugstr_w(face->StyleName));
2043 release_face( face );
2044 release_family( family );
2047 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
2048 FT_Long face_index, BOOL allow_bitmap )
2050 FT_Error err;
2051 TT_OS2 *pOS2;
2052 FT_Face ft_face;
2054 if (file)
2056 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2057 err = pFT_New_Face(library, file, face_index, &ft_face);
2059 else
2061 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2062 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2065 if (err != 0)
2067 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2068 return NULL;
2071 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2072 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
2074 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2075 goto fail;
2078 if (!FT_IS_SFNT( ft_face ))
2080 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2082 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2083 goto fail;
2086 else
2088 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2089 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2090 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2092 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2093 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2094 goto fail;
2097 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2098 we don't want to load these. */
2099 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2101 FT_ULong len = 0;
2103 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2105 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2106 goto fail;
2111 if (!ft_face->family_name || !ft_face->style_name)
2113 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2114 goto fail;
2117 return ft_face;
2118 fail:
2119 pFT_Done_Face( ft_face );
2120 return NULL;
2123 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
2125 FT_Face ft_face;
2126 FT_Long face_index = 0, num_faces;
2127 INT ret = 0;
2129 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2130 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
2132 #ifdef HAVE_CARBON_CARBON_H
2133 if(file)
2135 char **mac_list = expand_mac_font(file);
2136 if(mac_list)
2138 BOOL had_one = FALSE;
2139 char **cursor;
2140 for(cursor = mac_list; *cursor; cursor++)
2142 had_one = TRUE;
2143 AddFontToList(*cursor, NULL, 0, flags);
2144 HeapFree(GetProcessHeap(), 0, *cursor);
2146 HeapFree(GetProcessHeap(), 0, mac_list);
2147 if(had_one)
2148 return 1;
2151 #endif /* HAVE_CARBON_CARBON_H */
2153 do {
2154 const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
2155 FONTSIGNATURE fs;
2157 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2158 if (!ft_face) return 0;
2160 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2162 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
2163 pFT_Done_Face(ft_face);
2164 return 0;
2167 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
2168 ++ret;
2170 get_fontsig(ft_face, &fs);
2171 if (fs.fsCsb[0] & FS_DBCS_MASK)
2173 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
2174 flags | ADDFONT_VERTICAL_FONT);
2175 ++ret;
2178 num_faces = ft_face->num_faces;
2179 pFT_Done_Face(ft_face);
2180 } while(num_faces > ++face_index);
2181 return ret;
2184 static int remove_font_resource( const char *file, DWORD flags )
2186 Family *family, *family_next;
2187 Face *face, *face_next;
2188 struct stat st;
2189 int count = 0;
2191 if (stat( file, &st ) == -1) return 0;
2192 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2194 family->refcount++;
2195 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2197 if (!face->file) continue;
2198 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2199 if (st.st_dev == face->dev && st.st_ino == face->ino)
2201 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2202 release_face( face );
2203 count++;
2206 release_family( family );
2208 return count;
2211 static void DumpFontList(void)
2213 Family *family;
2214 Face *face;
2216 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2217 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2218 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2219 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2220 if(!face->scalable)
2221 TRACE(" %d", face->size.height);
2222 TRACE("\n");
2227 /***********************************************************
2228 * The replacement list is a way to map an entire font
2229 * family onto another family. For example adding
2231 * [HKCU\Software\Wine\Fonts\Replacements]
2232 * "Wingdings"="Winedings"
2234 * would enumerate the Winedings font both as Winedings and
2235 * Wingdings. However if a real Wingdings font is present the
2236 * replacement does not take place.
2239 static void LoadReplaceList(void)
2241 HKEY hkey;
2242 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2243 LPWSTR value;
2244 LPVOID data;
2246 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2247 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2249 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2250 &valuelen, &datalen, NULL, NULL);
2252 valuelen++; /* returned value doesn't include room for '\0' */
2253 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2254 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2256 dlen = datalen;
2257 vlen = valuelen;
2258 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2259 &dlen) == ERROR_SUCCESS) {
2260 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2261 /* "NewName"="Oldname" */
2262 if(!find_family_from_any_name(value))
2264 Family * const family = find_family_from_any_name(data);
2265 if (family != NULL)
2267 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2268 if (new_family != NULL)
2270 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2271 new_family->FamilyName = strdupW(value);
2272 new_family->EnglishName = NULL;
2273 list_init(&new_family->faces);
2274 new_family->replacement = &family->faces;
2275 list_add_tail(&font_list, &new_family->entry);
2278 else
2280 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2283 else
2285 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2287 /* reset dlen and vlen */
2288 dlen = datalen;
2289 vlen = valuelen;
2291 HeapFree(GetProcessHeap(), 0, data);
2292 HeapFree(GetProcessHeap(), 0, value);
2293 RegCloseKey(hkey);
2297 static const WCHAR *font_links_list[] =
2299 Lucida_Sans_Unicode,
2300 Microsoft_Sans_Serif,
2301 Tahoma
2304 static const struct font_links_defaults_list
2306 /* Keyed off substitution for "MS Shell Dlg" */
2307 const WCHAR *shelldlg;
2308 /* Maximum of four substitutes, plus terminating NULL pointer */
2309 const WCHAR *substitutes[5];
2310 } font_links_defaults_list[] =
2312 /* Non East-Asian */
2313 { Tahoma, /* FIXME unverified ordering */
2314 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2316 /* Below lists are courtesy of
2317 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2319 /* Japanese */
2320 { MS_UI_Gothic,
2321 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2323 /* Chinese Simplified */
2324 { SimSun,
2325 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2327 /* Korean */
2328 { Gulim,
2329 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2331 /* Chinese Traditional */
2332 { PMingLiU,
2333 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2338 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2340 SYSTEM_LINKS *font_link;
2342 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2344 if(!strcmpiW(font_link->font_name, name))
2345 return font_link;
2348 return NULL;
2351 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2353 const WCHAR *value;
2354 int i;
2355 FontSubst *psub;
2356 Family *family;
2357 Face *face;
2358 const WCHAR *file;
2360 if (values)
2362 SYSTEM_LINKS *font_link;
2364 psub = get_font_subst(&font_subst_list, name, -1);
2365 /* Don't store fonts that are only substitutes for other fonts */
2366 if(psub)
2368 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2369 return;
2372 font_link = find_font_link(name);
2373 if (font_link == NULL)
2375 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2376 font_link->font_name = strdupW(name);
2377 list_init(&font_link->links);
2378 list_add_tail(&system_links, &font_link->entry);
2381 memset(&font_link->fs, 0, sizeof font_link->fs);
2382 for (i = 0; values[i] != NULL; i++)
2384 const struct list *face_list;
2385 CHILD_FONT *child_font;
2387 value = values[i];
2388 if (!strcmpiW(name,value))
2389 continue;
2390 psub = get_font_subst(&font_subst_list, value, -1);
2391 if(psub)
2392 value = psub->to.name;
2393 family = find_family_from_name(value);
2394 if (!family)
2395 continue;
2396 file = NULL;
2397 /* Use first extant filename for this Family */
2398 face_list = get_face_list_from_family(family);
2399 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2401 if (!face->file)
2402 continue;
2403 file = strrchrW(face->file, '/');
2404 if (!file)
2405 file = face->file;
2406 else
2407 file++;
2408 break;
2410 if (!file)
2411 continue;
2412 face = find_face_from_filename(file, value);
2413 if(!face)
2415 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2416 continue;
2419 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2420 child_font->face = face;
2421 child_font->font = NULL;
2422 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2423 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2424 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2425 child_font->face->face_index);
2426 list_add_tail(&font_link->links, &child_font->entry);
2428 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2434 /*************************************************************
2435 * init_system_links
2437 static BOOL init_system_links(void)
2439 HKEY hkey;
2440 BOOL ret = FALSE;
2441 DWORD type, max_val, max_data, val_len, data_len, index;
2442 WCHAR *value, *data;
2443 WCHAR *entry, *next;
2444 SYSTEM_LINKS *font_link, *system_font_link;
2445 CHILD_FONT *child_font;
2446 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2447 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2448 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2449 Face *face;
2450 FontSubst *psub;
2451 UINT i, j;
2453 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2455 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2456 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2457 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2458 val_len = max_val + 1;
2459 data_len = max_data;
2460 index = 0;
2461 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2463 psub = get_font_subst(&font_subst_list, value, -1);
2464 /* Don't store fonts that are only substitutes for other fonts */
2465 if(psub)
2467 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2468 goto next;
2470 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2471 font_link->font_name = strdupW(value);
2472 memset(&font_link->fs, 0, sizeof font_link->fs);
2473 list_init(&font_link->links);
2474 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2476 WCHAR *face_name;
2477 CHILD_FONT *child_font;
2479 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2481 next = entry + strlenW(entry) + 1;
2483 face_name = strchrW(entry, ',');
2484 if(face_name)
2486 *face_name++ = 0;
2487 while(isspaceW(*face_name))
2488 face_name++;
2490 psub = get_font_subst(&font_subst_list, face_name, -1);
2491 if(psub)
2492 face_name = psub->to.name;
2494 face = find_face_from_filename(entry, face_name);
2495 if(!face)
2497 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2498 continue;
2501 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2502 child_font->face = face;
2503 child_font->font = NULL;
2504 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2505 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2506 TRACE("Adding file %s index %ld\n",
2507 debugstr_w(child_font->face->file), child_font->face->face_index);
2508 list_add_tail(&font_link->links, &child_font->entry);
2510 list_add_tail(&system_links, &font_link->entry);
2511 next:
2512 val_len = max_val + 1;
2513 data_len = max_data;
2516 HeapFree(GetProcessHeap(), 0, value);
2517 HeapFree(GetProcessHeap(), 0, data);
2518 RegCloseKey(hkey);
2522 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2523 if (!psub) {
2524 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2525 goto skip_internal;
2528 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2530 const FontSubst *psub2;
2531 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2533 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2535 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2536 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2538 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2539 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2541 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2543 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2547 skip_internal:
2549 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2550 that Tahoma has */
2552 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2553 system_font_link->font_name = strdupW(System);
2554 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2555 list_init(&system_font_link->links);
2557 face = find_face_from_filename(tahoma_ttf, Tahoma);
2558 if(face)
2560 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2561 child_font->face = face;
2562 child_font->font = NULL;
2563 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2564 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2565 TRACE("Found Tahoma in %s index %ld\n",
2566 debugstr_w(child_font->face->file), child_font->face->face_index);
2567 list_add_tail(&system_font_link->links, &child_font->entry);
2569 font_link = find_font_link(Tahoma);
2570 if (font_link != NULL)
2572 CHILD_FONT *font_link_entry;
2573 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2575 CHILD_FONT *new_child;
2576 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2577 new_child->face = font_link_entry->face;
2578 new_child->font = NULL;
2579 new_child->face->refcount++;
2580 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2581 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2582 list_add_tail(&system_font_link->links, &new_child->entry);
2585 list_add_tail(&system_links, &system_font_link->entry);
2586 return ret;
2589 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2591 DIR *dir;
2592 struct dirent *dent;
2593 char path[MAX_PATH];
2595 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2597 dir = opendir(dirname);
2598 if(!dir) {
2599 WARN("Can't open directory %s\n", debugstr_a(dirname));
2600 return FALSE;
2602 while((dent = readdir(dir)) != NULL) {
2603 struct stat statbuf;
2605 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2606 continue;
2608 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2610 sprintf(path, "%s/%s", dirname, dent->d_name);
2612 if(stat(path, &statbuf) == -1)
2614 WARN("Can't stat %s\n", debugstr_a(path));
2615 continue;
2617 if(S_ISDIR(statbuf.st_mode))
2618 ReadFontDir(path, external_fonts);
2619 else
2621 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2622 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2623 AddFontToList(path, NULL, 0, addfont_flags);
2626 closedir(dir);
2627 return TRUE;
2630 #ifdef SONAME_LIBFONTCONFIG
2632 static BOOL fontconfig_enabled;
2634 static UINT parse_aa_pattern( FcPattern *pattern )
2636 FcBool antialias;
2637 int rgba;
2638 UINT aa_flags = 0;
2640 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2641 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2643 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2645 switch (rgba)
2647 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2648 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2649 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2650 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2651 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2654 return aa_flags;
2657 static void init_fontconfig(void)
2659 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2661 if (!fc_handle)
2663 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2664 return;
2667 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2668 LOAD_FUNCPTR(FcConfigSubstitute);
2669 LOAD_FUNCPTR(FcFontList);
2670 LOAD_FUNCPTR(FcFontSetDestroy);
2671 LOAD_FUNCPTR(FcInit);
2672 LOAD_FUNCPTR(FcObjectSetAdd);
2673 LOAD_FUNCPTR(FcObjectSetCreate);
2674 LOAD_FUNCPTR(FcObjectSetDestroy);
2675 LOAD_FUNCPTR(FcPatternCreate);
2676 LOAD_FUNCPTR(FcPatternDestroy);
2677 LOAD_FUNCPTR(FcPatternGetBool);
2678 LOAD_FUNCPTR(FcPatternGetInteger);
2679 LOAD_FUNCPTR(FcPatternGetString);
2680 #undef LOAD_FUNCPTR
2682 if (pFcInit())
2684 FcPattern *pattern = pFcPatternCreate();
2685 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2686 default_aa_flags = parse_aa_pattern( pattern );
2687 pFcPatternDestroy( pattern );
2688 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2689 fontconfig_enabled = TRUE;
2693 static void load_fontconfig_fonts(void)
2695 FcPattern *pat;
2696 FcObjectSet *os;
2697 FcFontSet *fontset;
2698 int i, len;
2699 char *file;
2700 const char *ext;
2702 if (!fontconfig_enabled) return;
2704 pat = pFcPatternCreate();
2705 os = pFcObjectSetCreate();
2706 pFcObjectSetAdd(os, FC_FILE);
2707 pFcObjectSetAdd(os, FC_SCALABLE);
2708 pFcObjectSetAdd(os, FC_ANTIALIAS);
2709 pFcObjectSetAdd(os, FC_RGBA);
2710 fontset = pFcFontList(NULL, pat, os);
2711 if(!fontset) return;
2712 for(i = 0; i < fontset->nfont; i++) {
2713 FcBool scalable;
2714 DWORD aa_flags;
2716 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2717 continue;
2719 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2721 /* We're just interested in OT/TT fonts for now, so this hack just
2722 picks up the scalable fonts without extensions .pf[ab] to save time
2723 loading every other font */
2725 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2727 TRACE("not scalable\n");
2728 continue;
2731 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2732 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2734 len = strlen( file );
2735 if(len < 4) continue;
2736 ext = &file[ len - 3 ];
2737 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2738 AddFontToList(file, NULL, 0,
2739 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2741 pFcFontSetDestroy(fontset);
2742 pFcObjectSetDestroy(os);
2743 pFcPatternDestroy(pat);
2746 #elif defined(HAVE_CARBON_CARBON_H)
2748 static void load_mac_font_callback(const void *value, void *context)
2750 CFStringRef pathStr = value;
2751 CFIndex len;
2752 char* path;
2754 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2755 path = HeapAlloc(GetProcessHeap(), 0, len);
2756 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2758 TRACE("font file %s\n", path);
2759 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2761 HeapFree(GetProcessHeap(), 0, path);
2764 static void load_mac_fonts(void)
2766 CFStringRef removeDupesKey;
2767 CFBooleanRef removeDupesValue;
2768 CFDictionaryRef options;
2769 CTFontCollectionRef col;
2770 CFArrayRef descs;
2771 CFMutableSetRef paths;
2772 CFIndex i;
2774 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2775 removeDupesValue = kCFBooleanTrue;
2776 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2777 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2778 col = CTFontCollectionCreateFromAvailableFonts(options);
2779 if (options) CFRelease(options);
2780 if (!col)
2782 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2783 return;
2786 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2787 CFRelease(col);
2788 if (!descs)
2790 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2791 return;
2794 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2795 if (!paths)
2797 WARN("CFSetCreateMutable failed\n");
2798 CFRelease(descs);
2799 return;
2802 for (i = 0; i < CFArrayGetCount(descs); i++)
2804 CTFontDescriptorRef desc;
2805 CTFontRef font;
2806 ATSFontRef atsFont;
2807 OSStatus status;
2808 FSRef fsref;
2809 CFURLRef url;
2810 CFStringRef ext;
2811 CFStringRef path;
2813 desc = CFArrayGetValueAtIndex(descs, i);
2815 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2816 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2817 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2818 if (!font) continue;
2820 atsFont = CTFontGetPlatformFont(font, NULL);
2821 if (!atsFont)
2823 CFRelease(font);
2824 continue;
2827 status = ATSFontGetFileReference(atsFont, &fsref);
2828 CFRelease(font);
2829 if (status != noErr) continue;
2831 url = CFURLCreateFromFSRef(NULL, &fsref);
2832 if (!url) continue;
2834 ext = CFURLCopyPathExtension(url);
2835 if (ext)
2837 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2838 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2839 CFRelease(ext);
2840 if (skip)
2842 CFRelease(url);
2843 continue;
2847 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2848 CFRelease(url);
2849 if (!path) continue;
2851 CFSetAddValue(paths, path);
2852 CFRelease(path);
2855 CFRelease(descs);
2857 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2858 CFRelease(paths);
2861 #endif
2863 static char *get_data_dir_path( LPCWSTR file )
2865 char *unix_name = NULL;
2866 const char *data_dir = wine_get_data_dir();
2868 if (!data_dir) data_dir = wine_get_build_dir();
2870 if (data_dir)
2872 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2874 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2875 strcpy(unix_name, data_dir);
2876 strcat(unix_name, "/fonts/");
2878 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2880 return unix_name;
2883 static BOOL load_font_from_data_dir(LPCWSTR file)
2885 BOOL ret = FALSE;
2886 char *unix_name = get_data_dir_path( file );
2888 if (unix_name)
2890 EnterCriticalSection( &freetype_cs );
2891 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2892 LeaveCriticalSection( &freetype_cs );
2893 HeapFree(GetProcessHeap(), 0, unix_name);
2895 return ret;
2898 static char *get_winfonts_dir_path(LPCWSTR file)
2900 static const WCHAR slashW[] = {'\\','\0'};
2901 WCHAR windowsdir[MAX_PATH];
2903 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2904 strcatW(windowsdir, fontsW);
2905 strcatW(windowsdir, slashW);
2906 strcatW(windowsdir, file);
2907 return wine_get_unix_file_name( windowsdir );
2910 static void load_system_fonts(void)
2912 HKEY hkey;
2913 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2914 const WCHAR * const *value;
2915 DWORD dlen, type;
2916 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2917 char *unixname;
2919 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2920 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2921 strcatW(windowsdir, fontsW);
2922 for(value = SystemFontValues; *value; value++) {
2923 dlen = sizeof(data);
2924 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2925 type == REG_SZ) {
2926 BOOL added = FALSE;
2928 sprintfW(pathW, fmtW, windowsdir, data);
2929 if((unixname = wine_get_unix_file_name(pathW))) {
2930 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2931 HeapFree(GetProcessHeap(), 0, unixname);
2933 if (!added)
2934 load_font_from_data_dir(data);
2937 RegCloseKey(hkey);
2941 /*************************************************************
2943 * This adds registry entries for any externally loaded fonts
2944 * (fonts from fontconfig or FontDirs). It also deletes entries
2945 * of no longer existing fonts.
2948 static void update_reg_entries(void)
2950 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2951 LPWSTR valueW;
2952 DWORD len;
2953 Family *family;
2954 Face *face;
2955 WCHAR *file, *path;
2956 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2958 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2959 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2960 ERR("Can't create Windows font reg key\n");
2961 goto end;
2964 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2965 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2966 ERR("Can't create Windows font reg key\n");
2967 goto end;
2970 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2971 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2972 ERR("Can't create external font reg key\n");
2973 goto end;
2976 /* enumerate the fonts and add external ones to the two keys */
2978 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2979 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2980 char *buffer;
2981 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
2983 if(face->FullName)
2985 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2986 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2987 strcpyW(valueW, face->FullName);
2989 else
2991 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2992 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2993 strcpyW(valueW, family->FamilyName);
2996 buffer = strWtoA( CP_UNIXCP, face->file );
2997 path = wine_get_dos_file_name( buffer );
2998 HeapFree( GetProcessHeap(), 0, buffer );
3000 if (path)
3001 file = path;
3002 else if ((file = strrchrW(face->file, '/')))
3003 file++;
3004 else
3005 file = face->file;
3007 len = strlenW(file) + 1;
3008 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3009 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3010 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3012 HeapFree(GetProcessHeap(), 0, path);
3013 HeapFree(GetProcessHeap(), 0, valueW);
3016 end:
3017 if(external_key) RegCloseKey(external_key);
3018 if(win9x_key) RegCloseKey(win9x_key);
3019 if(winnt_key) RegCloseKey(winnt_key);
3022 static void delete_external_font_keys(void)
3024 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3025 DWORD dlen, vlen, datalen, valuelen, i, type;
3026 LPWSTR valueW;
3027 LPVOID data;
3029 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3030 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3031 ERR("Can't create Windows font reg key\n");
3032 goto end;
3035 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3036 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3037 ERR("Can't create Windows font reg key\n");
3038 goto end;
3041 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3042 ERR("Can't create external font reg key\n");
3043 goto end;
3046 /* Delete all external fonts added last time */
3048 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3049 &valuelen, &datalen, NULL, NULL);
3050 valuelen++; /* returned value doesn't include room for '\0' */
3051 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3052 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3054 dlen = datalen * sizeof(WCHAR);
3055 vlen = valuelen;
3056 i = 0;
3057 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3058 &dlen) == ERROR_SUCCESS) {
3060 RegDeleteValueW(winnt_key, valueW);
3061 RegDeleteValueW(win9x_key, valueW);
3062 /* reset dlen and vlen */
3063 dlen = datalen;
3064 vlen = valuelen;
3066 HeapFree(GetProcessHeap(), 0, data);
3067 HeapFree(GetProcessHeap(), 0, valueW);
3069 /* Delete the old external fonts key */
3070 RegCloseKey(external_key);
3071 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3073 end:
3074 if(win9x_key) RegCloseKey(win9x_key);
3075 if(winnt_key) RegCloseKey(winnt_key);
3078 /*************************************************************
3079 * WineEngAddFontResourceEx
3082 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3084 INT ret = 0;
3086 GDI_CheckNotLock();
3088 if (ft_handle) /* do it only if we have freetype up and running */
3090 char *unixname;
3092 EnterCriticalSection( &freetype_cs );
3094 if((unixname = wine_get_unix_file_name(file)))
3096 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3098 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3099 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3100 HeapFree(GetProcessHeap(), 0, unixname);
3102 if (!ret && !strchrW(file, '\\')) {
3103 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3104 if ((unixname = get_winfonts_dir_path( file )))
3106 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3107 HeapFree(GetProcessHeap(), 0, unixname);
3109 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3110 if (!ret && (unixname = get_data_dir_path( file )))
3112 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3113 HeapFree(GetProcessHeap(), 0, unixname);
3117 LeaveCriticalSection( &freetype_cs );
3119 return ret;
3122 /*************************************************************
3123 * WineEngAddFontMemResourceEx
3126 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3128 GDI_CheckNotLock();
3130 if (ft_handle) /* do it only if we have freetype up and running */
3132 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3134 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3135 memcpy(pFontCopy, pbFont, cbFont);
3137 EnterCriticalSection( &freetype_cs );
3138 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3139 LeaveCriticalSection( &freetype_cs );
3141 if (*pcFonts == 0)
3143 TRACE("AddFontToList failed\n");
3144 HeapFree(GetProcessHeap(), 0, pFontCopy);
3145 return 0;
3147 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3148 * For now return something unique but quite random
3150 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3151 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3154 *pcFonts = 0;
3155 return 0;
3158 /*************************************************************
3159 * WineEngRemoveFontResourceEx
3162 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3164 INT ret = 0;
3166 GDI_CheckNotLock();
3168 if (ft_handle) /* do it only if we have freetype up and running */
3170 char *unixname;
3172 EnterCriticalSection( &freetype_cs );
3174 if ((unixname = wine_get_unix_file_name(file)))
3176 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3178 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3179 ret = remove_font_resource( unixname, addfont_flags );
3180 HeapFree(GetProcessHeap(), 0, unixname);
3182 if (!ret && !strchrW(file, '\\'))
3184 if ((unixname = get_winfonts_dir_path( file )))
3186 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3187 HeapFree(GetProcessHeap(), 0, unixname);
3189 if (!ret && (unixname = get_data_dir_path( file )))
3191 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3192 HeapFree(GetProcessHeap(), 0, unixname);
3196 LeaveCriticalSection( &freetype_cs );
3198 return ret;
3201 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3203 WCHAR *fullname;
3204 char *unix_name;
3205 int file_len;
3207 if (!font_file) return NULL;
3209 file_len = strlenW( font_file );
3211 if (font_path && font_path[0])
3213 int path_len = strlenW( font_path );
3214 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3215 if (!fullname) return NULL;
3216 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3217 fullname[path_len] = '\\';
3218 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3220 else
3222 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3223 if (!len) return NULL;
3224 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3225 if (!fullname) return NULL;
3226 GetFullPathNameW( font_file, len, fullname, NULL );
3229 unix_name = wine_get_unix_file_name( fullname );
3230 HeapFree( GetProcessHeap(), 0, fullname );
3231 return unix_name;
3234 #include <pshpack1.h>
3235 struct fontdir
3237 WORD num_of_resources;
3238 WORD res_id;
3239 WORD dfVersion;
3240 DWORD dfSize;
3241 CHAR dfCopyright[60];
3242 WORD dfType;
3243 WORD dfPoints;
3244 WORD dfVertRes;
3245 WORD dfHorizRes;
3246 WORD dfAscent;
3247 WORD dfInternalLeading;
3248 WORD dfExternalLeading;
3249 BYTE dfItalic;
3250 BYTE dfUnderline;
3251 BYTE dfStrikeOut;
3252 WORD dfWeight;
3253 BYTE dfCharSet;
3254 WORD dfPixWidth;
3255 WORD dfPixHeight;
3256 BYTE dfPitchAndFamily;
3257 WORD dfAvgWidth;
3258 WORD dfMaxWidth;
3259 BYTE dfFirstChar;
3260 BYTE dfLastChar;
3261 BYTE dfDefaultChar;
3262 BYTE dfBreakChar;
3263 WORD dfWidthBytes;
3264 DWORD dfDevice;
3265 DWORD dfFace;
3266 DWORD dfReserved;
3267 CHAR szFaceName[LF_FACESIZE];
3270 #include <poppack.h>
3272 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3273 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3275 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3277 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3278 Face *face;
3279 WCHAR *name, *english_name;
3280 ENUMLOGFONTEXW elf;
3281 NEWTEXTMETRICEXW ntm;
3282 DWORD type;
3284 if (!ft_face) return FALSE;
3285 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3286 get_family_names( ft_face, &name, &english_name, FALSE );
3287 pFT_Done_Face( ft_face );
3289 GetEnumStructs( face, name, &elf, &ntm, &type );
3290 release_face( face );
3291 HeapFree( GetProcessHeap(), 0, name );
3292 HeapFree( GetProcessHeap(), 0, english_name );
3294 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3296 memset( fd, 0, sizeof(*fd) );
3298 fd->num_of_resources = 1;
3299 fd->res_id = 0;
3300 fd->dfVersion = 0x200;
3301 fd->dfSize = sizeof(*fd);
3302 strcpy( fd->dfCopyright, "Wine fontdir" );
3303 fd->dfType = 0x4003; /* 0x0080 set if private */
3304 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3305 fd->dfVertRes = 72;
3306 fd->dfHorizRes = 72;
3307 fd->dfAscent = ntm.ntmTm.tmAscent;
3308 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3309 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3310 fd->dfItalic = ntm.ntmTm.tmItalic;
3311 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3312 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3313 fd->dfWeight = ntm.ntmTm.tmWeight;
3314 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3315 fd->dfPixWidth = 0;
3316 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3317 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3318 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3319 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3320 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3321 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3322 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3323 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3324 fd->dfWidthBytes = 0;
3325 fd->dfDevice = 0;
3326 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3327 fd->dfReserved = 0;
3328 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3330 return TRUE;
3333 #define NE_FFLAGS_LIBMODULE 0x8000
3334 #define NE_OSFLAGS_WINDOWS 0x02
3336 static const char dos_string[0x40] = "This is a TrueType resource file";
3337 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3339 #include <pshpack2.h>
3341 struct ne_typeinfo
3343 WORD type_id;
3344 WORD count;
3345 DWORD res;
3348 struct ne_nameinfo
3350 WORD off;
3351 WORD len;
3352 WORD flags;
3353 WORD id;
3354 DWORD res;
3357 struct rsrc_tab
3359 WORD align;
3360 struct ne_typeinfo fontdir_type;
3361 struct ne_nameinfo fontdir_name;
3362 struct ne_typeinfo scalable_type;
3363 struct ne_nameinfo scalable_name;
3364 WORD end_of_rsrc;
3365 BYTE fontdir_res_name[8];
3368 #include <poppack.h>
3370 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3372 BOOL ret = FALSE;
3373 HANDLE file;
3374 DWORD size, written;
3375 BYTE *ptr, *start;
3376 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3377 char *font_fileA, *last_part, *ext;
3378 IMAGE_DOS_HEADER dos;
3379 IMAGE_OS2_HEADER ne =
3381 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3382 0, 0, 0, 0, 0, 0,
3383 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3384 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3386 struct rsrc_tab rsrc_tab =
3389 { 0x8007, 1, 0 },
3390 { 0, 0, 0x0c50, 0x2c, 0 },
3391 { 0x80cc, 1, 0 },
3392 { 0, 0, 0x0c50, 0x8001, 0 },
3394 { 7,'F','O','N','T','D','I','R'}
3397 memset( &dos, 0, sizeof(dos) );
3398 dos.e_magic = IMAGE_DOS_SIGNATURE;
3399 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3401 /* import name is last part\0, resident name is last part without extension
3402 non-resident name is "FONTRES:" + lfFaceName */
3404 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3405 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3406 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3408 last_part = strrchr( font_fileA, '\\' );
3409 if (last_part) last_part++;
3410 else last_part = font_fileA;
3411 import_name_len = strlen( last_part ) + 1;
3413 ext = strchr( last_part, '.' );
3414 if (ext) res_name_len = ext - last_part;
3415 else res_name_len = import_name_len - 1;
3417 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3419 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3420 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3421 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3422 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3423 ne.ne_cbenttab = 2;
3424 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3426 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3427 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3428 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3429 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3431 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3432 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3434 if (!ptr)
3436 HeapFree( GetProcessHeap(), 0, font_fileA );
3437 return FALSE;
3440 memcpy( ptr, &dos, sizeof(dos) );
3441 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3442 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3444 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3445 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3447 ptr = start + dos.e_lfanew + ne.ne_restab;
3448 *ptr++ = res_name_len;
3449 memcpy( ptr, last_part, res_name_len );
3451 ptr = start + dos.e_lfanew + ne.ne_imptab;
3452 *ptr++ = import_name_len;
3453 memcpy( ptr, last_part, import_name_len );
3455 ptr = start + ne.ne_nrestab;
3456 *ptr++ = non_res_name_len;
3457 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3458 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3460 ptr = start + (rsrc_tab.scalable_name.off << 4);
3461 memcpy( ptr, font_fileA, font_file_len );
3463 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3464 memcpy( ptr, fontdir, fontdir->dfSize );
3466 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3467 if (file != INVALID_HANDLE_VALUE)
3469 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3470 ret = TRUE;
3471 CloseHandle( file );
3474 HeapFree( GetProcessHeap(), 0, start );
3475 HeapFree( GetProcessHeap(), 0, font_fileA );
3477 return ret;
3480 /*************************************************************
3481 * WineEngCreateScalableFontResource
3484 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3485 LPCWSTR font_file, LPCWSTR font_path )
3487 char *unix_name = get_ttf_file_name( font_file, font_path );
3488 struct fontdir fontdir;
3489 BOOL ret = FALSE;
3491 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3492 SetLastError( ERROR_INVALID_PARAMETER );
3493 else
3495 if (hidden) fontdir.dfType |= 0x80;
3496 ret = create_fot( resource, font_file, &fontdir );
3499 HeapFree( GetProcessHeap(), 0, unix_name );
3500 return ret;
3503 static const struct nls_update_font_list
3505 UINT ansi_cp, oem_cp;
3506 const char *oem, *fixed, *system;
3507 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3508 /* these are for font substitutes */
3509 const char *shelldlg, *tmsrmn;
3510 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3511 *helv_0, *tmsrmn_0;
3512 const struct subst
3514 const char *from, *to;
3515 } arial_0, courier_new_0, times_new_roman_0;
3516 } nls_update_font_list[] =
3518 /* Latin 1 (United States) */
3519 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3520 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3521 "Tahoma","Times New Roman",
3522 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3523 { 0 }, { 0 }, { 0 }
3525 /* Latin 1 (Multilingual) */
3526 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3527 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3528 "Tahoma","Times New Roman", /* FIXME unverified */
3529 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3530 { 0 }, { 0 }, { 0 }
3532 /* Eastern Europe */
3533 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3534 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3535 "Tahoma","Times New Roman", /* FIXME unverified */
3536 "Fixedsys,238", "System,238",
3537 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3538 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3539 { "Arial CE,0", "Arial,238" },
3540 { "Courier New CE,0", "Courier New,238" },
3541 { "Times New Roman CE,0", "Times New Roman,238" }
3543 /* Cyrillic */
3544 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3545 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3546 "Tahoma","Times New Roman", /* FIXME unverified */
3547 "Fixedsys,204", "System,204",
3548 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3549 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3550 { "Arial Cyr,0", "Arial,204" },
3551 { "Courier New Cyr,0", "Courier New,204" },
3552 { "Times New Roman Cyr,0", "Times New Roman,204" }
3554 /* Greek */
3555 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3556 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3557 "Tahoma","Times New Roman", /* FIXME unverified */
3558 "Fixedsys,161", "System,161",
3559 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3560 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3561 { "Arial Greek,0", "Arial,161" },
3562 { "Courier New Greek,0", "Courier New,161" },
3563 { "Times New Roman Greek,0", "Times New Roman,161" }
3565 /* Turkish */
3566 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3567 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3568 "Tahoma","Times New Roman", /* FIXME unverified */
3569 "Fixedsys,162", "System,162",
3570 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3571 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3572 { "Arial Tur,0", "Arial,162" },
3573 { "Courier New Tur,0", "Courier New,162" },
3574 { "Times New Roman Tur,0", "Times New Roman,162" }
3576 /* Hebrew */
3577 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3578 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3579 "Tahoma","Times New Roman", /* FIXME unverified */
3580 "Fixedsys,177", "System,177",
3581 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3582 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3583 { 0 }, { 0 }, { 0 }
3585 /* Arabic */
3586 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3587 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3588 "Microsoft Sans Serif","Times New Roman",
3589 "Fixedsys,178", "System,178",
3590 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3591 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3592 { 0 }, { 0 }, { 0 }
3594 /* Baltic */
3595 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3596 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3597 "Tahoma","Times New Roman", /* FIXME unverified */
3598 "Fixedsys,186", "System,186",
3599 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3600 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3601 { "Arial Baltic,0", "Arial,186" },
3602 { "Courier New Baltic,0", "Courier New,186" },
3603 { "Times New Roman Baltic,0", "Times New Roman,186" }
3605 /* Vietnamese */
3606 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3607 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3608 "Tahoma","Times New Roman", /* FIXME unverified */
3609 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3610 { 0 }, { 0 }, { 0 }
3612 /* Thai */
3613 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3614 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3615 "Tahoma","Times New Roman", /* FIXME unverified */
3616 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3617 { 0 }, { 0 }, { 0 }
3619 /* Japanese */
3620 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3621 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3622 "MS UI Gothic","MS Serif",
3623 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3624 { 0 }, { 0 }, { 0 }
3626 /* Chinese Simplified */
3627 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3628 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3629 "SimSun", "NSimSun",
3630 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3631 { 0 }, { 0 }, { 0 }
3633 /* Korean */
3634 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3635 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3636 "Gulim", "Batang",
3637 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3638 { 0 }, { 0 }, { 0 }
3640 /* Chinese Traditional */
3641 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3642 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3643 "PMingLiU", "MingLiU",
3644 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3645 { 0 }, { 0 }, { 0 }
3649 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3651 return ( ansi_cp == 932 /* CP932 for Japanese */
3652 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3653 || ansi_cp == 949 /* CP949 for Korean */
3654 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3657 static inline HKEY create_fonts_NT_registry_key(void)
3659 HKEY hkey = 0;
3661 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3662 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3663 return hkey;
3666 static inline HKEY create_fonts_9x_registry_key(void)
3668 HKEY hkey = 0;
3670 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3671 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3672 return hkey;
3675 static inline HKEY create_config_fonts_registry_key(void)
3677 HKEY hkey = 0;
3679 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3680 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3681 return hkey;
3684 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3686 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3688 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3689 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3690 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3691 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3694 static void set_value_key(HKEY hkey, const char *name, const char *value)
3696 if (value)
3697 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3698 else if (name)
3699 RegDeleteValueA(hkey, name);
3702 static void update_font_association_info(UINT current_ansi_codepage)
3704 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3705 static const char *assoc_charset_subkey = "Associated Charset";
3707 if (is_dbcs_ansi_cp(current_ansi_codepage))
3709 HKEY hkey;
3710 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3712 HKEY hsubkey;
3713 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3715 switch (current_ansi_codepage)
3717 case 932:
3718 set_value_key(hsubkey, "ANSI(00)", "NO");
3719 set_value_key(hsubkey, "OEM(FF)", "NO");
3720 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3721 break;
3722 case 936:
3723 case 949:
3724 case 950:
3725 set_value_key(hsubkey, "ANSI(00)", "YES");
3726 set_value_key(hsubkey, "OEM(FF)", "YES");
3727 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3728 break;
3730 RegCloseKey(hsubkey);
3733 /* TODO: Associated DefaultFonts */
3735 RegCloseKey(hkey);
3738 else
3739 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3742 static void update_font_info(void)
3744 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3745 char buf[40], cpbuf[40];
3746 DWORD len, type;
3747 HKEY hkey = 0;
3748 UINT i, ansi_cp = 0, oem_cp = 0;
3749 DWORD screen_dpi = 96, font_dpi = 0;
3750 BOOL done = FALSE;
3752 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3753 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3754 &hkey) == ERROR_SUCCESS)
3756 reg_load_dword(hkey, logpixels, &screen_dpi);
3757 RegCloseKey(hkey);
3760 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3761 return;
3763 reg_load_dword(hkey, logpixels, &font_dpi);
3765 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3766 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3767 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3768 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3769 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3771 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3772 if (is_dbcs_ansi_cp(ansi_cp))
3773 use_default_fallback = TRUE;
3775 buf[0] = 0;
3776 len = sizeof(buf);
3777 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3779 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3781 RegCloseKey(hkey);
3782 return;
3784 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3785 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3787 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3788 ansi_cp, oem_cp, screen_dpi);
3790 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3791 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3792 RegCloseKey(hkey);
3794 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3796 HKEY hkey;
3798 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3799 nls_update_font_list[i].oem_cp == oem_cp)
3801 hkey = create_config_fonts_registry_key();
3802 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3803 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3804 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3805 RegCloseKey(hkey);
3807 hkey = create_fonts_NT_registry_key();
3808 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3809 RegCloseKey(hkey);
3811 hkey = create_fonts_9x_registry_key();
3812 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3813 RegCloseKey(hkey);
3815 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3817 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3818 strlen(nls_update_font_list[i].shelldlg)+1);
3819 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3820 strlen(nls_update_font_list[i].tmsrmn)+1);
3822 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3823 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3824 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3825 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3826 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3827 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3828 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3829 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3831 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3832 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3833 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3835 RegCloseKey(hkey);
3837 done = TRUE;
3839 else
3841 /* Delete the FontSubstitutes from other locales */
3842 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3844 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3845 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3846 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3847 RegCloseKey(hkey);
3851 if (!done)
3852 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3854 /* update locale dependent font association info in registry.
3855 update only when codepages changed, not logpixels. */
3856 if (strcmp(buf, cpbuf) != 0)
3857 update_font_association_info(ansi_cp);
3860 static BOOL init_freetype(void)
3862 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3863 if(!ft_handle) {
3864 WINE_MESSAGE(
3865 "Wine cannot find the FreeType font library. To enable Wine to\n"
3866 "use TrueType fonts please install a version of FreeType greater than\n"
3867 "or equal to 2.0.5.\n"
3868 "http://www.freetype.org\n");
3869 return FALSE;
3872 #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;}
3874 LOAD_FUNCPTR(FT_Done_Face)
3875 LOAD_FUNCPTR(FT_Get_Char_Index)
3876 LOAD_FUNCPTR(FT_Get_First_Char)
3877 LOAD_FUNCPTR(FT_Get_Next_Char)
3878 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3879 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3880 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3881 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3882 LOAD_FUNCPTR(FT_Init_FreeType)
3883 LOAD_FUNCPTR(FT_Library_Version)
3884 LOAD_FUNCPTR(FT_Load_Glyph)
3885 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3886 LOAD_FUNCPTR(FT_Matrix_Multiply)
3887 #ifndef FT_MULFIX_INLINED
3888 LOAD_FUNCPTR(FT_MulFix)
3889 #endif
3890 LOAD_FUNCPTR(FT_New_Face)
3891 LOAD_FUNCPTR(FT_New_Memory_Face)
3892 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3893 LOAD_FUNCPTR(FT_Outline_Get_CBox)
3894 LOAD_FUNCPTR(FT_Outline_Transform)
3895 LOAD_FUNCPTR(FT_Outline_Translate)
3896 LOAD_FUNCPTR(FT_Render_Glyph)
3897 LOAD_FUNCPTR(FT_Select_Charmap)
3898 LOAD_FUNCPTR(FT_Set_Charmap)
3899 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3900 LOAD_FUNCPTR(FT_Vector_Transform)
3901 LOAD_FUNCPTR(FT_Vector_Unit)
3902 #undef LOAD_FUNCPTR
3903 /* Don't warn if these ones are missing */
3904 pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
3905 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3906 #ifdef FT_LCD_FILTER_H
3907 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3908 #endif
3910 if(pFT_Init_FreeType(&library) != 0) {
3911 ERR("Can't init FreeType library\n");
3912 wine_dlclose(ft_handle, NULL, 0);
3913 ft_handle = NULL;
3914 return FALSE;
3916 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3918 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3919 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3920 ((FT_Version.minor << 8) & 0x00ff00) |
3921 ((FT_Version.patch ) & 0x0000ff);
3923 font_driver = &freetype_funcs;
3924 return TRUE;
3926 sym_not_found:
3927 WINE_MESSAGE(
3928 "Wine cannot find certain functions that it needs inside the FreeType\n"
3929 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3930 "FreeType to at least version 2.1.4.\n"
3931 "http://www.freetype.org\n");
3932 wine_dlclose(ft_handle, NULL, 0);
3933 ft_handle = NULL;
3934 return FALSE;
3937 static void init_font_list(void)
3939 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3940 static const WCHAR pathW[] = {'P','a','t','h',0};
3941 HKEY hkey;
3942 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3943 WCHAR windowsdir[MAX_PATH];
3944 char *unixname;
3945 const char *data_dir;
3947 delete_external_font_keys();
3949 /* load the system bitmap fonts */
3950 load_system_fonts();
3952 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3953 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3954 strcatW(windowsdir, fontsW);
3955 if((unixname = wine_get_unix_file_name(windowsdir)))
3957 ReadFontDir(unixname, FALSE);
3958 HeapFree(GetProcessHeap(), 0, unixname);
3961 /* load the system truetype fonts */
3962 data_dir = wine_get_data_dir();
3963 if (!data_dir) data_dir = wine_get_build_dir();
3964 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3966 strcpy(unixname, data_dir);
3967 strcat(unixname, "/fonts/");
3968 ReadFontDir(unixname, TRUE);
3969 HeapFree(GetProcessHeap(), 0, unixname);
3972 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3973 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3974 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3975 will skip these. */
3976 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3977 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3978 &hkey) == ERROR_SUCCESS)
3980 LPWSTR data, valueW;
3981 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3982 &valuelen, &datalen, NULL, NULL);
3984 valuelen++; /* returned value doesn't include room for '\0' */
3985 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3986 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3987 if (valueW && data)
3989 dlen = datalen * sizeof(WCHAR);
3990 vlen = valuelen;
3991 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3992 &dlen) == ERROR_SUCCESS)
3994 if(data[0] && (data[1] == ':'))
3996 if((unixname = wine_get_unix_file_name(data)))
3998 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3999 HeapFree(GetProcessHeap(), 0, unixname);
4002 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4004 WCHAR pathW[MAX_PATH];
4005 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4006 BOOL added = FALSE;
4008 sprintfW(pathW, fmtW, windowsdir, data);
4009 if((unixname = wine_get_unix_file_name(pathW)))
4011 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4012 HeapFree(GetProcessHeap(), 0, unixname);
4014 if (!added)
4015 load_font_from_data_dir(data);
4017 /* reset dlen and vlen */
4018 dlen = datalen;
4019 vlen = valuelen;
4022 HeapFree(GetProcessHeap(), 0, data);
4023 HeapFree(GetProcessHeap(), 0, valueW);
4024 RegCloseKey(hkey);
4027 #ifdef SONAME_LIBFONTCONFIG
4028 load_fontconfig_fonts();
4029 #elif defined(HAVE_CARBON_CARBON_H)
4030 load_mac_fonts();
4031 #endif
4033 /* then look in any directories that we've specified in the config file */
4034 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4035 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4037 DWORD len;
4038 LPWSTR valueW;
4039 LPSTR valueA, ptr;
4041 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4043 len += sizeof(WCHAR);
4044 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4045 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4047 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4048 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4049 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4050 TRACE( "got font path %s\n", debugstr_a(valueA) );
4051 ptr = valueA;
4052 while (ptr)
4054 const char* home;
4055 LPSTR next = strchr( ptr, ':' );
4056 if (next) *next++ = 0;
4057 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4058 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4060 strcpy( unixname, home );
4061 strcat( unixname, ptr + 1 );
4062 ReadFontDir( unixname, TRUE );
4063 HeapFree( GetProcessHeap(), 0, unixname );
4065 else
4066 ReadFontDir( ptr, TRUE );
4067 ptr = next;
4069 HeapFree( GetProcessHeap(), 0, valueA );
4071 HeapFree( GetProcessHeap(), 0, valueW );
4073 RegCloseKey(hkey);
4077 static BOOL move_to_front(const WCHAR *name)
4079 Family *family, *cursor2;
4080 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4082 if(!strcmpiW(family->FamilyName, name))
4084 list_remove(&family->entry);
4085 list_add_head(&font_list, &family->entry);
4086 return TRUE;
4089 return FALSE;
4092 static BOOL set_default(const WCHAR **name_list)
4094 while (*name_list)
4096 if (move_to_front(*name_list)) return TRUE;
4097 name_list++;
4100 return FALSE;
4103 static void reorder_font_list(void)
4105 set_default( default_serif_list );
4106 set_default( default_fixed_list );
4107 set_default( default_sans_list );
4110 /*************************************************************
4111 * WineEngInit
4113 * Initialize FreeType library and create a list of available faces
4115 BOOL WineEngInit(void)
4117 DWORD disposition;
4118 HANDLE font_mutex;
4120 /* update locale dependent font info in registry */
4121 update_font_info();
4123 if(!init_freetype()) return FALSE;
4125 #ifdef SONAME_LIBFONTCONFIG
4126 init_fontconfig();
4127 #endif
4129 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4131 ERR("Failed to create font mutex\n");
4132 return FALSE;
4134 WaitForSingleObject(font_mutex, INFINITE);
4136 create_font_cache_key(&hkey_font_cache, &disposition);
4138 if(disposition == REG_CREATED_NEW_KEY)
4139 init_font_list();
4140 else
4141 load_font_list_from_cache(hkey_font_cache);
4143 reorder_font_list();
4145 DumpFontList();
4146 LoadSubstList();
4147 DumpSubstList();
4148 LoadReplaceList();
4150 if(disposition == REG_CREATED_NEW_KEY)
4151 update_reg_entries();
4153 init_system_links();
4155 ReleaseMutex(font_mutex);
4156 return TRUE;
4160 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4162 TT_OS2 *pOS2;
4163 TT_HoriHeader *pHori;
4165 LONG ppem;
4166 const LONG MAX_PPEM = (1 << 16) - 1;
4168 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4169 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4171 if(height == 0) height = 16;
4173 /* Calc. height of EM square:
4175 * For +ve lfHeight we have
4176 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4177 * Re-arranging gives:
4178 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4180 * For -ve lfHeight we have
4181 * |lfHeight| = ppem
4182 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4183 * with il = winAscent + winDescent - units_per_em]
4187 if(height > 0) {
4188 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
4189 ppem = MulDiv(ft_face->units_per_EM, height,
4190 pHori->Ascender - pHori->Descender);
4191 else
4192 ppem = MulDiv(ft_face->units_per_EM, height,
4193 pOS2->usWinAscent + pOS2->usWinDescent);
4194 if(ppem > MAX_PPEM) {
4195 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4196 ppem = 1;
4199 else if(height >= -MAX_PPEM)
4200 ppem = -height;
4201 else {
4202 WARN("Ignoring too large height %d\n", height);
4203 ppem = 1;
4206 return ppem;
4209 static struct font_mapping *map_font_file( const char *name )
4211 struct font_mapping *mapping;
4212 struct stat st;
4213 int fd;
4215 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4216 if (fstat( fd, &st ) == -1) goto error;
4218 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4220 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4222 mapping->refcount++;
4223 close( fd );
4224 return mapping;
4227 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4228 goto error;
4230 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4231 close( fd );
4233 if (mapping->data == MAP_FAILED)
4235 HeapFree( GetProcessHeap(), 0, mapping );
4236 return NULL;
4238 mapping->refcount = 1;
4239 mapping->dev = st.st_dev;
4240 mapping->ino = st.st_ino;
4241 mapping->size = st.st_size;
4242 list_add_tail( &mappings_list, &mapping->entry );
4243 return mapping;
4245 error:
4246 close( fd );
4247 return NULL;
4250 static void unmap_font_file( struct font_mapping *mapping )
4252 if (!--mapping->refcount)
4254 list_remove( &mapping->entry );
4255 munmap( mapping->data, mapping->size );
4256 HeapFree( GetProcessHeap(), 0, mapping );
4260 static LONG load_VDMX(GdiFont*, LONG);
4262 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4264 FT_Error err;
4265 FT_Face ft_face;
4266 void *data_ptr;
4267 DWORD data_size;
4269 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4271 if (face->file)
4273 char *filename = strWtoA( CP_UNIXCP, face->file );
4274 font->mapping = map_font_file( filename );
4275 HeapFree( GetProcessHeap(), 0, filename );
4276 if (!font->mapping)
4278 WARN("failed to map %s\n", debugstr_w(face->file));
4279 return 0;
4281 data_ptr = font->mapping->data;
4282 data_size = font->mapping->size;
4284 else
4286 data_ptr = face->font_data_ptr;
4287 data_size = face->font_data_size;
4290 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4291 if(err) {
4292 ERR("FT_New_Face rets %d\n", err);
4293 return 0;
4296 /* set it here, as load_VDMX needs it */
4297 font->ft_face = ft_face;
4299 if(FT_IS_SCALABLE(ft_face)) {
4300 /* load the VDMX table if we have one */
4301 font->ppem = load_VDMX(font, height);
4302 if(font->ppem == 0)
4303 font->ppem = calc_ppem_for_height(ft_face, height);
4304 TRACE("height %d => ppem %d\n", height, font->ppem);
4306 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4307 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4308 } else {
4309 font->ppem = height;
4310 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4311 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4313 return ft_face;
4317 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4319 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4320 a single face with the requested charset. The idea is to check if
4321 the selected font supports the current ANSI codepage, if it does
4322 return the corresponding charset, else return the first charset */
4324 CHARSETINFO csi;
4325 int acp = GetACP(), i;
4326 DWORD fs0;
4328 *cp = acp;
4329 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4331 const SYSTEM_LINKS *font_link;
4333 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4334 return csi.ciCharset;
4336 font_link = find_font_link(family_name);
4337 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4338 return csi.ciCharset;
4341 for(i = 0; i < 32; i++) {
4342 fs0 = 1L << i;
4343 if(face->fs.fsCsb[0] & fs0) {
4344 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4345 *cp = csi.ciACP;
4346 return csi.ciCharset;
4348 else
4349 FIXME("TCI failing on %x\n", fs0);
4353 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4354 face->fs.fsCsb[0], debugstr_w(face->file));
4355 *cp = acp;
4356 return DEFAULT_CHARSET;
4359 static GdiFont *alloc_font(void)
4361 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4362 ret->refcount = 1;
4363 ret->gmsize = 1;
4364 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4365 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4366 ret->potm = NULL;
4367 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4368 ret->total_kern_pairs = (DWORD)-1;
4369 ret->kern_pairs = NULL;
4370 list_init(&ret->child_fonts);
4371 return ret;
4374 static void free_font(GdiFont *font)
4376 CHILD_FONT *child, *child_next;
4377 DWORD i;
4379 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4381 list_remove(&child->entry);
4382 if(child->font)
4383 free_font(child->font);
4384 release_face( child->face );
4385 HeapFree(GetProcessHeap(), 0, child);
4388 if (font->ft_face) pFT_Done_Face(font->ft_face);
4389 if (font->mapping) unmap_font_file( font->mapping );
4390 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4391 HeapFree(GetProcessHeap(), 0, font->potm);
4392 HeapFree(GetProcessHeap(), 0, font->name);
4393 for (i = 0; i < font->gmsize; i++)
4394 HeapFree(GetProcessHeap(),0,font->gm[i]);
4395 HeapFree(GetProcessHeap(), 0, font->gm);
4396 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4397 HeapFree(GetProcessHeap(), 0, font);
4401 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4403 FT_Face ft_face = font->ft_face;
4404 FT_ULong len;
4405 FT_Error err;
4407 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4409 if(!buf)
4410 len = 0;
4411 else
4412 len = cbData;
4414 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4416 /* make sure value of len is the value freetype says it needs */
4417 if (buf && len)
4419 FT_ULong needed = 0;
4420 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4421 if( !err && needed < len) len = needed;
4423 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4424 if (err)
4426 TRACE("Can't find table %c%c%c%c\n",
4427 /* bytes were reversed */
4428 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4429 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4430 return GDI_ERROR;
4432 return len;
4435 /*************************************************************
4436 * load_VDMX
4438 * load the vdmx entry for the specified height
4441 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4442 ( ( (FT_ULong)_x4 << 24 ) | \
4443 ( (FT_ULong)_x3 << 16 ) | \
4444 ( (FT_ULong)_x2 << 8 ) | \
4445 (FT_ULong)_x1 )
4447 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4449 typedef struct {
4450 BYTE bCharSet;
4451 BYTE xRatio;
4452 BYTE yStartRatio;
4453 BYTE yEndRatio;
4454 } Ratios;
4456 typedef struct {
4457 WORD recs;
4458 BYTE startsz;
4459 BYTE endsz;
4460 } VDMX_group;
4462 static LONG load_VDMX(GdiFont *font, LONG height)
4464 WORD hdr[3];
4465 VDMX_group group;
4466 BYTE devXRatio, devYRatio;
4467 USHORT numRecs, numRatios;
4468 DWORD result, offset = -1;
4469 LONG ppem = 0;
4470 int i;
4472 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, sizeof(hdr));
4474 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4475 return ppem;
4477 /* FIXME: need the real device aspect ratio */
4478 devXRatio = 1;
4479 devYRatio = 1;
4481 numRecs = GET_BE_WORD(hdr[1]);
4482 numRatios = GET_BE_WORD(hdr[2]);
4484 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4485 for(i = 0; i < numRatios; i++) {
4486 Ratios ratio;
4488 offset = (3 * 2) + (i * sizeof(Ratios));
4489 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4490 offset = -1;
4492 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4494 if (!ratio.bCharSet) continue;
4496 if((ratio.xRatio == 0 &&
4497 ratio.yStartRatio == 0 &&
4498 ratio.yEndRatio == 0) ||
4499 (devXRatio == ratio.xRatio &&
4500 devYRatio >= ratio.yStartRatio &&
4501 devYRatio <= ratio.yEndRatio))
4503 WORD tmp;
4505 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4506 get_font_data(font, MS_VDMX_TAG, offset, &tmp, sizeof(tmp));
4507 offset = GET_BE_WORD(tmp);
4508 break;
4512 if(offset == -1) return 0;
4514 if(get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
4515 USHORT recs;
4516 BYTE startsz, endsz;
4517 WORD *vTable;
4519 recs = GET_BE_WORD(group.recs);
4520 startsz = group.startsz;
4521 endsz = group.endsz;
4523 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4525 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4526 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4527 if(result == GDI_ERROR) {
4528 FIXME("Failed to retrieve vTable\n");
4529 goto end;
4532 if(height > 0) {
4533 for(i = 0; i < recs; i++) {
4534 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4535 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4536 ppem = GET_BE_WORD(vTable[i * 3]);
4538 if(yMax + -yMin == height) {
4539 font->yMax = yMax;
4540 font->yMin = yMin;
4541 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4542 break;
4544 if(yMax + -yMin > height) {
4545 if(--i < 0) {
4546 ppem = 0;
4547 goto end; /* failed */
4549 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4550 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4551 ppem = GET_BE_WORD(vTable[i * 3]);
4552 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4553 break;
4556 if(!font->yMax) {
4557 ppem = 0;
4558 TRACE("ppem not found for height %d\n", height);
4560 } else {
4561 ppem = -height;
4562 if(ppem < startsz || ppem > endsz)
4564 ppem = 0;
4565 goto end;
4568 for(i = 0; i < recs; i++) {
4569 USHORT yPelHeight;
4570 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4572 if(yPelHeight > ppem)
4574 ppem = 0;
4575 break; /* failed */
4578 if(yPelHeight == ppem) {
4579 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4580 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4581 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4582 break;
4586 end:
4587 HeapFree(GetProcessHeap(), 0, vTable);
4590 return ppem;
4593 static void dump_gdi_font_list(void)
4595 GdiFont *font;
4597 TRACE("---------- Font Cache ----------\n");
4598 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4599 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4600 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4603 static void grab_font( GdiFont *font )
4605 if (!font->refcount++)
4607 list_remove( &font->unused_entry );
4608 unused_font_count--;
4612 static void release_font( GdiFont *font )
4614 if (!font) return;
4615 if (!--font->refcount)
4617 TRACE( "font %p\n", font );
4619 /* add it to the unused list */
4620 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4621 if (unused_font_count > UNUSED_CACHE_SIZE)
4623 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4624 TRACE( "freeing %p\n", font );
4625 list_remove( &font->entry );
4626 list_remove( &font->unused_entry );
4627 free_font( font );
4629 else unused_font_count++;
4631 if (TRACE_ON(font)) dump_gdi_font_list();
4635 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4637 if(font->font_desc.hash != fd->hash) return TRUE;
4638 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4639 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4640 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4641 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4644 static void calc_hash(FONT_DESC *pfd)
4646 DWORD hash = 0, *ptr, two_chars;
4647 WORD *pwc;
4648 unsigned int i;
4650 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4651 hash ^= *ptr;
4652 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4653 hash ^= *ptr;
4654 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4655 two_chars = *ptr;
4656 pwc = (WCHAR *)&two_chars;
4657 if(!*pwc) break;
4658 *pwc = toupperW(*pwc);
4659 pwc++;
4660 *pwc = toupperW(*pwc);
4661 hash ^= two_chars;
4662 if(!*pwc) break;
4664 hash ^= !pfd->can_use_bitmap;
4665 pfd->hash = hash;
4668 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4670 GdiFont *ret;
4671 FONT_DESC fd;
4673 fd.lf = *plf;
4674 fd.matrix = *pmat;
4675 fd.can_use_bitmap = can_use_bitmap;
4676 calc_hash(&fd);
4678 /* try the in-use list */
4679 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4681 if(fontcmp(ret, &fd)) continue;
4682 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4683 list_remove( &ret->entry );
4684 list_add_head( &gdi_font_list, &ret->entry );
4685 grab_font( ret );
4686 return ret;
4688 return NULL;
4691 static void add_to_cache(GdiFont *font)
4693 static DWORD cache_num = 1;
4695 font->cache_num = cache_num++;
4696 list_add_head(&gdi_font_list, &font->entry);
4697 TRACE( "font %p\n", font );
4700 /*************************************************************
4701 * create_child_font_list
4703 static BOOL create_child_font_list(GdiFont *font)
4705 BOOL ret = FALSE;
4706 SYSTEM_LINKS *font_link;
4707 CHILD_FONT *font_link_entry, *new_child;
4708 FontSubst *psub;
4709 WCHAR* font_name;
4711 psub = get_font_subst(&font_subst_list, font->name, -1);
4712 font_name = psub ? psub->to.name : font->name;
4713 font_link = find_font_link(font_name);
4714 if (font_link != NULL)
4716 TRACE("found entry in system list\n");
4717 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4719 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4720 new_child->face = font_link_entry->face;
4721 new_child->font = NULL;
4722 new_child->face->refcount++;
4723 list_add_tail(&font->child_fonts, &new_child->entry);
4724 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4726 ret = TRUE;
4729 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4730 * Sans Serif. This is how asian windows get default fallbacks for fonts
4732 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4733 font->charset != OEM_CHARSET &&
4734 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4736 font_link = find_font_link(szDefaultFallbackLink);
4737 if (font_link != NULL)
4739 TRACE("found entry in default fallback list\n");
4740 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4742 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4743 new_child->face = font_link_entry->face;
4744 new_child->font = NULL;
4745 new_child->face->refcount++;
4746 list_add_tail(&font->child_fonts, &new_child->entry);
4747 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4749 ret = TRUE;
4753 return ret;
4756 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4758 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4760 if (pFT_Set_Charmap)
4762 FT_Int i;
4763 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4765 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4767 for (i = 0; i < ft_face->num_charmaps; i++)
4769 if (ft_face->charmaps[i]->encoding == encoding)
4771 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4772 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4774 switch (ft_face->charmaps[i]->platform_id)
4776 default:
4777 cmap_def = ft_face->charmaps[i];
4778 break;
4779 case 0: /* Apple Unicode */
4780 cmap0 = ft_face->charmaps[i];
4781 break;
4782 case 1: /* Macintosh */
4783 cmap1 = ft_face->charmaps[i];
4784 break;
4785 case 2: /* ISO */
4786 cmap2 = ft_face->charmaps[i];
4787 break;
4788 case 3: /* Microsoft */
4789 cmap3 = ft_face->charmaps[i];
4790 break;
4794 if (cmap3) /* prefer Microsoft cmap table */
4795 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4796 else if (cmap1)
4797 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4798 else if (cmap2)
4799 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4800 else if (cmap0)
4801 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4802 else if (cmap_def)
4803 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4805 return ft_err == FT_Err_Ok;
4808 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4812 /*************************************************************
4813 * freetype_CreateDC
4815 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4816 LPCWSTR output, const DEVMODEW *devmode )
4818 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4820 if (!physdev) return FALSE;
4821 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4822 return TRUE;
4826 /*************************************************************
4827 * freetype_DeleteDC
4829 static BOOL freetype_DeleteDC( PHYSDEV dev )
4831 struct freetype_physdev *physdev = get_freetype_dev( dev );
4832 release_font( physdev->font );
4833 HeapFree( GetProcessHeap(), 0, physdev );
4834 return TRUE;
4837 static FT_Encoding pick_charmap( FT_Face face, int charset )
4839 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4840 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4841 const FT_Encoding *encs = regular_order;
4843 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4845 while (*encs != 0)
4847 if (select_charmap( face, *encs )) break;
4848 encs++;
4850 return *encs;
4853 #define GASP_GRIDFIT 0x01
4854 #define GASP_DOGRAY 0x02
4855 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4857 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4859 DWORD size;
4860 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4861 WORD *alloced = NULL, *ptr = buf;
4862 WORD num_recs, version;
4863 BOOL ret = FALSE;
4865 *flags = 0;
4866 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4867 if (size == GDI_ERROR) return FALSE;
4868 if (size < 4 * sizeof(WORD)) return FALSE;
4869 if (size > sizeof(buf))
4871 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4872 if (!ptr) return FALSE;
4875 get_font_data( font, GASP_TAG, 0, ptr, size );
4877 version = GET_BE_WORD( *ptr++ );
4878 num_recs = GET_BE_WORD( *ptr++ );
4880 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4882 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4883 goto done;
4886 while (num_recs--)
4888 *flags = GET_BE_WORD( *(ptr + 1) );
4889 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4890 ptr += 2;
4892 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4893 ret = TRUE;
4895 done:
4896 HeapFree( GetProcessHeap(), 0, alloced );
4897 return ret;
4900 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4902 const GSUB_ScriptList *script;
4903 const GSUB_Script *deflt = NULL;
4904 int i;
4905 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4907 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4908 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4910 const GSUB_Script *scr;
4911 int offset;
4913 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4914 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4916 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4917 return scr;
4918 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4919 deflt = scr;
4921 return deflt;
4924 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4926 int i;
4927 int offset;
4928 const GSUB_LangSys *Lang;
4930 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4932 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4934 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4935 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4937 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4938 return Lang;
4940 offset = GET_BE_WORD(script->DefaultLangSys);
4941 if (offset)
4943 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4944 return Lang;
4946 return NULL;
4949 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4951 int i;
4952 const GSUB_FeatureList *feature;
4953 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4955 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4956 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4958 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4959 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4961 const GSUB_Feature *feat;
4962 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4963 return feat;
4966 return NULL;
4969 static const char* get_opentype_script(const GdiFont *font)
4972 * I am not sure if this is the correct way to generate our script tag
4975 switch (font->charset)
4977 case ANSI_CHARSET: return "latn";
4978 case BALTIC_CHARSET: return "latn"; /* ?? */
4979 case CHINESEBIG5_CHARSET: return "hani";
4980 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4981 case GB2312_CHARSET: return "hani";
4982 case GREEK_CHARSET: return "grek";
4983 case HANGUL_CHARSET: return "hang";
4984 case RUSSIAN_CHARSET: return "cyrl";
4985 case SHIFTJIS_CHARSET: return "kana";
4986 case TURKISH_CHARSET: return "latn"; /* ?? */
4987 case VIETNAMESE_CHARSET: return "latn";
4988 case JOHAB_CHARSET: return "latn"; /* ?? */
4989 case ARABIC_CHARSET: return "arab";
4990 case HEBREW_CHARSET: return "hebr";
4991 case THAI_CHARSET: return "thai";
4992 default: return "latn";
4996 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
4998 const GSUB_Header *header;
4999 const GSUB_Script *script;
5000 const GSUB_LangSys *language;
5001 const GSUB_Feature *feature;
5003 if (!font->GSUB_Table)
5004 return NULL;
5006 header = font->GSUB_Table;
5008 script = GSUB_get_script_table(header, get_opentype_script(font));
5009 if (!script)
5011 TRACE("Script not found\n");
5012 return NULL;
5014 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5015 if (!language)
5017 TRACE("Language not found\n");
5018 return NULL;
5020 feature = GSUB_get_feature(header, language, "vrt2");
5021 if (!feature)
5022 feature = GSUB_get_feature(header, language, "vert");
5023 if (!feature)
5025 TRACE("vrt2/vert feature not found\n");
5026 return NULL;
5028 return feature;
5031 /*************************************************************
5032 * freetype_SelectFont
5034 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5036 struct freetype_physdev *physdev = get_freetype_dev( dev );
5037 GdiFont *ret;
5038 Face *face, *best, *best_bitmap;
5039 Family *family, *last_resort_family;
5040 const struct list *face_list;
5041 INT height, width = 0;
5042 unsigned int score = 0, new_score;
5043 signed int diff = 0, newdiff;
5044 BOOL bd, it, can_use_bitmap, want_vertical;
5045 LOGFONTW lf;
5046 CHARSETINFO csi;
5047 FMAT2 dcmat;
5048 FontSubst *psub = NULL;
5049 DC *dc = get_dc_ptr( dev->hdc );
5050 const SYSTEM_LINKS *font_link;
5052 if (!hfont) /* notification that the font has been changed by another driver */
5054 release_font( physdev->font );
5055 physdev->font = NULL;
5056 release_dc_ptr( dc );
5057 return 0;
5060 GetObjectW( hfont, sizeof(lf), &lf );
5061 lf.lfWidth = abs(lf.lfWidth);
5063 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5065 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5066 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5067 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5068 lf.lfEscapement);
5070 if(dc->GraphicsMode == GM_ADVANCED)
5072 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5073 /* Try to avoid not necessary glyph transformations */
5074 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5076 lf.lfHeight *= fabs(dcmat.eM11);
5077 lf.lfWidth *= fabs(dcmat.eM11);
5078 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5081 else
5083 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5084 font scaling abilities. */
5085 dcmat.eM11 = dcmat.eM22 = 1.0;
5086 dcmat.eM21 = dcmat.eM12 = 0;
5087 lf.lfOrientation = lf.lfEscapement;
5088 if (dc->vport2WorldValid)
5090 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5091 lf.lfOrientation = -lf.lfOrientation;
5092 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5093 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5097 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5098 dcmat.eM21, dcmat.eM22);
5100 GDI_CheckNotLock();
5101 EnterCriticalSection( &freetype_cs );
5103 /* check the cache first */
5104 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5105 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5106 goto done;
5109 TRACE("not in cache\n");
5110 ret = alloc_font();
5112 ret->font_desc.matrix = dcmat;
5113 ret->font_desc.lf = lf;
5114 ret->font_desc.can_use_bitmap = can_use_bitmap;
5115 calc_hash(&ret->font_desc);
5117 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5118 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5119 original value lfCharSet. Note this is a special case for
5120 Symbol and doesn't happen at least for "Wingdings*" */
5122 if(!strcmpiW(lf.lfFaceName, SymbolW))
5123 lf.lfCharSet = SYMBOL_CHARSET;
5125 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5126 switch(lf.lfCharSet) {
5127 case DEFAULT_CHARSET:
5128 csi.fs.fsCsb[0] = 0;
5129 break;
5130 default:
5131 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5132 csi.fs.fsCsb[0] = 0;
5133 break;
5137 family = NULL;
5138 if(lf.lfFaceName[0] != '\0') {
5139 CHILD_FONT *font_link_entry;
5140 LPWSTR FaceName = lf.lfFaceName;
5142 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5144 if(psub) {
5145 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5146 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5147 if (psub->to.charset != -1)
5148 lf.lfCharSet = psub->to.charset;
5151 /* We want a match on name and charset or just name if
5152 charset was DEFAULT_CHARSET. If the latter then
5153 we fixup the returned charset later in get_nearest_charset
5154 where we'll either use the charset of the current ansi codepage
5155 or if that's unavailable the first charset that the font supports.
5157 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5158 if (!strcmpiW(family->FamilyName, FaceName) ||
5159 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
5161 font_link = find_font_link(family->FamilyName);
5162 face_list = get_face_list_from_family(family);
5163 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5164 if (!(face->scalable || can_use_bitmap))
5165 continue;
5166 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5167 goto found;
5168 if (font_link != NULL &&
5169 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5170 goto found;
5171 if (!csi.fs.fsCsb[0])
5172 goto found;
5177 /* Search by full face name. */
5178 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5179 face_list = get_face_list_from_family(family);
5180 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5181 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
5182 (face->scalable || can_use_bitmap))
5184 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5185 goto found_face;
5186 font_link = find_font_link(family->FamilyName);
5187 if (font_link != NULL &&
5188 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5189 goto found_face;
5195 * Try check the SystemLink list first for a replacement font.
5196 * We may find good replacements there.
5198 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5200 if(!strcmpiW(font_link->font_name, FaceName) ||
5201 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
5203 TRACE("found entry in system list\n");
5204 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5206 const SYSTEM_LINKS *links;
5208 face = font_link_entry->face;
5209 if (!(face->scalable || can_use_bitmap))
5210 continue;
5211 family = face->family;
5212 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5213 goto found;
5214 links = find_font_link(family->FamilyName);
5215 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5216 goto found;
5222 psub = NULL; /* substitution is no more relevant */
5224 /* If requested charset was DEFAULT_CHARSET then try using charset
5225 corresponding to the current ansi codepage */
5226 if (!csi.fs.fsCsb[0])
5228 INT acp = GetACP();
5229 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5230 FIXME("TCI failed on codepage %d\n", acp);
5231 csi.fs.fsCsb[0] = 0;
5232 } else
5233 lf.lfCharSet = csi.ciCharset;
5236 want_vertical = (lf.lfFaceName[0] == '@');
5238 /* Face families are in the top 4 bits of lfPitchAndFamily,
5239 so mask with 0xF0 before testing */
5241 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5242 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5243 strcpyW(lf.lfFaceName, defFixed);
5244 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5245 strcpyW(lf.lfFaceName, defSerif);
5246 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5247 strcpyW(lf.lfFaceName, defSans);
5248 else
5249 strcpyW(lf.lfFaceName, defSans);
5250 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5251 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5252 font_link = find_font_link(family->FamilyName);
5253 face_list = get_face_list_from_family(family);
5254 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5255 if (!(face->scalable || can_use_bitmap))
5256 continue;
5257 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5258 goto found;
5259 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5260 goto found;
5265 last_resort_family = NULL;
5266 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5267 font_link = find_font_link(family->FamilyName);
5268 face_list = get_face_list_from_family(family);
5269 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5270 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5271 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5272 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5273 if(face->scalable)
5274 goto found;
5275 if(can_use_bitmap && !last_resort_family)
5276 last_resort_family = family;
5281 if(last_resort_family) {
5282 family = last_resort_family;
5283 csi.fs.fsCsb[0] = 0;
5284 goto found;
5287 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5288 face_list = get_face_list_from_family(family);
5289 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5290 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5291 csi.fs.fsCsb[0] = 0;
5292 WARN("just using first face for now\n");
5293 goto found;
5295 if(can_use_bitmap && !last_resort_family)
5296 last_resort_family = family;
5299 if(!last_resort_family) {
5300 FIXME("can't find a single appropriate font - bailing\n");
5301 free_font(ret);
5302 ret = NULL;
5303 goto done;
5306 WARN("could only find a bitmap font - this will probably look awful!\n");
5307 family = last_resort_family;
5308 csi.fs.fsCsb[0] = 0;
5310 found:
5311 it = lf.lfItalic ? 1 : 0;
5312 bd = lf.lfWeight > 550 ? 1 : 0;
5314 height = lf.lfHeight;
5316 face = best = best_bitmap = NULL;
5317 font_link = find_font_link(family->FamilyName);
5318 face_list = get_face_list_from_family(family);
5319 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5321 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5322 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5323 !csi.fs.fsCsb[0])
5325 BOOL italic, bold;
5327 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5328 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5329 new_score = (italic ^ it) + (bold ^ bd);
5330 if(!best || new_score <= score)
5332 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5333 italic, bold, it, bd);
5334 score = new_score;
5335 best = face;
5336 if(best->scalable && score == 0) break;
5337 if(!best->scalable)
5339 if(height > 0)
5340 newdiff = height - (signed int)(best->size.height);
5341 else
5342 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5343 if(!best_bitmap || new_score < score ||
5344 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5346 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5347 diff = newdiff;
5348 best_bitmap = best;
5349 if(score == 0 && diff == 0) break;
5355 if(best)
5356 face = best->scalable ? best : best_bitmap;
5357 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5358 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5360 found_face:
5361 height = lf.lfHeight;
5363 ret->fs = face->fs;
5365 if(csi.fs.fsCsb[0]) {
5366 ret->charset = lf.lfCharSet;
5367 ret->codepage = csi.ciACP;
5369 else
5370 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5372 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5373 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5375 ret->aveWidth = height ? lf.lfWidth : 0;
5377 if(!face->scalable) {
5378 /* Windows uses integer scaling factors for bitmap fonts */
5379 INT scale, scaled_height;
5380 GdiFont *cachedfont;
5382 /* FIXME: rotation of bitmap fonts is ignored */
5383 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5384 if (ret->aveWidth)
5385 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5386 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5387 dcmat.eM11 = dcmat.eM22 = 1.0;
5388 /* As we changed the matrix, we need to search the cache for the font again,
5389 * otherwise we might explode the cache. */
5390 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5391 TRACE("Found cached font after non-scalable matrix rescale!\n");
5392 free_font( ret );
5393 ret = cachedfont;
5394 goto done;
5396 calc_hash(&ret->font_desc);
5398 if (height != 0) height = diff;
5399 height += face->size.height;
5401 scale = (height + face->size.height - 1) / face->size.height;
5402 scaled_height = scale * face->size.height;
5403 /* Only jump to the next height if the difference <= 25% original height */
5404 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5405 /* The jump between unscaled and doubled is delayed by 1 */
5406 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5407 ret->scale_y = scale;
5409 width = face->size.x_ppem >> 6;
5410 height = face->size.y_ppem >> 6;
5412 else
5413 ret->scale_y = 1.0;
5414 TRACE("font scale y: %f\n", ret->scale_y);
5416 ret->ft_face = OpenFontFace(ret, face, width, height);
5418 if (!ret->ft_face)
5420 free_font( ret );
5421 ret = NULL;
5422 goto done;
5425 ret->ntmFlags = face->ntmFlags;
5427 pick_charmap( ret->ft_face, ret->charset );
5429 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5430 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5431 ret->underline = lf.lfUnderline ? 0xff : 0;
5432 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5433 create_child_font_list(ret);
5435 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5437 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5438 if (length != GDI_ERROR)
5440 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5441 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5442 TRACE("Loaded GSUB table of %i bytes\n",length);
5443 ret->vert_feature = get_GSUB_vert_feature(ret);
5444 if (!ret->vert_feature)
5446 TRACE("Vertical feature not found\n");
5447 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5448 ret->GSUB_Table = NULL;
5452 ret->aa_flags = HIWORD( face->flags );
5454 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5456 add_to_cache(ret);
5457 done:
5458 if (ret)
5460 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5462 switch (lf.lfQuality)
5464 case NONANTIALIASED_QUALITY:
5465 case ANTIALIASED_QUALITY:
5466 next->funcs->pSelectFont( dev, hfont, aa_flags );
5467 break;
5468 case CLEARTYPE_QUALITY:
5469 case CLEARTYPE_NATURAL_QUALITY:
5470 default:
5471 if (!*aa_flags) *aa_flags = ret->aa_flags;
5472 next->funcs->pSelectFont( dev, hfont, aa_flags );
5474 /* fixup the antialiasing flags for that font */
5475 switch (*aa_flags)
5477 case WINE_GGO_HRGB_BITMAP:
5478 case WINE_GGO_HBGR_BITMAP:
5479 case WINE_GGO_VRGB_BITMAP:
5480 case WINE_GGO_VBGR_BITMAP:
5481 if (is_subpixel_rendering_enabled()) break;
5482 *aa_flags = GGO_GRAY4_BITMAP;
5483 /* fall through */
5484 case GGO_GRAY2_BITMAP:
5485 case GGO_GRAY4_BITMAP:
5486 case GGO_GRAY8_BITMAP:
5487 case WINE_GGO_GRAY16_BITMAP:
5488 if (is_hinting_enabled())
5490 WORD gasp_flags;
5491 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5493 TRACE( "font %s %d aa disabled by GASP\n",
5494 debugstr_w(lf.lfFaceName), lf.lfHeight );
5495 *aa_flags = GGO_BITMAP;
5500 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5501 release_font( physdev->font );
5502 physdev->font = ret;
5504 LeaveCriticalSection( &freetype_cs );
5505 release_dc_ptr( dc );
5506 return ret ? hfont : 0;
5509 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5511 HRSRC rsrc;
5512 HGLOBAL hMem;
5513 WCHAR *p;
5514 int i;
5516 id += IDS_FIRST_SCRIPT;
5517 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5518 if (!rsrc) return 0;
5519 hMem = LoadResource( gdi32_module, rsrc );
5520 if (!hMem) return 0;
5522 p = LockResource( hMem );
5523 id &= 0x000f;
5524 while (id--) p += *p + 1;
5526 i = min(LF_FACESIZE - 1, *p);
5527 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5528 buffer[i] = 0;
5529 return i;
5532 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
5534 return (ansi_cp == 874 /* Thai */
5535 || ansi_cp == 1255 /* Hebrew */
5536 || ansi_cp == 1256 /* Arabic */
5540 /***************************************************
5541 * create_enum_charset_list
5543 * This function creates charset enumeration list because in DEFAULT_CHARSET
5544 * case, the ANSI codepage's charset takes precedence over other charsets.
5545 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5546 * This function works as a filter other than DEFAULT_CHARSET case.
5548 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5550 CHARSETINFO csi;
5551 DWORD n = 0;
5553 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5554 csi.fs.fsCsb[0] != 0) {
5555 list->element[n].mask = csi.fs.fsCsb[0];
5556 list->element[n].charset = csi.ciCharset;
5557 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5558 n++;
5560 else { /* charset is DEFAULT_CHARSET or invalid. */
5561 INT acp, i;
5562 DWORD mask = 0;
5564 /* Set the current codepage's charset as the first element. */
5565 acp = GetACP();
5566 if (!is_complex_script_ansi_cp(acp) &&
5567 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5568 csi.fs.fsCsb[0] != 0) {
5569 list->element[n].mask = csi.fs.fsCsb[0];
5570 list->element[n].charset = csi.ciCharset;
5571 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5572 mask |= csi.fs.fsCsb[0];
5573 n++;
5576 /* Fill out left elements. */
5577 for (i = 0; i < 32; i++) {
5578 FONTSIGNATURE fs;
5579 fs.fsCsb[0] = 1L << i;
5580 fs.fsCsb[1] = 0;
5581 if (fs.fsCsb[0] & mask)
5582 continue; /* skip, already added. */
5583 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5584 continue; /* skip, this is an invalid fsCsb bit. */
5586 list->element[n].mask = fs.fsCsb[0];
5587 list->element[n].charset = csi.ciCharset;
5588 load_script_name( i, list->element[n].name );
5589 mask |= fs.fsCsb[0];
5590 n++;
5593 /* add catch all mask for remaining bits */
5594 if (~mask)
5596 list->element[n].mask = ~mask;
5597 list->element[n].charset = DEFAULT_CHARSET;
5598 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5599 n++;
5602 list->total = n;
5604 return n;
5607 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5608 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5610 GdiFont *font;
5611 LONG width, height;
5613 if (face->cached_enum_data)
5615 TRACE("Cached\n");
5616 *pelf = face->cached_enum_data->elf;
5617 *pntm = face->cached_enum_data->ntm;
5618 *ptype = face->cached_enum_data->type;
5619 return;
5622 font = alloc_font();
5624 if(face->scalable) {
5625 height = 100;
5626 width = 0;
5627 } else {
5628 height = face->size.y_ppem >> 6;
5629 width = face->size.x_ppem >> 6;
5631 font->scale_y = 1.0;
5633 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5635 free_font(font);
5636 return;
5639 font->name = strdupW( family_name );
5640 font->ntmFlags = face->ntmFlags;
5642 if (get_outline_text_metrics(font))
5644 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5646 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5647 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5648 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5650 lstrcpynW(pelf->elfLogFont.lfFaceName,
5651 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5652 LF_FACESIZE);
5653 lstrcpynW(pelf->elfFullName,
5654 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5655 LF_FULLFACESIZE);
5656 lstrcpynW(pelf->elfStyle,
5657 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5658 LF_FACESIZE);
5660 else
5662 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5664 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5665 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5666 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5668 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5669 if (face->FullName)
5670 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5671 else
5672 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5673 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5676 pntm->ntmTm.ntmFlags = face->ntmFlags;
5677 pntm->ntmFontSig = face->fs;
5679 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5681 pelf->elfLogFont.lfEscapement = 0;
5682 pelf->elfLogFont.lfOrientation = 0;
5683 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5684 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5685 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5686 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5687 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5688 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5689 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5690 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5691 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5692 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5693 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5695 *ptype = 0;
5696 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5697 *ptype |= TRUETYPE_FONTTYPE;
5698 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5699 *ptype |= DEVICE_FONTTYPE;
5700 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5701 *ptype |= RASTER_FONTTYPE;
5703 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5704 if (face->cached_enum_data)
5706 face->cached_enum_data->elf = *pelf;
5707 face->cached_enum_data->ntm = *pntm;
5708 face->cached_enum_data->type = *ptype;
5711 free_font(font);
5714 static BOOL family_matches(Family *family, const WCHAR *face_name)
5716 Face *face;
5717 const struct list *face_list;
5719 if (!strcmpiW(face_name, family->FamilyName)) return TRUE;
5721 face_list = get_face_list_from_family(family);
5722 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5723 if (face->FullName && !strcmpiW(face_name, face->FullName)) return TRUE;
5725 return FALSE;
5728 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
5730 if (!strcmpiW(face_name, family_name)) return TRUE;
5732 return (face->FullName && !strcmpiW(face_name, face->FullName));
5735 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5736 FONTENUMPROCW proc, LPARAM lparam)
5738 ENUMLOGFONTEXW elf;
5739 NEWTEXTMETRICEXW ntm;
5740 DWORD type = 0;
5741 DWORD i;
5743 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5744 for(i = 0; i < list->total; i++) {
5745 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5746 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5747 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5748 i = list->total; /* break out of loop after enumeration */
5750 else
5752 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5753 /* use the DEFAULT_CHARSET case only if no other charset is present */
5754 if (list->element[i].charset == DEFAULT_CHARSET &&
5755 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5756 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5757 strcpyW(elf.elfScript, list->element[i].name);
5758 if (!elf.elfScript[0])
5759 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5761 /* Font Replacement */
5762 if (family != face->family)
5764 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5765 if (face->FullName)
5766 strcpyW(elf.elfFullName, face->FullName);
5767 else
5768 strcpyW(elf.elfFullName, family->FamilyName);
5770 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5771 debugstr_w(elf.elfLogFont.lfFaceName),
5772 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5773 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5774 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5775 ntm.ntmTm.ntmFlags);
5776 /* release section before callback (FIXME) */
5777 LeaveCriticalSection( &freetype_cs );
5778 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5779 EnterCriticalSection( &freetype_cs );
5781 return TRUE;
5784 /*************************************************************
5785 * freetype_EnumFonts
5787 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5789 Family *family;
5790 Face *face;
5791 const struct list *face_list;
5792 LOGFONTW lf;
5793 struct enum_charset_list enum_charsets;
5795 if (!plf)
5797 lf.lfCharSet = DEFAULT_CHARSET;
5798 lf.lfPitchAndFamily = 0;
5799 lf.lfFaceName[0] = 0;
5800 plf = &lf;
5803 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5805 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5807 GDI_CheckNotLock();
5808 EnterCriticalSection( &freetype_cs );
5809 if(plf->lfFaceName[0]) {
5810 WCHAR *face_name = plf->lfFaceName;
5811 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5813 if(psub) {
5814 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5815 debugstr_w(psub->to.name));
5816 face_name = psub->to.name;
5819 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5820 if (!family_matches(family, face_name)) continue;
5821 face_list = get_face_list_from_family(family);
5822 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5823 if (!face_matches(family->FamilyName, face, face_name)) continue;
5824 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5827 } else {
5828 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5829 face_list = get_face_list_from_family(family);
5830 face = LIST_ENTRY(list_head(face_list), Face, entry);
5831 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5834 LeaveCriticalSection( &freetype_cs );
5835 return TRUE;
5838 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5840 pt->x.value = vec->x >> 6;
5841 pt->x.fract = (vec->x & 0x3f) << 10;
5842 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5843 pt->y.value = vec->y >> 6;
5844 pt->y.fract = (vec->y & 0x3f) << 10;
5845 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5848 /***************************************************
5849 * According to the MSDN documentation on WideCharToMultiByte,
5850 * certain codepages cannot set the default_used parameter.
5851 * This returns TRUE if the codepage can set that parameter, false else
5852 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5854 static BOOL codepage_sets_default_used(UINT codepage)
5856 switch (codepage)
5858 case CP_UTF7:
5859 case CP_UTF8:
5860 case CP_SYMBOL:
5861 return FALSE;
5862 default:
5863 return TRUE;
5868 * GSUB Table handling functions
5871 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5873 const GSUB_CoverageFormat1* cf1;
5875 cf1 = table;
5877 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5879 int count = GET_BE_WORD(cf1->GlyphCount);
5880 int i;
5881 TRACE("Coverage Format 1, %i glyphs\n",count);
5882 for (i = 0; i < count; i++)
5883 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5884 return i;
5885 return -1;
5887 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5889 const GSUB_CoverageFormat2* cf2;
5890 int i;
5891 int count;
5892 cf2 = (const GSUB_CoverageFormat2*)cf1;
5894 count = GET_BE_WORD(cf2->RangeCount);
5895 TRACE("Coverage Format 2, %i ranges\n",count);
5896 for (i = 0; i < count; i++)
5898 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5899 return -1;
5900 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5901 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5903 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5904 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5907 return -1;
5909 else
5910 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5912 return -1;
5915 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5917 int i;
5918 int offset;
5919 const GSUB_LookupList *lookup;
5920 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5922 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5923 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5925 const GSUB_LookupTable *look;
5926 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5927 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5928 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5929 if (GET_BE_WORD(look->LookupType) != 1)
5930 FIXME("We only handle SubType 1\n");
5931 else
5933 int j;
5935 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5937 const GSUB_SingleSubstFormat1 *ssf1;
5938 offset = GET_BE_WORD(look->SubTable[j]);
5939 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5940 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5942 int offset = GET_BE_WORD(ssf1->Coverage);
5943 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5944 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5946 TRACE(" Glyph 0x%x ->",glyph);
5947 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5948 TRACE(" 0x%x\n",glyph);
5951 else
5953 const GSUB_SingleSubstFormat2 *ssf2;
5954 INT index;
5955 INT offset;
5957 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5958 offset = GET_BE_WORD(ssf1->Coverage);
5959 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5960 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5961 TRACE(" Coverage index %i\n",index);
5962 if (index != -1)
5964 TRACE(" Glyph is 0x%x ->",glyph);
5965 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5966 TRACE("0x%x\n",glyph);
5972 return glyph;
5976 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5978 const GSUB_Header *header;
5979 const GSUB_Feature *feature;
5981 if (!font->GSUB_Table)
5982 return glyph;
5984 header = font->GSUB_Table;
5985 feature = font->vert_feature;
5987 return GSUB_apply_feature(header, feature, glyph);
5990 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5992 FT_UInt glyphId;
5994 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5995 WCHAR wc = (WCHAR)glyph;
5996 BOOL default_used;
5997 BOOL *default_used_pointer;
5998 FT_UInt ret;
5999 char buf;
6000 default_used_pointer = NULL;
6001 default_used = FALSE;
6002 if (codepage_sets_default_used(font->codepage))
6003 default_used_pointer = &default_used;
6004 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6006 if (font->codepage == CP_SYMBOL && wc < 0x100)
6007 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6008 else
6009 ret = 0;
6011 else
6012 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6013 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6014 return ret;
6017 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6019 if (glyph < 0x100) glyph += 0xf000;
6020 /* there is a number of old pre-Unicode "broken" TTFs, which
6021 do have symbols at U+00XX instead of U+f0XX */
6022 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6023 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6025 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6027 return glyphId;
6030 /* helper for freetype_GetGlyphIndices */
6031 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6033 WCHAR wc = (WCHAR)glyph;
6034 BOOL default_used = FALSE;
6035 BOOL *default_used_pointer = NULL;
6036 FT_UInt ret;
6037 char buf;
6039 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6040 return get_glyph_index(font, glyph);
6042 if (codepage_sets_default_used(font->codepage))
6043 default_used_pointer = &default_used;
6044 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6045 || default_used)
6047 if (font->codepage == CP_SYMBOL && wc < 0x100)
6048 ret = (unsigned char)wc;
6049 else
6050 ret = 0;
6052 else
6053 ret = (unsigned char)buf;
6054 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6055 return ret;
6058 static FT_UInt get_default_char_index(GdiFont *font)
6060 FT_UInt default_char;
6062 if (FT_IS_SFNT(font->ft_face))
6064 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6065 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6067 else
6069 TEXTMETRICW textm;
6070 get_text_metrics(font, &textm);
6071 default_char = textm.tmDefaultChar;
6074 return default_char;
6077 /*************************************************************
6078 * freetype_GetGlyphIndices
6080 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6082 struct freetype_physdev *physdev = get_freetype_dev( dev );
6083 int i;
6084 WORD default_char;
6085 BOOL got_default = FALSE;
6087 if (!physdev->font)
6089 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6090 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6093 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6095 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6096 got_default = TRUE;
6099 GDI_CheckNotLock();
6100 EnterCriticalSection( &freetype_cs );
6102 for(i = 0; i < count; i++)
6104 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6105 if (pgi[i] == 0)
6107 if (!got_default)
6109 default_char = get_default_char_index(physdev->font);
6110 got_default = TRUE;
6112 pgi[i] = default_char;
6114 else
6115 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6117 LeaveCriticalSection( &freetype_cs );
6118 return count;
6121 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6123 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6124 return !memcmp(matrix, &identity, sizeof(FMAT2));
6127 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6129 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6130 return !memcmp(matrix, &identity, sizeof(MAT2));
6133 static void synthesize_bold_glyph(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6135 FT_Error err;
6136 static UINT once;
6138 switch(glyph->format) {
6139 case FT_GLYPH_FORMAT_OUTLINE:
6141 FT_Pos strength;
6142 FT_BBox bbox;
6143 if(!pFT_Outline_Embolden)
6144 break;
6146 strength = MulDiv(ppem, 1 << 6, 24);
6147 err = pFT_Outline_Embolden(&glyph->outline, strength);
6148 if(err) {
6149 TRACE("FT_Ouline_Embolden returns %d, ignored\n", err);
6150 break;
6153 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6154 metrics->width = bbox.xMax - bbox.xMin;
6155 metrics->height = bbox.yMax - bbox.yMin;
6156 metrics->horiBearingX = bbox.xMin;
6157 metrics->horiBearingY = bbox.yMax;
6158 metrics->horiAdvance += (1 << 6);
6159 metrics->vertAdvance += (1 << 6);
6160 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6161 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6162 break;
6164 default:
6165 if (!once++)
6166 WARN("Emboldening format 0x%x is not supported\n", glyph->format);
6167 return;
6171 static inline BYTE get_max_level( UINT format )
6173 switch( format )
6175 case GGO_GRAY2_BITMAP: return 4;
6176 case GGO_GRAY4_BITMAP: return 16;
6177 case GGO_GRAY8_BITMAP: return 64;
6179 return 255;
6182 extern const unsigned short vertical_orientation_table[];
6184 static BOOL check_unicode_tategaki(WCHAR uchar)
6186 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6188 /* We only reach this code if typographical substitution did not occur */
6189 /* Type: U or Type: Tu */
6190 return (orientation == 1 || orientation == 3);
6193 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6195 TTPOLYGONHEADER *pph;
6196 TTPOLYCURVE *ppc;
6197 unsigned int needed = 0, point = 0, contour, first_pt;
6198 unsigned int pph_start, cpfx;
6199 DWORD type;
6201 for (contour = 0; contour < outline->n_contours; contour++)
6203 /* Ignore contours containing one point */
6204 if (point == outline->contours[contour])
6206 point++;
6207 continue;
6210 pph_start = needed;
6211 pph = (TTPOLYGONHEADER *)(buf + needed);
6212 first_pt = point;
6213 if (buf)
6215 pph->dwType = TT_POLYGON_TYPE;
6216 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6218 needed += sizeof(*pph);
6219 point++;
6220 while (point <= outline->contours[contour])
6222 ppc = (TTPOLYCURVE *)(buf + needed);
6223 type = outline->tags[point] & FT_Curve_Tag_On ?
6224 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6225 cpfx = 0;
6228 if (buf)
6229 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6230 cpfx++;
6231 point++;
6232 } while (point <= outline->contours[contour] &&
6233 (outline->tags[point] & FT_Curve_Tag_On) ==
6234 (outline->tags[point-1] & FT_Curve_Tag_On));
6235 /* At the end of a contour Windows adds the start point, but
6236 only for Beziers */
6237 if (point > outline->contours[contour] &&
6238 !(outline->tags[point-1] & FT_Curve_Tag_On))
6240 if (buf)
6241 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6242 cpfx++;
6244 else if (point <= outline->contours[contour] &&
6245 outline->tags[point] & FT_Curve_Tag_On)
6247 /* add closing pt for bezier */
6248 if (buf)
6249 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6250 cpfx++;
6251 point++;
6253 if (buf)
6255 ppc->wType = type;
6256 ppc->cpfx = cpfx;
6258 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6260 if (buf)
6261 pph->cb = needed - pph_start;
6263 return needed;
6266 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
6268 /* Convert the quadratic Beziers to cubic Beziers.
6269 The parametric eqn for a cubic Bezier is, from PLRM:
6270 r(t) = at^3 + bt^2 + ct + r0
6271 with the control points:
6272 r1 = r0 + c/3
6273 r2 = r1 + (c + b)/3
6274 r3 = r0 + c + b + a
6276 A quadratic Bezier has the form:
6277 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6279 So equating powers of t leads to:
6280 r1 = 2/3 p1 + 1/3 p0
6281 r2 = 2/3 p1 + 1/3 p2
6282 and of course r0 = p0, r3 = p2
6284 int contour, point = 0, first_pt;
6285 TTPOLYGONHEADER *pph;
6286 TTPOLYCURVE *ppc;
6287 DWORD pph_start, cpfx, type;
6288 FT_Vector cubic_control[4];
6289 unsigned int needed = 0;
6291 for (contour = 0; contour < outline->n_contours; contour++)
6293 pph_start = needed;
6294 pph = (TTPOLYGONHEADER *)(buf + needed);
6295 first_pt = point;
6296 if (buf)
6298 pph->dwType = TT_POLYGON_TYPE;
6299 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6301 needed += sizeof(*pph);
6302 point++;
6303 while (point <= outline->contours[contour])
6305 ppc = (TTPOLYCURVE *)(buf + needed);
6306 type = outline->tags[point] & FT_Curve_Tag_On ?
6307 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6308 cpfx = 0;
6311 if (type == TT_PRIM_LINE)
6313 if (buf)
6314 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6315 cpfx++;
6316 point++;
6318 else
6320 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6321 so cpfx = 3n */
6323 /* FIXME: Possible optimization in endpoint calculation
6324 if there are two consecutive curves */
6325 cubic_control[0] = outline->points[point-1];
6326 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
6328 cubic_control[0].x += outline->points[point].x + 1;
6329 cubic_control[0].y += outline->points[point].y + 1;
6330 cubic_control[0].x >>= 1;
6331 cubic_control[0].y >>= 1;
6333 if (point+1 > outline->contours[contour])
6334 cubic_control[3] = outline->points[first_pt];
6335 else
6337 cubic_control[3] = outline->points[point+1];
6338 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
6340 cubic_control[3].x += outline->points[point].x + 1;
6341 cubic_control[3].y += outline->points[point].y + 1;
6342 cubic_control[3].x >>= 1;
6343 cubic_control[3].y >>= 1;
6346 /* r1 = 1/3 p0 + 2/3 p1
6347 r2 = 1/3 p2 + 2/3 p1 */
6348 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6349 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6350 cubic_control[2] = cubic_control[1];
6351 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6352 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6353 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6354 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6355 if (buf)
6357 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6358 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6359 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6361 cpfx += 3;
6362 point++;
6364 } while (point <= outline->contours[contour] &&
6365 (outline->tags[point] & FT_Curve_Tag_On) ==
6366 (outline->tags[point-1] & FT_Curve_Tag_On));
6367 /* At the end of a contour Windows adds the start point,
6368 but only for Beziers and we've already done that.
6370 if (point <= outline->contours[contour] &&
6371 outline->tags[point] & FT_Curve_Tag_On)
6373 /* This is the closing pt of a bezier, but we've already
6374 added it, so just inc point and carry on */
6375 point++;
6377 if (buf)
6379 ppc->wType = type;
6380 ppc->cpfx = cpfx;
6382 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6384 if (buf)
6385 pph->cb = needed - pph_start;
6387 return needed;
6390 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6392 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6393 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6394 const MAT2* lpmat)
6396 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6397 GLYPHMETRICS gm;
6398 FT_Face ft_face = incoming_font->ft_face;
6399 GdiFont *font = incoming_font;
6400 FT_Glyph_Metrics metrics;
6401 FT_UInt glyph_index;
6402 DWORD width, height, pitch, needed = 0;
6403 FT_Bitmap ft_bitmap;
6404 FT_Error err;
6405 INT left, right, top = 0, bottom = 0, adv;
6406 INT origin_x = 0, origin_y = 0;
6407 FT_Angle angle = 0;
6408 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6409 double widthRatio = 1.0;
6410 FT_Matrix transMat = identityMat;
6411 FT_Matrix transMatUnrotated;
6412 FT_Matrix transMatTategaki;
6413 BOOL needsTransform = FALSE;
6414 BOOL tategaki = (font->name[0] == '@');
6415 BOOL vertical_metrics;
6416 UINT original_index;
6417 LONG avgAdvance = 0;
6418 FT_Fixed em_scale;
6420 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6421 buflen, buf, lpmat);
6423 TRACE("font transform %f %f %f %f\n",
6424 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6425 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6427 if(format & GGO_GLYPH_INDEX) {
6428 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6429 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6430 as glyph index. "Treasure Adventure Game" depends on this. */
6431 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6432 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6433 } else
6434 glyph_index = glyph;
6435 original_index = glyph_index;
6436 format &= ~GGO_GLYPH_INDEX;
6437 /* TODO: Window also turns off tategaki for glyphs passed in by index
6438 if their unicode code points fall outside of the range that is
6439 rotated. */
6440 } else {
6441 BOOL vert;
6442 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6443 ft_face = font->ft_face;
6444 original_index = glyph_index;
6445 if (!vert && tategaki)
6446 tategaki = check_unicode_tategaki(glyph);
6449 if(format & GGO_UNHINTED) {
6450 load_flags |= FT_LOAD_NO_HINTING;
6451 format &= ~GGO_UNHINTED;
6454 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6455 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6456 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6457 font->gmsize * sizeof(GM*));
6458 } else {
6459 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6460 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6462 *lpgm = FONT_GM(font,original_index)->gm;
6463 *abc = FONT_GM(font,original_index)->abc;
6464 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6465 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6466 lpgm->gmCellIncX, lpgm->gmCellIncY);
6467 return 1; /* FIXME */
6471 if (!font->gm[original_index / GM_BLOCK_SIZE])
6472 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6474 /* Scaling factor */
6475 if (font->aveWidth)
6477 TEXTMETRICW tm;
6479 get_text_metrics(font, &tm);
6481 widthRatio = (double)font->aveWidth;
6482 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6484 else
6485 widthRatio = font->scale_y;
6487 /* Scaling transform */
6488 if (widthRatio != 1.0 || font->scale_y != 1.0)
6490 FT_Matrix scaleMat;
6491 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6492 scaleMat.xy = 0;
6493 scaleMat.yx = 0;
6494 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6496 pFT_Matrix_Multiply(&scaleMat, &transMat);
6497 needsTransform = TRUE;
6500 /* Slant transform */
6501 if (font->fake_italic) {
6502 FT_Matrix slantMat;
6504 slantMat.xx = (1 << 16);
6505 slantMat.xy = ((1 << 16) >> 2);
6506 slantMat.yx = 0;
6507 slantMat.yy = (1 << 16);
6508 pFT_Matrix_Multiply(&slantMat, &transMat);
6509 needsTransform = TRUE;
6512 /* Rotation transform */
6513 transMatUnrotated = transMat;
6514 transMatTategaki = transMat;
6515 if(font->orientation || tategaki) {
6516 FT_Matrix rotationMat;
6517 FT_Matrix taterotationMat;
6518 FT_Vector vecAngle;
6520 double orient = font->orientation / 10.0;
6521 double tate_orient = 0.f;
6523 if (tategaki)
6524 tate_orient = ((font->orientation+900)%3600)/10.0;
6525 else
6526 tate_orient = font->orientation/10.0;
6528 if (orient)
6530 angle = FT_FixedFromFloat(orient);
6531 pFT_Vector_Unit(&vecAngle, angle);
6532 rotationMat.xx = vecAngle.x;
6533 rotationMat.xy = -vecAngle.y;
6534 rotationMat.yx = -rotationMat.xy;
6535 rotationMat.yy = rotationMat.xx;
6537 pFT_Matrix_Multiply(&rotationMat, &transMat);
6540 if (tate_orient)
6542 angle = FT_FixedFromFloat(tate_orient);
6543 pFT_Vector_Unit(&vecAngle, angle);
6544 taterotationMat.xx = vecAngle.x;
6545 taterotationMat.xy = -vecAngle.y;
6546 taterotationMat.yx = -taterotationMat.xy;
6547 taterotationMat.yy = taterotationMat.xx;
6548 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6551 needsTransform = TRUE;
6554 /* World transform */
6555 if (!is_identity_FMAT2(&font->font_desc.matrix))
6557 FT_Matrix worldMat;
6558 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6559 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6560 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6561 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6562 pFT_Matrix_Multiply(&worldMat, &transMat);
6563 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6564 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6565 needsTransform = TRUE;
6568 /* Extra transformation specified by caller */
6569 if (!is_identity_MAT2(lpmat))
6571 FT_Matrix extraMat;
6572 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6573 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6574 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6575 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6576 pFT_Matrix_Multiply(&extraMat, &transMat);
6577 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6578 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6579 needsTransform = TRUE;
6582 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6583 /* there is a freetype bug where vertical metrics are only
6584 properly scaled and correct in 2.4.0 or greater */
6585 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6586 vertical_metrics = FALSE;
6588 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6589 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6591 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6593 if(err) {
6594 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6595 return GDI_ERROR;
6598 metrics = ft_face->glyph->metrics;
6599 if(font->fake_bold)
6600 synthesize_bold_glyph(ft_face->glyph, font->ppem, &metrics);
6602 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6603 * by the text metrics. The proper behavior is to clip the glyph metrics to
6604 * fit within the maximums specified in the text metrics. */
6605 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6606 get_bitmap_text_metrics(incoming_font)) {
6607 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6608 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6609 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6610 metrics.horiBearingY = top;
6611 metrics.height = top - bottom;
6613 /* TODO: Are we supposed to clip the width as well...? */
6614 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6617 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6619 if(FT_IS_SCALABLE(incoming_font->ft_face) && !font->fake_bold) {
6620 TEXTMETRICW tm;
6621 if (get_text_metrics(incoming_font, &tm) &&
6622 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6623 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6624 if (avgAdvance &&
6625 (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6626 TRACE("Fixed-pitch full-width character detected\n");
6627 else
6628 avgAdvance = 0; /* cancel this feature */
6632 if(!needsTransform) {
6633 left = (INT)(metrics.horiBearingX) & -64;
6634 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6635 if (!avgAdvance)
6636 adv = (INT)(metrics.horiAdvance + 63) >> 6;
6637 else
6638 adv = (INT)avgAdvance * 2;
6640 top = (metrics.horiBearingY + 63) & -64;
6641 bottom = (metrics.horiBearingY - metrics.height) & -64;
6642 gm.gmCellIncX = adv;
6643 gm.gmCellIncY = 0;
6644 origin_x = left;
6645 origin_y = top;
6646 abc->abcA = origin_x >> 6;
6647 abc->abcB = metrics.width >> 6;
6648 } else {
6649 INT xc, yc;
6650 FT_Vector vec;
6651 FT_Pos lsb;
6653 left = right = 0;
6655 for(xc = 0; xc < 2; xc++) {
6656 for(yc = 0; yc < 2; yc++) {
6657 vec.x = metrics.horiBearingX + xc * metrics.width;
6658 vec.y = metrics.horiBearingY - yc * metrics.height;
6659 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6660 pFT_Vector_Transform(&vec, &transMatTategaki);
6661 if(xc == 0 && yc == 0) {
6662 left = right = vec.x;
6663 top = bottom = vec.y;
6664 } else {
6665 if(vec.x < left) left = vec.x;
6666 else if(vec.x > right) right = vec.x;
6667 if(vec.y < bottom) bottom = vec.y;
6668 else if(vec.y > top) top = vec.y;
6672 left = left & -64;
6673 right = (right + 63) & -64;
6674 bottom = bottom & -64;
6675 top = (top + 63) & -64;
6677 if (tategaki && (font->potm || get_outline_text_metrics(font)))
6679 if (vertical_metrics)
6680 lsb = metrics.horiBearingY + metrics.vertBearingY;
6681 else
6682 lsb = metrics.vertAdvance + (font->potm->otmDescent << 6);
6683 vec.x = lsb;
6684 vec.y = font->potm->otmDescent << 6;
6685 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
6686 pFT_Vector_Transform(&vec, &transMat);
6687 origin_x = (vec.x + left) & -64;
6688 origin_y = (vec.y + top + 63) & -64;
6690 else
6692 origin_x = left;
6693 origin_y = top;
6694 lsb = metrics.horiBearingX;
6697 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6698 if (vertical_metrics)
6699 vec.x = metrics.vertAdvance;
6700 else
6701 vec.x = metrics.horiAdvance;
6702 vec.y = 0;
6703 pFT_Vector_Transform(&vec, &transMat);
6704 gm.gmCellIncY = -((vec.y+63) >> 6);
6705 if (!avgAdvance || vec.y)
6706 gm.gmCellIncX = (vec.x+63) >> 6;
6707 else {
6708 vec.x = incoming_font->ntmAvgWidth;
6709 vec.y = 0;
6710 pFT_Vector_Transform(&vec, &transMat);
6711 gm.gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6714 if (vertical_metrics)
6715 vec.x = metrics.vertAdvance;
6716 else
6717 vec.x = metrics.horiAdvance;
6718 vec.y = 0;
6719 pFT_Vector_Transform(&vec, &transMatUnrotated);
6720 if (!avgAdvance || vec.y)
6721 adv = (vec.x+63) >> 6;
6722 else {
6723 vec.x = incoming_font->ntmAvgWidth;
6724 vec.y = 0;
6725 pFT_Vector_Transform(&vec, &transMatUnrotated);
6726 adv = pFT_MulFix(vec.x, em_scale) * 2;
6729 vec.x = lsb;
6730 vec.y = 0;
6731 pFT_Vector_Transform(&vec, &transMatUnrotated);
6732 abc->abcA = vec.x >> 6;
6734 vec.x = metrics.width;
6735 vec.y = 0;
6736 pFT_Vector_Transform(&vec, &transMatUnrotated);
6737 if (vec.x >= 0)
6738 abc->abcB = vec.x >> 6;
6739 else
6740 abc->abcB = -vec.x >> 6;
6743 width = (right - left) >> 6;
6744 height = (top - bottom) >> 6;
6745 gm.gmBlackBoxX = width ? width : 1;
6746 gm.gmBlackBoxY = height ? height : 1;
6747 gm.gmptGlyphOrigin.x = origin_x >> 6;
6748 gm.gmptGlyphOrigin.y = origin_y >> 6;
6749 if (!abc->abcB) abc->abcB = 1;
6750 abc->abcC = adv - abc->abcA - abc->abcB;
6752 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
6753 wine_dbgstr_point(&gm.gmptGlyphOrigin),
6754 gm.gmCellIncX, gm.gmCellIncY);
6756 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6757 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6759 FONT_GM(font,original_index)->gm = gm;
6760 FONT_GM(font,original_index)->abc = *abc;
6761 FONT_GM(font,original_index)->init = TRUE;
6764 if(format == GGO_METRICS)
6766 *lpgm = gm;
6767 return 1; /* FIXME */
6770 if(ft_face->glyph->format != ft_glyph_format_outline &&
6771 (format == GGO_NATIVE || format == GGO_BEZIER))
6773 TRACE("loaded a bitmap\n");
6774 return GDI_ERROR;
6777 switch(format) {
6778 case GGO_BITMAP:
6779 pitch = ((width + 31) >> 5) << 2;
6780 needed = pitch * height;
6782 if(!buf || !buflen) break;
6783 if (!needed) return GDI_ERROR; /* empty glyph */
6784 if (needed > buflen)
6785 return GDI_ERROR;
6787 switch(ft_face->glyph->format) {
6788 case ft_glyph_format_bitmap:
6790 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6791 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
6792 INT h = min( height, ft_face->glyph->bitmap.rows );
6793 while(h--) {
6794 memcpy(dst, src, w);
6795 src += ft_face->glyph->bitmap.pitch;
6796 dst += pitch;
6798 break;
6801 case ft_glyph_format_outline:
6802 ft_bitmap.width = width;
6803 ft_bitmap.rows = height;
6804 ft_bitmap.pitch = pitch;
6805 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6806 ft_bitmap.buffer = buf;
6808 if(needsTransform)
6809 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6811 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6813 /* Note: FreeType will only set 'black' bits for us. */
6814 memset(buf, 0, needed);
6815 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6816 break;
6818 default:
6819 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6820 return GDI_ERROR;
6822 break;
6824 case GGO_GRAY2_BITMAP:
6825 case GGO_GRAY4_BITMAP:
6826 case GGO_GRAY8_BITMAP:
6827 case WINE_GGO_GRAY16_BITMAP:
6829 unsigned int max_level, row, col;
6830 BYTE *start, *ptr;
6832 pitch = (width + 3) / 4 * 4;
6833 needed = pitch * height;
6835 if(!buf || !buflen) break;
6836 if (!needed) return GDI_ERROR; /* empty glyph */
6837 if (needed > buflen)
6838 return GDI_ERROR;
6840 max_level = get_max_level( format );
6842 switch(ft_face->glyph->format) {
6843 case ft_glyph_format_bitmap:
6845 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6846 INT h = min( height, ft_face->glyph->bitmap.rows );
6847 INT x;
6848 memset( buf, 0, needed );
6849 while(h--) {
6850 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6851 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6852 src += ft_face->glyph->bitmap.pitch;
6853 dst += pitch;
6855 break;
6857 case ft_glyph_format_outline:
6859 ft_bitmap.width = width;
6860 ft_bitmap.rows = height;
6861 ft_bitmap.pitch = pitch;
6862 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6863 ft_bitmap.buffer = buf;
6865 if(needsTransform)
6866 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6868 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6870 memset(ft_bitmap.buffer, 0, buflen);
6872 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6874 if (max_level != 255)
6876 for (row = 0, start = buf; row < height; row++)
6878 for (col = 0, ptr = start; col < width; col++, ptr++)
6879 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6880 start += pitch;
6883 break;
6886 default:
6887 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6888 return GDI_ERROR;
6890 break;
6893 case WINE_GGO_HRGB_BITMAP:
6894 case WINE_GGO_HBGR_BITMAP:
6895 case WINE_GGO_VRGB_BITMAP:
6896 case WINE_GGO_VBGR_BITMAP:
6897 #ifdef FT_LCD_FILTER_H
6899 switch (ft_face->glyph->format)
6901 case FT_GLYPH_FORMAT_BITMAP:
6903 BYTE *src, *dst;
6904 INT src_pitch, x;
6906 pitch = width * 4;
6907 needed = pitch * height;
6909 if (!buf || !buflen) break;
6910 if (!needed) return GDI_ERROR; /* empty glyph */
6911 if (needed > buflen)
6912 return GDI_ERROR;
6914 memset(buf, 0, buflen);
6915 dst = buf;
6916 src = ft_face->glyph->bitmap.buffer;
6917 src_pitch = ft_face->glyph->bitmap.pitch;
6919 height = min( height, ft_face->glyph->bitmap.rows );
6920 while ( height-- )
6922 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6924 if ( src[x / 8] & masks[x % 8] )
6925 ((unsigned int *)dst)[x] = ~0u;
6927 src += src_pitch;
6928 dst += pitch;
6931 break;
6934 case FT_GLYPH_FORMAT_OUTLINE:
6936 unsigned int *dst;
6937 BYTE *src;
6938 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6939 INT x_shift, y_shift;
6940 BOOL rgb;
6941 FT_Render_Mode render_mode =
6942 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6943 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6945 if (!width || !height)
6947 if (!buf || !buflen) break;
6948 return GDI_ERROR;
6951 if ( render_mode == FT_RENDER_MODE_LCD)
6953 gm.gmBlackBoxX += 2;
6954 gm.gmptGlyphOrigin.x -= 1;
6955 left -= (1 << 6);
6957 else
6959 gm.gmBlackBoxY += 2;
6960 gm.gmptGlyphOrigin.y += 1;
6961 top += (1 << 6);
6964 width = gm.gmBlackBoxX;
6965 height = gm.gmBlackBoxY;
6966 pitch = width * 4;
6967 needed = pitch * height;
6969 if (!buf || !buflen) break;
6970 if (needed > buflen)
6971 return GDI_ERROR;
6973 memset(buf, 0, buflen);
6974 dst = buf;
6975 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6977 if ( needsTransform )
6978 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
6980 if ( pFT_Library_SetLcdFilter )
6981 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
6982 pFT_Render_Glyph (ft_face->glyph, render_mode);
6984 src = ft_face->glyph->bitmap.buffer;
6985 src_pitch = ft_face->glyph->bitmap.pitch;
6986 src_width = ft_face->glyph->bitmap.width;
6987 src_height = ft_face->glyph->bitmap.rows;
6989 if ( render_mode == FT_RENDER_MODE_LCD)
6991 rgb_interval = 1;
6992 hmul = 3;
6993 vmul = 1;
6995 else
6997 rgb_interval = src_pitch;
6998 hmul = 1;
6999 vmul = 3;
7002 x_shift = ft_face->glyph->bitmap_left - (left >> 6);
7003 if ( x_shift < 0 )
7005 src += hmul * -x_shift;
7006 src_width -= hmul * -x_shift;
7008 else if ( x_shift > 0 )
7010 dst += x_shift;
7011 width -= x_shift;
7014 y_shift = (top >> 6) - ft_face->glyph->bitmap_top;
7015 if ( y_shift < 0 )
7017 src += src_pitch * vmul * -y_shift;
7018 src_height -= vmul * -y_shift;
7020 else if ( y_shift > 0 )
7022 dst += y_shift * ( pitch / sizeof(*dst) );
7023 height -= y_shift;
7026 width = min( width, src_width / hmul );
7027 height = min( height, src_height / vmul );
7029 while ( height-- )
7031 for ( x = 0; x < width; x++ )
7033 if ( rgb )
7035 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
7036 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7037 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
7038 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7040 else
7042 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
7043 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
7044 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
7045 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
7048 src += src_pitch * vmul;
7049 dst += pitch / sizeof(*dst);
7052 break;
7055 default:
7056 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
7057 return GDI_ERROR;
7060 break;
7062 #else
7063 return GDI_ERROR;
7064 #endif
7066 case GGO_NATIVE:
7068 FT_Outline *outline = &ft_face->glyph->outline;
7070 if(buflen == 0) buf = NULL;
7072 if (needsTransform && buf)
7073 pFT_Outline_Transform(outline, &transMatTategaki);
7075 needed = get_native_glyph_outline(outline, buflen, NULL);
7077 if (!buf || !buflen)
7078 break;
7079 if (needed > buflen)
7080 return GDI_ERROR;
7082 get_native_glyph_outline(outline, buflen, buf);
7083 break;
7085 case GGO_BEZIER:
7087 FT_Outline *outline = &ft_face->glyph->outline;
7088 if(buflen == 0) buf = NULL;
7090 if (needsTransform && buf)
7091 pFT_Outline_Transform(outline, &transMat);
7093 needed = get_bezier_glyph_outline(outline, buflen, NULL);
7095 if (!buf || !buflen)
7096 break;
7097 if (needed > buflen)
7098 return GDI_ERROR;
7100 get_bezier_glyph_outline(outline, buflen, buf);
7101 break;
7104 default:
7105 FIXME("Unsupported format %d\n", format);
7106 return GDI_ERROR;
7108 *lpgm = gm;
7109 return needed;
7112 static BOOL get_bitmap_text_metrics(GdiFont *font)
7114 FT_Face ft_face = font->ft_face;
7115 FT_WinFNT_HeaderRec winfnt_header;
7116 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7117 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7118 font->potm->otmSize = size;
7120 #define TM font->potm->otmTextMetrics
7121 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7123 TM.tmHeight = winfnt_header.pixel_height;
7124 TM.tmAscent = winfnt_header.ascent;
7125 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7126 TM.tmInternalLeading = winfnt_header.internal_leading;
7127 TM.tmExternalLeading = winfnt_header.external_leading;
7128 TM.tmAveCharWidth = winfnt_header.avg_width;
7129 TM.tmMaxCharWidth = winfnt_header.max_width;
7130 TM.tmWeight = winfnt_header.weight;
7131 TM.tmOverhang = 0;
7132 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7133 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7134 TM.tmFirstChar = winfnt_header.first_char;
7135 TM.tmLastChar = winfnt_header.last_char;
7136 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7137 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7138 TM.tmItalic = winfnt_header.italic;
7139 TM.tmUnderlined = font->underline;
7140 TM.tmStruckOut = font->strikeout;
7141 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7142 TM.tmCharSet = winfnt_header.charset;
7144 else
7146 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7147 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7148 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7149 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7150 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7151 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7152 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7153 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7154 TM.tmOverhang = 0;
7155 TM.tmDigitizedAspectX = 96; /* FIXME */
7156 TM.tmDigitizedAspectY = 96; /* FIXME */
7157 TM.tmFirstChar = 1;
7158 TM.tmLastChar = 255;
7159 TM.tmDefaultChar = 32;
7160 TM.tmBreakChar = 32;
7161 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7162 TM.tmUnderlined = font->underline;
7163 TM.tmStruckOut = font->strikeout;
7164 /* NB inverted meaning of TMPF_FIXED_PITCH */
7165 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
7166 TM.tmCharSet = font->charset;
7168 #undef TM
7170 return TRUE;
7174 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7176 double scale_x, scale_y;
7178 if (font->aveWidth)
7180 scale_x = (double)font->aveWidth;
7181 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7183 else
7184 scale_x = font->scale_y;
7186 scale_x *= fabs(font->font_desc.matrix.eM11);
7187 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7189 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7190 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7192 SCALE_Y(ptm->tmHeight);
7193 SCALE_Y(ptm->tmAscent);
7194 SCALE_Y(ptm->tmDescent);
7195 SCALE_Y(ptm->tmInternalLeading);
7196 SCALE_Y(ptm->tmExternalLeading);
7197 SCALE_Y(ptm->tmOverhang);
7199 SCALE_X(ptm->tmAveCharWidth);
7200 SCALE_X(ptm->tmMaxCharWidth);
7202 #undef SCALE_X
7203 #undef SCALE_Y
7206 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7208 double scale_x, scale_y;
7210 if (font->aveWidth)
7212 scale_x = (double)font->aveWidth;
7213 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7215 else
7216 scale_x = font->scale_y;
7218 scale_x *= fabs(font->font_desc.matrix.eM11);
7219 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7221 scale_font_metrics(font, &potm->otmTextMetrics);
7223 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7224 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7226 SCALE_Y(potm->otmAscent);
7227 SCALE_Y(potm->otmDescent);
7228 SCALE_Y(potm->otmLineGap);
7229 SCALE_Y(potm->otmsCapEmHeight);
7230 SCALE_Y(potm->otmsXHeight);
7231 SCALE_Y(potm->otmrcFontBox.top);
7232 SCALE_Y(potm->otmrcFontBox.bottom);
7233 SCALE_X(potm->otmrcFontBox.left);
7234 SCALE_X(potm->otmrcFontBox.right);
7235 SCALE_Y(potm->otmMacAscent);
7236 SCALE_Y(potm->otmMacDescent);
7237 SCALE_Y(potm->otmMacLineGap);
7238 SCALE_X(potm->otmptSubscriptSize.x);
7239 SCALE_Y(potm->otmptSubscriptSize.y);
7240 SCALE_X(potm->otmptSubscriptOffset.x);
7241 SCALE_Y(potm->otmptSubscriptOffset.y);
7242 SCALE_X(potm->otmptSuperscriptSize.x);
7243 SCALE_Y(potm->otmptSuperscriptSize.y);
7244 SCALE_X(potm->otmptSuperscriptOffset.x);
7245 SCALE_Y(potm->otmptSuperscriptOffset.y);
7246 SCALE_Y(potm->otmsStrikeoutSize);
7247 SCALE_Y(potm->otmsStrikeoutPosition);
7248 SCALE_Y(potm->otmsUnderscoreSize);
7249 SCALE_Y(potm->otmsUnderscorePosition);
7251 #undef SCALE_X
7252 #undef SCALE_Y
7255 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7257 if(!font->potm)
7259 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7261 /* Make sure that the font has sane width/height ratio */
7262 if (font->aveWidth)
7264 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7266 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7267 font->aveWidth = 0;
7271 *ptm = font->potm->otmTextMetrics;
7272 scale_font_metrics(font, ptm);
7273 return TRUE;
7276 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7278 int i;
7280 for(i = 0; i < ft_face->num_charmaps; i++)
7282 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7283 return TRUE;
7285 return FALSE;
7288 static BOOL get_outline_text_metrics(GdiFont *font)
7290 BOOL ret = FALSE;
7291 FT_Face ft_face = font->ft_face;
7292 UINT needed, lenfam, lensty, lenface, lenfull;
7293 TT_OS2 *pOS2;
7294 TT_HoriHeader *pHori;
7295 TT_Postscript *pPost;
7296 FT_Fixed em_scale;
7297 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7298 char *cp;
7299 INT ascent, descent;
7301 TRACE("font=%p\n", font);
7303 if(!FT_IS_SCALABLE(ft_face))
7304 return FALSE;
7306 needed = sizeof(*font->potm);
7308 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7309 family_nameW = strdupW(font->name);
7311 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7312 if (!style_nameW)
7314 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7315 style_nameW = towstr( CP_ACP, ft_face->style_name );
7317 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7319 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7320 if (!face_nameW)
7322 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7323 face_nameW = strdupW(font->name);
7325 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7326 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7328 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7329 if (!full_nameW)
7331 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7332 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7333 full_nameW = strdupW(fake_nameW);
7335 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7337 /* These names should be read from the TT name table */
7339 /* length of otmpFamilyName */
7340 needed += lenfam;
7342 /* length of otmpFaceName */
7343 needed += lenface;
7345 /* length of otmpStyleName */
7346 needed += lensty;
7348 /* length of otmpFullName */
7349 needed += lenfull;
7352 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7354 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7355 if(!pOS2) {
7356 FIXME("Can't find OS/2 table - not TT font?\n");
7357 goto end;
7360 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7361 if(!pHori) {
7362 FIXME("Can't find HHEA table - not TT font?\n");
7363 goto end;
7366 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7368 TRACE("OS/2 winA = %d winD = %d 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",
7369 pOS2->usWinAscent, pOS2->usWinDescent,
7370 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7371 pOS2->xAvgCharWidth,
7372 ft_face->ascender, ft_face->descender, ft_face->height,
7373 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7374 ft_face->bbox.yMax, ft_face->bbox.yMin);
7376 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7377 font->potm->otmSize = needed;
7379 #define TM font->potm->otmTextMetrics
7381 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
7382 ascent = pHori->Ascender;
7383 descent = -pHori->Descender;
7384 } else {
7385 ascent = pOS2->usWinAscent;
7386 descent = pOS2->usWinDescent;
7389 font->ntmCellHeight = ascent + descent;
7390 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7392 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7393 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7395 if(font->yMax) {
7396 TM.tmAscent = font->yMax;
7397 TM.tmDescent = -font->yMin;
7398 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7399 } else {
7400 TM.tmAscent = SCALE_Y(ascent);
7401 TM.tmDescent = SCALE_Y(descent);
7402 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7405 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7407 /* MSDN says:
7408 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7410 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7411 ((ascent + descent) -
7412 (pHori->Ascender - pHori->Descender))));
7414 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7415 if (TM.tmAveCharWidth == 0) {
7416 TM.tmAveCharWidth = 1;
7418 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7419 TM.tmWeight = FW_REGULAR;
7420 if (font->fake_bold) {
7421 TM.tmAveCharWidth++;
7422 TM.tmMaxCharWidth++;
7423 TM.tmWeight = FW_BOLD;
7425 else
7427 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7429 if (pOS2->usWeightClass > FW_MEDIUM)
7430 TM.tmWeight = pOS2->usWeightClass;
7432 else if (pOS2->usWeightClass <= FW_MEDIUM)
7433 TM.tmWeight = pOS2->usWeightClass;
7435 TM.tmOverhang = 0;
7436 TM.tmDigitizedAspectX = 96; /* FIXME */
7437 TM.tmDigitizedAspectY = 96; /* FIXME */
7438 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7439 * symbol range to 0 - f0ff
7442 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7444 TM.tmFirstChar = 0;
7445 switch(GetACP())
7447 case 1255: /* Hebrew */
7448 TM.tmLastChar = 0xf896;
7449 break;
7450 case 1257: /* Baltic */
7451 TM.tmLastChar = 0xf8fd;
7452 break;
7453 default:
7454 TM.tmLastChar = 0xf0ff;
7456 TM.tmBreakChar = 0x20;
7457 TM.tmDefaultChar = 0x1f;
7459 else
7461 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7462 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7464 if(pOS2->usFirstCharIndex <= 1)
7465 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7466 else if (pOS2->usFirstCharIndex > 0xff)
7467 TM.tmBreakChar = 0x20;
7468 else
7469 TM.tmBreakChar = pOS2->usFirstCharIndex;
7470 TM.tmDefaultChar = TM.tmBreakChar - 1;
7472 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7473 TM.tmUnderlined = font->underline;
7474 TM.tmStruckOut = font->strikeout;
7476 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7477 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7478 (pOS2->version == 0xFFFFU ||
7479 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7480 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7481 else
7482 TM.tmPitchAndFamily = 0;
7484 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7486 case PAN_FAMILY_SCRIPT:
7487 TM.tmPitchAndFamily |= FF_SCRIPT;
7488 break;
7490 case PAN_FAMILY_DECORATIVE:
7491 TM.tmPitchAndFamily |= FF_DECORATIVE;
7492 break;
7494 case PAN_ANY:
7495 case PAN_NO_FIT:
7496 case PAN_FAMILY_TEXT_DISPLAY:
7497 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7498 /* which is clearly not what the panose spec says. */
7499 default:
7500 if(TM.tmPitchAndFamily == 0 || /* fixed */
7501 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7502 TM.tmPitchAndFamily = FF_MODERN;
7503 else
7505 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7507 case PAN_ANY:
7508 case PAN_NO_FIT:
7509 default:
7510 TM.tmPitchAndFamily |= FF_DONTCARE;
7511 break;
7513 case PAN_SERIF_COVE:
7514 case PAN_SERIF_OBTUSE_COVE:
7515 case PAN_SERIF_SQUARE_COVE:
7516 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7517 case PAN_SERIF_SQUARE:
7518 case PAN_SERIF_THIN:
7519 case PAN_SERIF_BONE:
7520 case PAN_SERIF_EXAGGERATED:
7521 case PAN_SERIF_TRIANGLE:
7522 TM.tmPitchAndFamily |= FF_ROMAN;
7523 break;
7525 case PAN_SERIF_NORMAL_SANS:
7526 case PAN_SERIF_OBTUSE_SANS:
7527 case PAN_SERIF_PERP_SANS:
7528 case PAN_SERIF_FLARED:
7529 case PAN_SERIF_ROUNDED:
7530 TM.tmPitchAndFamily |= FF_SWISS;
7531 break;
7534 break;
7537 if(FT_IS_SCALABLE(ft_face))
7538 TM.tmPitchAndFamily |= TMPF_VECTOR;
7540 if(FT_IS_SFNT(ft_face))
7542 if (font->ntmFlags & NTM_PS_OPENTYPE)
7543 TM.tmPitchAndFamily |= TMPF_DEVICE;
7544 else
7545 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7548 TM.tmCharSet = font->charset;
7550 font->potm->otmFiller = 0;
7551 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7552 font->potm->otmfsSelection = pOS2->fsSelection;
7553 font->potm->otmfsType = pOS2->fsType;
7554 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7555 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7556 font->potm->otmItalicAngle = 0; /* POST table */
7557 font->potm->otmEMSquare = ft_face->units_per_EM;
7558 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7559 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7560 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7561 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7562 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7563 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7564 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7565 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7566 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7567 font->potm->otmMacAscent = TM.tmAscent;
7568 font->potm->otmMacDescent = -TM.tmDescent;
7569 font->potm->otmMacLineGap = font->potm->otmLineGap;
7570 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7571 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7572 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7573 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7574 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7575 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7576 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7577 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7578 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7579 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7580 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7581 if(!pPost) {
7582 font->potm->otmsUnderscoreSize = 0;
7583 font->potm->otmsUnderscorePosition = 0;
7584 } else {
7585 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7586 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7588 #undef SCALE_X
7589 #undef SCALE_Y
7590 #undef TM
7592 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7593 cp = (char*)font->potm + sizeof(*font->potm);
7594 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7595 strcpyW((WCHAR*)cp, family_nameW);
7596 cp += lenfam;
7597 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7598 strcpyW((WCHAR*)cp, style_nameW);
7599 cp += lensty;
7600 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7601 strcpyW((WCHAR*)cp, face_nameW);
7602 cp += lenface;
7603 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7604 strcpyW((WCHAR*)cp, full_nameW);
7605 ret = TRUE;
7607 end:
7608 HeapFree(GetProcessHeap(), 0, style_nameW);
7609 HeapFree(GetProcessHeap(), 0, family_nameW);
7610 HeapFree(GetProcessHeap(), 0, face_nameW);
7611 HeapFree(GetProcessHeap(), 0, full_nameW);
7612 return ret;
7615 /*************************************************************
7616 * freetype_GetGlyphOutline
7618 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7619 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7621 struct freetype_physdev *physdev = get_freetype_dev( dev );
7622 DWORD ret;
7623 ABC abc;
7625 if (!physdev->font)
7627 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7628 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7631 GDI_CheckNotLock();
7632 EnterCriticalSection( &freetype_cs );
7633 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7634 LeaveCriticalSection( &freetype_cs );
7635 return ret;
7638 /*************************************************************
7639 * freetype_GetTextMetrics
7641 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7643 struct freetype_physdev *physdev = get_freetype_dev( dev );
7644 BOOL ret;
7646 if (!physdev->font)
7648 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7649 return dev->funcs->pGetTextMetrics( dev, metrics );
7652 GDI_CheckNotLock();
7653 EnterCriticalSection( &freetype_cs );
7654 ret = get_text_metrics( physdev->font, metrics );
7655 LeaveCriticalSection( &freetype_cs );
7656 return ret;
7659 /*************************************************************
7660 * freetype_GetOutlineTextMetrics
7662 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7664 struct freetype_physdev *physdev = get_freetype_dev( dev );
7665 UINT ret = 0;
7667 if (!physdev->font)
7669 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7670 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7673 TRACE("font=%p\n", physdev->font);
7675 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7677 GDI_CheckNotLock();
7678 EnterCriticalSection( &freetype_cs );
7680 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7682 if(cbSize >= physdev->font->potm->otmSize)
7684 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7685 scale_outline_font_metrics(physdev->font, potm);
7687 ret = physdev->font->potm->otmSize;
7689 LeaveCriticalSection( &freetype_cs );
7690 return ret;
7693 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7695 child->font = alloc_font();
7696 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7697 if(!child->font->ft_face)
7699 free_font(child->font);
7700 child->font = NULL;
7701 return FALSE;
7704 child->font->font_desc = font->font_desc;
7705 child->font->ntmFlags = child->face->ntmFlags;
7706 child->font->orientation = font->orientation;
7707 child->font->scale_y = font->scale_y;
7708 child->font->name = strdupW(child->face->family->FamilyName);
7709 child->font->base_font = font;
7710 TRACE("created child font %p for base %p\n", child->font, font);
7711 return TRUE;
7714 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
7716 FT_UInt g,o;
7717 CHILD_FONT *child_font;
7719 if(font->base_font)
7720 font = font->base_font;
7722 *linked_font = font;
7724 if((*glyph = get_glyph_index(font, c)))
7726 o = *glyph;
7727 *glyph = get_GSUB_vert_glyph(font, *glyph);
7728 *vert = (o != *glyph);
7729 return TRUE;
7732 if (c < 32) goto done; /* don't check linked fonts for control characters */
7734 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7736 if(!child_font->font)
7737 if(!load_child_font(font, child_font))
7738 continue;
7740 if(!child_font->font->ft_face)
7741 continue;
7742 g = get_glyph_index(child_font->font, c);
7743 o = g;
7744 g = get_GSUB_vert_glyph(child_font->font, g);
7745 if(g)
7747 *glyph = g;
7748 *linked_font = child_font->font;
7749 *vert = (o != g);
7750 return TRUE;
7754 done:
7755 *vert = FALSE;
7756 return FALSE;
7759 /*************************************************************
7760 * freetype_GetCharWidth
7762 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7764 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7765 UINT c;
7766 GLYPHMETRICS gm;
7767 ABC abc;
7768 struct freetype_physdev *physdev = get_freetype_dev( dev );
7770 if (!physdev->font)
7772 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7773 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7776 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7778 GDI_CheckNotLock();
7779 EnterCriticalSection( &freetype_cs );
7780 for(c = firstChar; c <= lastChar; c++) {
7781 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7782 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7784 LeaveCriticalSection( &freetype_cs );
7785 return TRUE;
7788 /*************************************************************
7789 * freetype_GetCharABCWidths
7791 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7793 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7794 UINT c;
7795 GLYPHMETRICS gm;
7796 struct freetype_physdev *physdev = get_freetype_dev( dev );
7798 if (!physdev->font)
7800 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7801 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7804 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7806 GDI_CheckNotLock();
7807 EnterCriticalSection( &freetype_cs );
7809 for(c = firstChar; c <= lastChar; c++, buffer++)
7810 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7812 LeaveCriticalSection( &freetype_cs );
7813 return TRUE;
7816 /*************************************************************
7817 * freetype_GetCharABCWidthsI
7819 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7821 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7822 UINT c;
7823 GLYPHMETRICS gm;
7824 struct freetype_physdev *physdev = get_freetype_dev( dev );
7826 if (!physdev->font)
7828 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7829 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7832 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7833 return FALSE;
7835 GDI_CheckNotLock();
7836 EnterCriticalSection( &freetype_cs );
7838 for(c = 0; c < count; c++, buffer++)
7839 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7840 &gm, buffer, 0, NULL, &identity );
7842 LeaveCriticalSection( &freetype_cs );
7843 return TRUE;
7846 /*************************************************************
7847 * freetype_GetTextExtentExPoint
7849 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7851 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7852 INT idx, pos;
7853 ABC abc;
7854 GLYPHMETRICS gm;
7855 struct freetype_physdev *physdev = get_freetype_dev( dev );
7857 if (!physdev->font)
7859 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7860 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7863 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7865 GDI_CheckNotLock();
7866 EnterCriticalSection( &freetype_cs );
7868 for (idx = pos = 0; idx < count; idx++)
7870 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7871 pos += abc.abcA + abc.abcB + abc.abcC;
7872 dxs[idx] = pos;
7875 LeaveCriticalSection( &freetype_cs );
7876 return TRUE;
7879 /*************************************************************
7880 * freetype_GetTextExtentExPointI
7882 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7884 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7885 INT idx, pos;
7886 ABC abc;
7887 GLYPHMETRICS gm;
7888 struct freetype_physdev *physdev = get_freetype_dev( dev );
7890 if (!physdev->font)
7892 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7893 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7896 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7898 GDI_CheckNotLock();
7899 EnterCriticalSection( &freetype_cs );
7901 for (idx = pos = 0; idx < count; idx++)
7903 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7904 &gm, &abc, 0, NULL, &identity );
7905 pos += abc.abcA + abc.abcB + abc.abcC;
7906 dxs[idx] = pos;
7909 LeaveCriticalSection( &freetype_cs );
7910 return TRUE;
7913 /*************************************************************
7914 * freetype_GetFontData
7916 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7918 struct freetype_physdev *physdev = get_freetype_dev( dev );
7920 if (!physdev->font)
7922 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7923 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7926 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7927 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7928 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7930 return get_font_data( physdev->font, table, offset, buf, cbData );
7933 /*************************************************************
7934 * freetype_GetTextFace
7936 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7938 INT n;
7939 struct freetype_physdev *physdev = get_freetype_dev( dev );
7941 if (!physdev->font)
7943 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7944 return dev->funcs->pGetTextFace( dev, count, str );
7947 n = strlenW(physdev->font->name) + 1;
7948 if (str)
7950 lstrcpynW(str, physdev->font->name, count);
7951 n = min(count, n);
7953 return n;
7956 /*************************************************************
7957 * freetype_GetTextCharsetInfo
7959 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7961 struct freetype_physdev *physdev = get_freetype_dev( dev );
7963 if (!physdev->font)
7965 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7966 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7968 if (fs) *fs = physdev->font->fs;
7969 return physdev->font->charset;
7972 /* Retrieve a list of supported Unicode ranges for a given font.
7973 * Can be called with NULL gs to calculate the buffer size. Returns
7974 * the number of ranges found.
7976 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7978 DWORD num_ranges = 0;
7980 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7982 FT_UInt glyph_code;
7983 FT_ULong char_code, char_code_prev;
7985 glyph_code = 0;
7986 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7988 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7989 face->num_glyphs, glyph_code, char_code);
7991 if (!glyph_code) return 0;
7993 if (gs)
7995 gs->ranges[0].wcLow = (USHORT)char_code;
7996 gs->ranges[0].cGlyphs = 0;
7997 gs->cGlyphsSupported = 0;
8000 num_ranges = 1;
8001 while (glyph_code)
8003 if (char_code < char_code_prev)
8005 ERR("expected increasing char code from FT_Get_Next_Char\n");
8006 return 0;
8008 if (char_code - char_code_prev > 1)
8010 num_ranges++;
8011 if (gs)
8013 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
8014 gs->ranges[num_ranges - 1].cGlyphs = 1;
8015 gs->cGlyphsSupported++;
8018 else if (gs)
8020 gs->ranges[num_ranges - 1].cGlyphs++;
8021 gs->cGlyphsSupported++;
8023 char_code_prev = char_code;
8024 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
8027 else
8028 FIXME("encoding %u not supported\n", face->charmap->encoding);
8030 return num_ranges;
8033 /*************************************************************
8034 * freetype_GetFontUnicodeRanges
8036 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
8038 struct freetype_physdev *physdev = get_freetype_dev( dev );
8039 DWORD size, num_ranges;
8041 if (!physdev->font)
8043 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
8044 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
8047 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
8048 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
8049 if (glyphset)
8051 glyphset->cbThis = size;
8052 glyphset->cRanges = num_ranges;
8053 glyphset->flAccel = 0;
8055 return size;
8058 /*************************************************************
8059 * freetype_FontIsLinked
8061 static BOOL freetype_FontIsLinked( PHYSDEV dev )
8063 struct freetype_physdev *physdev = get_freetype_dev( dev );
8064 BOOL ret;
8066 if (!physdev->font)
8068 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8069 return dev->funcs->pFontIsLinked( dev );
8072 GDI_CheckNotLock();
8073 EnterCriticalSection( &freetype_cs );
8074 ret = !list_empty(&physdev->font->child_fonts);
8075 LeaveCriticalSection( &freetype_cs );
8076 return ret;
8079 /*************************************************************************
8080 * GetRasterizerCaps (GDI32.@)
8082 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8084 lprs->nSize = sizeof(RASTERIZER_STATUS);
8085 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8086 lprs->nLanguageID = 0;
8087 return TRUE;
8090 /*************************************************************
8091 * freetype_GdiRealizationInfo
8093 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
8095 struct freetype_physdev *physdev = get_freetype_dev( dev );
8096 realization_info_t *info = ptr;
8098 if (!physdev->font)
8100 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
8101 return dev->funcs->pGdiRealizationInfo( dev, ptr );
8104 FIXME("(%p, %p): stub!\n", physdev->font, info);
8106 info->flags = 1;
8107 if(FT_IS_SCALABLE(physdev->font->ft_face))
8108 info->flags |= 2;
8110 info->cache_num = physdev->font->cache_num;
8111 info->unknown2 = -1;
8112 return TRUE;
8115 /*************************************************************************
8116 * Kerning support for TrueType fonts
8118 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8120 struct TT_kern_table
8122 USHORT version;
8123 USHORT nTables;
8126 struct TT_kern_subtable
8128 USHORT version;
8129 USHORT length;
8130 union
8132 USHORT word;
8133 struct
8135 USHORT horizontal : 1;
8136 USHORT minimum : 1;
8137 USHORT cross_stream: 1;
8138 USHORT override : 1;
8139 USHORT reserved1 : 4;
8140 USHORT format : 8;
8141 } bits;
8142 } coverage;
8145 struct TT_format0_kern_subtable
8147 USHORT nPairs;
8148 USHORT searchRange;
8149 USHORT entrySelector;
8150 USHORT rangeShift;
8153 struct TT_kern_pair
8155 USHORT left;
8156 USHORT right;
8157 short value;
8160 static DWORD parse_format0_kern_subtable(GdiFont *font,
8161 const struct TT_format0_kern_subtable *tt_f0_ks,
8162 const USHORT *glyph_to_char,
8163 KERNINGPAIR *kern_pair, DWORD cPairs)
8165 USHORT i, nPairs;
8166 const struct TT_kern_pair *tt_kern_pair;
8168 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8170 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8172 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8173 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8174 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8176 if (!kern_pair || !cPairs)
8177 return nPairs;
8179 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8181 nPairs = min(nPairs, cPairs);
8183 for (i = 0; i < nPairs; i++)
8185 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8186 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8187 /* this algorithm appears to better match what Windows does */
8188 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8189 if (kern_pair->iKernAmount < 0)
8191 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8192 kern_pair->iKernAmount -= font->ppem;
8194 else if (kern_pair->iKernAmount > 0)
8196 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8197 kern_pair->iKernAmount += font->ppem;
8199 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8201 TRACE("left %u right %u value %d\n",
8202 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8204 kern_pair++;
8206 TRACE("copied %u entries\n", nPairs);
8207 return nPairs;
8210 /*************************************************************
8211 * freetype_GetKerningPairs
8213 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8215 DWORD length;
8216 void *buf;
8217 const struct TT_kern_table *tt_kern_table;
8218 const struct TT_kern_subtable *tt_kern_subtable;
8219 USHORT i, nTables;
8220 USHORT *glyph_to_char;
8221 GdiFont *font;
8222 struct freetype_physdev *physdev = get_freetype_dev( dev );
8224 if (!(font = physdev->font))
8226 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8227 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8230 GDI_CheckNotLock();
8231 EnterCriticalSection( &freetype_cs );
8232 if (font->total_kern_pairs != (DWORD)-1)
8234 if (cPairs && kern_pair)
8236 cPairs = min(cPairs, font->total_kern_pairs);
8237 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8239 else cPairs = font->total_kern_pairs;
8241 LeaveCriticalSection( &freetype_cs );
8242 return cPairs;
8245 font->total_kern_pairs = 0;
8247 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8249 if (length == GDI_ERROR)
8251 TRACE("no kerning data in the font\n");
8252 LeaveCriticalSection( &freetype_cs );
8253 return 0;
8256 buf = HeapAlloc(GetProcessHeap(), 0, length);
8257 if (!buf)
8259 WARN("Out of memory\n");
8260 LeaveCriticalSection( &freetype_cs );
8261 return 0;
8264 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8266 /* build a glyph index to char code map */
8267 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8268 if (!glyph_to_char)
8270 WARN("Out of memory allocating a glyph index to char code map\n");
8271 HeapFree(GetProcessHeap(), 0, buf);
8272 LeaveCriticalSection( &freetype_cs );
8273 return 0;
8276 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8278 FT_UInt glyph_code;
8279 FT_ULong char_code;
8281 glyph_code = 0;
8282 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8284 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8285 font->ft_face->num_glyphs, glyph_code, char_code);
8287 while (glyph_code)
8289 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8291 /* FIXME: This doesn't match what Windows does: it does some fancy
8292 * things with duplicate glyph index to char code mappings, while
8293 * we just avoid overriding existing entries.
8295 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8296 glyph_to_char[glyph_code] = (USHORT)char_code;
8298 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8301 else
8303 ULONG n;
8305 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
8306 for (n = 0; n <= 65535; n++)
8307 glyph_to_char[n] = (USHORT)n;
8310 tt_kern_table = buf;
8311 nTables = GET_BE_WORD(tt_kern_table->nTables);
8312 TRACE("version %u, nTables %u\n",
8313 GET_BE_WORD(tt_kern_table->version), nTables);
8315 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8317 for (i = 0; i < nTables; i++)
8319 struct TT_kern_subtable tt_kern_subtable_copy;
8321 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8322 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8323 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8325 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8326 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8327 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8329 /* According to the TrueType specification this is the only format
8330 * that will be properly interpreted by Windows and OS/2
8332 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8334 DWORD new_chunk, old_total = font->total_kern_pairs;
8336 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8337 glyph_to_char, NULL, 0);
8338 font->total_kern_pairs += new_chunk;
8340 if (!font->kern_pairs)
8341 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8342 font->total_kern_pairs * sizeof(*font->kern_pairs));
8343 else
8344 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8345 font->total_kern_pairs * sizeof(*font->kern_pairs));
8347 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8348 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8350 else
8351 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8353 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8356 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8357 HeapFree(GetProcessHeap(), 0, buf);
8359 if (cPairs && kern_pair)
8361 cPairs = min(cPairs, font->total_kern_pairs);
8362 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8364 else cPairs = font->total_kern_pairs;
8366 LeaveCriticalSection( &freetype_cs );
8367 return cPairs;
8370 static const struct gdi_dc_funcs freetype_funcs =
8372 NULL, /* pAbortDoc */
8373 NULL, /* pAbortPath */
8374 NULL, /* pAlphaBlend */
8375 NULL, /* pAngleArc */
8376 NULL, /* pArc */
8377 NULL, /* pArcTo */
8378 NULL, /* pBeginPath */
8379 NULL, /* pBlendImage */
8380 NULL, /* pChord */
8381 NULL, /* pCloseFigure */
8382 NULL, /* pCreateCompatibleDC */
8383 freetype_CreateDC, /* pCreateDC */
8384 freetype_DeleteDC, /* pDeleteDC */
8385 NULL, /* pDeleteObject */
8386 NULL, /* pDeviceCapabilities */
8387 NULL, /* pEllipse */
8388 NULL, /* pEndDoc */
8389 NULL, /* pEndPage */
8390 NULL, /* pEndPath */
8391 freetype_EnumFonts, /* pEnumFonts */
8392 NULL, /* pEnumICMProfiles */
8393 NULL, /* pExcludeClipRect */
8394 NULL, /* pExtDeviceMode */
8395 NULL, /* pExtEscape */
8396 NULL, /* pExtFloodFill */
8397 NULL, /* pExtSelectClipRgn */
8398 NULL, /* pExtTextOut */
8399 NULL, /* pFillPath */
8400 NULL, /* pFillRgn */
8401 NULL, /* pFlattenPath */
8402 freetype_FontIsLinked, /* pFontIsLinked */
8403 NULL, /* pFrameRgn */
8404 NULL, /* pGdiComment */
8405 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
8406 NULL, /* pGetBoundsRect */
8407 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8408 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8409 freetype_GetCharWidth, /* pGetCharWidth */
8410 NULL, /* pGetDeviceCaps */
8411 NULL, /* pGetDeviceGammaRamp */
8412 freetype_GetFontData, /* pGetFontData */
8413 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8414 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8415 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8416 NULL, /* pGetICMProfile */
8417 NULL, /* pGetImage */
8418 freetype_GetKerningPairs, /* pGetKerningPairs */
8419 NULL, /* pGetNearestColor */
8420 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8421 NULL, /* pGetPixel */
8422 NULL, /* pGetSystemPaletteEntries */
8423 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8424 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8425 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8426 freetype_GetTextFace, /* pGetTextFace */
8427 freetype_GetTextMetrics, /* pGetTextMetrics */
8428 NULL, /* pGradientFill */
8429 NULL, /* pIntersectClipRect */
8430 NULL, /* pInvertRgn */
8431 NULL, /* pLineTo */
8432 NULL, /* pModifyWorldTransform */
8433 NULL, /* pMoveTo */
8434 NULL, /* pOffsetClipRgn */
8435 NULL, /* pOffsetViewportOrg */
8436 NULL, /* pOffsetWindowOrg */
8437 NULL, /* pPaintRgn */
8438 NULL, /* pPatBlt */
8439 NULL, /* pPie */
8440 NULL, /* pPolyBezier */
8441 NULL, /* pPolyBezierTo */
8442 NULL, /* pPolyDraw */
8443 NULL, /* pPolyPolygon */
8444 NULL, /* pPolyPolyline */
8445 NULL, /* pPolygon */
8446 NULL, /* pPolyline */
8447 NULL, /* pPolylineTo */
8448 NULL, /* pPutImage */
8449 NULL, /* pRealizeDefaultPalette */
8450 NULL, /* pRealizePalette */
8451 NULL, /* pRectangle */
8452 NULL, /* pResetDC */
8453 NULL, /* pRestoreDC */
8454 NULL, /* pRoundRect */
8455 NULL, /* pSaveDC */
8456 NULL, /* pScaleViewportExt */
8457 NULL, /* pScaleWindowExt */
8458 NULL, /* pSelectBitmap */
8459 NULL, /* pSelectBrush */
8460 NULL, /* pSelectClipPath */
8461 freetype_SelectFont, /* pSelectFont */
8462 NULL, /* pSelectPalette */
8463 NULL, /* pSelectPen */
8464 NULL, /* pSetArcDirection */
8465 NULL, /* pSetBkColor */
8466 NULL, /* pSetBkMode */
8467 NULL, /* pSetDCBrushColor */
8468 NULL, /* pSetDCPenColor */
8469 NULL, /* pSetDIBColorTable */
8470 NULL, /* pSetDIBitsToDevice */
8471 NULL, /* pSetDeviceClipping */
8472 NULL, /* pSetDeviceGammaRamp */
8473 NULL, /* pSetLayout */
8474 NULL, /* pSetMapMode */
8475 NULL, /* pSetMapperFlags */
8476 NULL, /* pSetPixel */
8477 NULL, /* pSetPolyFillMode */
8478 NULL, /* pSetROP2 */
8479 NULL, /* pSetRelAbs */
8480 NULL, /* pSetStretchBltMode */
8481 NULL, /* pSetTextAlign */
8482 NULL, /* pSetTextCharacterExtra */
8483 NULL, /* pSetTextColor */
8484 NULL, /* pSetTextJustification */
8485 NULL, /* pSetViewportExt */
8486 NULL, /* pSetViewportOrg */
8487 NULL, /* pSetWindowExt */
8488 NULL, /* pSetWindowOrg */
8489 NULL, /* pSetWorldTransform */
8490 NULL, /* pStartDoc */
8491 NULL, /* pStartPage */
8492 NULL, /* pStretchBlt */
8493 NULL, /* pStretchDIBits */
8494 NULL, /* pStrokeAndFillPath */
8495 NULL, /* pStrokePath */
8496 NULL, /* pUnrealizePalette */
8497 NULL, /* pWidenPath */
8498 NULL, /* wine_get_wgl_driver */
8499 GDI_PRIORITY_FONT_DRV /* priority */
8502 #else /* HAVE_FREETYPE */
8504 /*************************************************************************/
8506 BOOL WineEngInit(void)
8508 return FALSE;
8511 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8513 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8514 return 1;
8517 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8519 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8520 return TRUE;
8523 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8525 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8526 return NULL;
8529 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8530 LPCWSTR font_file, LPCWSTR font_path )
8532 FIXME("stub\n");
8533 return FALSE;
8536 /*************************************************************************
8537 * GetRasterizerCaps (GDI32.@)
8539 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8541 lprs->nSize = sizeof(RASTERIZER_STATUS);
8542 lprs->wFlags = 0;
8543 lprs->nLanguageID = 0;
8544 return TRUE;
8547 #endif /* HAVE_FREETYPE */