msi: Improve support for advertized shortcuts.
[wine.git] / dlls / gdi32 / freetype.c
blobfae9ffeac3dec71b303afc190c47b0283598af78
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 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
533 'F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 /****************************************
537 * Notes on .fon files
539 * The fonts System, FixedSys and Terminal are special. There are typically multiple
540 * versions installed for different resolutions and codepages. Windows stores which one to use
541 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
542 * Key Meaning
543 * FIXEDFON.FON FixedSys
544 * FONTS.FON System
545 * OEMFONT.FON Terminal
546 * LogPixels Current dpi set by the display control panel applet
547 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
548 * also has a LogPixels value that appears to mirror this)
550 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
551 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
552 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
553 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
554 * so that makes sense.
556 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
557 * to be mapped into the registry on Windows 2000 at least).
558 * I have
559 * woafont=app850.fon
560 * ega80woa.fon=ega80850.fon
561 * ega40woa.fon=ega40850.fon
562 * cga80woa.fon=cga80850.fon
563 * cga40woa.fon=cga40850.fon
566 /* These are all structures needed for the GSUB table */
568 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
570 typedef struct {
571 DWORD version;
572 WORD ScriptList;
573 WORD FeatureList;
574 WORD LookupList;
575 } GSUB_Header;
577 typedef struct {
578 CHAR ScriptTag[4];
579 WORD Script;
580 } GSUB_ScriptRecord;
582 typedef struct {
583 WORD ScriptCount;
584 GSUB_ScriptRecord ScriptRecord[1];
585 } GSUB_ScriptList;
587 typedef struct {
588 CHAR LangSysTag[4];
589 WORD LangSys;
590 } GSUB_LangSysRecord;
592 typedef struct {
593 WORD DefaultLangSys;
594 WORD LangSysCount;
595 GSUB_LangSysRecord LangSysRecord[1];
596 } GSUB_Script;
598 typedef struct {
599 WORD LookupOrder; /* Reserved */
600 WORD ReqFeatureIndex;
601 WORD FeatureCount;
602 WORD FeatureIndex[1];
603 } GSUB_LangSys;
605 typedef struct {
606 CHAR FeatureTag[4];
607 WORD Feature;
608 } GSUB_FeatureRecord;
610 typedef struct {
611 WORD FeatureCount;
612 GSUB_FeatureRecord FeatureRecord[1];
613 } GSUB_FeatureList;
615 typedef struct {
616 WORD FeatureParams; /* Reserved */
617 WORD LookupCount;
618 WORD LookupListIndex[1];
619 } GSUB_Feature;
621 typedef struct {
622 WORD LookupCount;
623 WORD Lookup[1];
624 } GSUB_LookupList;
626 typedef struct {
627 WORD LookupType;
628 WORD LookupFlag;
629 WORD SubTableCount;
630 WORD SubTable[1];
631 } GSUB_LookupTable;
633 typedef struct {
634 WORD CoverageFormat;
635 WORD GlyphCount;
636 WORD GlyphArray[1];
637 } GSUB_CoverageFormat1;
639 typedef struct {
640 WORD Start;
641 WORD End;
642 WORD StartCoverageIndex;
643 } GSUB_RangeRecord;
645 typedef struct {
646 WORD CoverageFormat;
647 WORD RangeCount;
648 GSUB_RangeRecord RangeRecord[1];
649 } GSUB_CoverageFormat2;
651 typedef struct {
652 WORD SubstFormat; /* = 1 */
653 WORD Coverage;
654 WORD DeltaGlyphID;
655 } GSUB_SingleSubstFormat1;
657 typedef struct {
658 WORD SubstFormat; /* = 2 */
659 WORD Coverage;
660 WORD GlyphCount;
661 WORD Substitute[1];
662 }GSUB_SingleSubstFormat2;
664 #ifdef HAVE_CARBON_CARBON_H
665 static char *find_cache_dir(void)
667 FSRef ref;
668 OSErr err;
669 static char cached_path[MAX_PATH];
670 static const char *wine = "/Wine", *fonts = "/Fonts";
672 if(*cached_path) return cached_path;
674 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
675 if(err != noErr)
677 WARN("can't create cached data folder\n");
678 return NULL;
680 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
681 if(err != noErr)
683 WARN("can't create cached data path\n");
684 *cached_path = '\0';
685 return NULL;
687 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
689 ERR("Could not create full path\n");
690 *cached_path = '\0';
691 return NULL;
693 strcat(cached_path, wine);
695 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
697 WARN("Couldn't mkdir %s\n", cached_path);
698 *cached_path = '\0';
699 return NULL;
701 strcat(cached_path, fonts);
702 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
704 WARN("Couldn't mkdir %s\n", cached_path);
705 *cached_path = '\0';
706 return NULL;
708 return cached_path;
711 /******************************************************************
712 * expand_mac_font
714 * Extracts individual TrueType font files from a Mac suitcase font
715 * and saves them into the user's caches directory (see
716 * find_cache_dir()).
717 * Returns a NULL terminated array of filenames.
719 * We do this because they are apps that try to read ttf files
720 * themselves and they don't like Mac suitcase files.
722 static char **expand_mac_font(const char *path)
724 FSRef ref;
725 SInt16 res_ref;
726 OSStatus s;
727 unsigned int idx;
728 const char *out_dir;
729 const char *filename;
730 int output_len;
731 struct {
732 char **array;
733 unsigned int size, max_size;
734 } ret;
736 TRACE("path %s\n", path);
738 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
739 if(s != noErr)
741 WARN("failed to get ref\n");
742 return NULL;
745 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
746 if(s != noErr)
748 TRACE("no data fork, so trying resource fork\n");
749 res_ref = FSOpenResFile(&ref, fsRdPerm);
750 if(res_ref == -1)
752 TRACE("unable to open resource fork\n");
753 return NULL;
757 ret.size = 0;
758 ret.max_size = 10;
759 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
760 if(!ret.array)
762 CloseResFile(res_ref);
763 return NULL;
766 out_dir = find_cache_dir();
768 filename = strrchr(path, '/');
769 if(!filename) filename = path;
770 else filename++;
772 /* output filename has the form out_dir/filename_%04x.ttf */
773 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
775 UseResFile(res_ref);
776 idx = 1;
777 while(1)
779 FamRec *fam_rec;
780 unsigned short *num_faces_ptr, num_faces, face;
781 AsscEntry *assoc;
782 Handle fond;
783 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
785 fond = Get1IndResource(fond_res, idx);
786 if(!fond) break;
787 TRACE("got fond resource %d\n", idx);
788 HLock(fond);
790 fam_rec = *(FamRec**)fond;
791 num_faces_ptr = (unsigned short *)(fam_rec + 1);
792 num_faces = GET_BE_WORD(*num_faces_ptr);
793 num_faces++;
794 assoc = (AsscEntry*)(num_faces_ptr + 1);
795 TRACE("num faces %04x\n", num_faces);
796 for(face = 0; face < num_faces; face++, assoc++)
798 Handle sfnt;
799 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
800 unsigned short size, font_id;
801 char *output;
803 size = GET_BE_WORD(assoc->fontSize);
804 font_id = GET_BE_WORD(assoc->fontID);
805 if(size != 0)
807 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
808 continue;
811 TRACE("trying to load sfnt id %04x\n", font_id);
812 sfnt = GetResource(sfnt_res, font_id);
813 if(!sfnt)
815 TRACE("can't get sfnt resource %04x\n", font_id);
816 continue;
819 output = HeapAlloc(GetProcessHeap(), 0, output_len);
820 if(output)
822 int fd;
824 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
826 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
827 if(fd != -1 || errno == EEXIST)
829 if(fd != -1)
831 unsigned char *sfnt_data;
833 HLock(sfnt);
834 sfnt_data = *(unsigned char**)sfnt;
835 write(fd, sfnt_data, GetHandleSize(sfnt));
836 HUnlock(sfnt);
837 close(fd);
839 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
841 ret.max_size *= 2;
842 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
844 ret.array[ret.size++] = output;
846 else
848 WARN("unable to create %s\n", output);
849 HeapFree(GetProcessHeap(), 0, output);
852 ReleaseResource(sfnt);
854 HUnlock(fond);
855 ReleaseResource(fond);
856 idx++;
858 CloseResFile(res_ref);
860 return ret.array;
863 #endif /* HAVE_CARBON_CARBON_H */
865 static inline BOOL is_win9x(void)
867 return GetVersion() & 0x80000000;
870 This function builds an FT_Fixed from a double. It fails if the absolute
871 value of the float number is greater than 32768.
873 static inline FT_Fixed FT_FixedFromFloat(double f)
875 return f * 0x10000;
879 This function builds an FT_Fixed from a FIXED. It simply put f.value
880 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
882 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
884 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
887 static BOOL is_hinting_enabled(void)
889 static int enabled = -1;
891 if (enabled == -1)
893 /* Use the >= 2.2.0 function if available */
894 if (pFT_Get_TrueType_Engine_Type)
896 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
897 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
899 else enabled = FALSE;
900 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
902 return enabled;
905 static BOOL is_subpixel_rendering_enabled( void )
907 #ifdef FT_LCD_FILTER_H
908 static int enabled = -1;
909 if (enabled == -1)
911 enabled = (pFT_Library_SetLcdFilter &&
912 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
913 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
915 return enabled;
916 #else
917 return FALSE;
918 #endif
922 static const struct list *get_face_list_from_family(const Family *family)
924 if (!list_empty(&family->faces))
925 return &family->faces;
926 else
927 return family->replacement;
930 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
932 Family *family;
933 Face *face;
934 const WCHAR *file;
936 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
938 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
940 const struct list *face_list;
941 if(face_name && strcmpiW(face_name, family->FamilyName))
942 continue;
943 face_list = get_face_list_from_family(family);
944 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
946 if (!face->file)
947 continue;
948 file = strrchrW(face->file, '/');
949 if(!file)
950 file = face->file;
951 else
952 file++;
953 if(strcmpiW(file, file_name)) continue;
954 face->refcount++;
955 return face;
958 return NULL;
961 static Family *find_family_from_name(const WCHAR *name)
963 Family *family;
965 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
967 if(!strcmpiW(family->FamilyName, name))
968 return family;
971 return NULL;
974 static Family *find_family_from_any_name(const WCHAR *name)
976 Family *family;
978 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
980 if(!strcmpiW(family->FamilyName, name))
981 return family;
982 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
983 return family;
986 return NULL;
989 static void DumpSubstList(void)
991 FontSubst *psub;
993 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
995 if(psub->from.charset != -1 || psub->to.charset != -1)
996 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
997 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
998 else
999 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1000 debugstr_w(psub->to.name));
1002 return;
1005 static LPWSTR strdupW(LPCWSTR p)
1007 LPWSTR ret;
1008 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1009 ret = HeapAlloc(GetProcessHeap(), 0, len);
1010 memcpy(ret, p, len);
1011 return ret;
1014 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1015 INT from_charset)
1017 FontSubst *element;
1019 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1021 if(!strcmpiW(element->from.name, from_name) &&
1022 (element->from.charset == from_charset ||
1023 element->from.charset == -1))
1024 return element;
1027 return NULL;
1030 #define ADD_FONT_SUBST_FORCE 1
1032 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1034 FontSubst *from_exist, *to_exist;
1036 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1038 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1040 list_remove(&from_exist->entry);
1041 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1042 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1043 HeapFree(GetProcessHeap(), 0, from_exist);
1044 from_exist = NULL;
1047 if(!from_exist)
1049 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1051 if(to_exist)
1053 HeapFree(GetProcessHeap(), 0, subst->to.name);
1054 subst->to.name = strdupW(to_exist->to.name);
1057 list_add_tail(subst_list, &subst->entry);
1059 return TRUE;
1062 HeapFree(GetProcessHeap(), 0, subst->from.name);
1063 HeapFree(GetProcessHeap(), 0, subst->to.name);
1064 HeapFree(GetProcessHeap(), 0, subst);
1065 return FALSE;
1068 static WCHAR *towstr(UINT cp, const char *str)
1070 int len;
1071 WCHAR *wstr;
1073 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1074 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1075 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1076 return wstr;
1079 static char *strWtoA(UINT cp, const WCHAR *str)
1081 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1082 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1083 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1084 return ret;
1087 static void split_subst_info(NameCs *nc, LPSTR str)
1089 CHAR *p = strrchr(str, ',');
1091 nc->charset = -1;
1092 if(p && *(p+1)) {
1093 nc->charset = strtol(p+1, NULL, 10);
1094 *p = '\0';
1096 nc->name = towstr(CP_ACP, str);
1099 static void LoadSubstList(void)
1101 FontSubst *psub;
1102 HKEY hkey;
1103 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1104 LPSTR value;
1105 LPVOID data;
1107 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1108 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1109 &hkey) == ERROR_SUCCESS) {
1111 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1112 &valuelen, &datalen, NULL, NULL);
1114 valuelen++; /* returned value doesn't include room for '\0' */
1115 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1116 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1118 dlen = datalen;
1119 vlen = valuelen;
1120 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1121 &dlen) == ERROR_SUCCESS) {
1122 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1124 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1125 split_subst_info(&psub->from, value);
1126 split_subst_info(&psub->to, data);
1128 /* Win 2000 doesn't allow mapping between different charsets
1129 or mapping of DEFAULT_CHARSET */
1130 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1131 psub->to.charset == DEFAULT_CHARSET) {
1132 HeapFree(GetProcessHeap(), 0, psub->to.name);
1133 HeapFree(GetProcessHeap(), 0, psub->from.name);
1134 HeapFree(GetProcessHeap(), 0, psub);
1135 } else {
1136 add_font_subst(&font_subst_list, psub, 0);
1138 /* reset dlen and vlen */
1139 dlen = datalen;
1140 vlen = valuelen;
1142 HeapFree(GetProcessHeap(), 0, data);
1143 HeapFree(GetProcessHeap(), 0, value);
1144 RegCloseKey(hkey);
1149 static const LANGID mac_langid_table[] =
1151 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
1152 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
1153 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
1154 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
1155 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
1156 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
1157 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
1158 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
1159 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
1160 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
1161 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
1162 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
1163 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
1164 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
1165 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
1166 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
1167 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
1168 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
1169 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
1170 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1171 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
1172 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
1173 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
1174 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
1175 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
1176 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
1177 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
1178 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
1179 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
1180 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
1181 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
1182 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
1183 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
1184 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1185 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
1186 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
1187 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
1188 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
1189 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
1190 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
1191 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
1192 0, /* TT_MAC_LANGID_YIDDISH */
1193 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
1194 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
1195 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
1196 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
1197 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
1198 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
1199 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
1200 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
1201 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1202 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
1203 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
1204 0, /* TT_MAC_LANGID_MOLDAVIAN */
1205 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
1206 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
1207 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
1208 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
1209 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1210 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
1211 0, /* TT_MAC_LANGID_KURDISH */
1212 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
1213 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
1214 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
1215 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
1216 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
1217 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
1218 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
1219 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
1220 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
1221 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
1222 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
1223 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
1224 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
1225 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
1226 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
1227 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
1228 0, /* TT_MAC_LANGID_BURMESE */
1229 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
1230 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
1231 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
1232 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
1233 0, /* TT_MAC_LANGID_TAGALOG */
1234 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1235 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1236 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
1237 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
1238 0, /* TT_MAC_LANGID_GALLA */
1239 0, /* TT_MAC_LANGID_SOMALI */
1240 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
1241 0, /* TT_MAC_LANGID_RUANDA */
1242 0, /* TT_MAC_LANGID_RUNDI */
1243 0, /* TT_MAC_LANGID_CHEWA */
1244 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
1245 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
1246 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1247 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1248 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
1249 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
1250 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
1251 0, /* TT_MAC_LANGID_LATIN */
1252 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
1253 0, /* TT_MAC_LANGID_GUARANI */
1254 0, /* TT_MAC_LANGID_AYMARA */
1255 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
1256 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
1257 0, /* TT_MAC_LANGID_DZONGKHA */
1258 0, /* TT_MAC_LANGID_JAVANESE */
1259 0, /* TT_MAC_LANGID_SUNDANESE */
1260 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
1261 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
1262 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
1263 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
1264 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1265 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
1266 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
1267 0, /* TT_MAC_LANGID_TONGAN */
1268 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1269 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
1270 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1273 static inline WORD get_mac_code_page( const FT_SfntName *name )
1275 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) return 10008; /* special case */
1276 return 10000 + name->encoding_id;
1279 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
1281 LANGID name_lang;
1282 int res = 0;
1284 switch (name->platform_id)
1286 case TT_PLATFORM_MICROSOFT:
1287 res += 5; /* prefer the Microsoft name */
1288 switch (name->encoding_id)
1290 case TT_MS_ID_UNICODE_CS:
1291 case TT_MS_ID_SYMBOL_CS:
1292 name_lang = name->language_id;
1293 break;
1294 default:
1295 return 0;
1297 break;
1298 case TT_PLATFORM_MACINTOSH:
1299 if (!IsValidCodePage( get_mac_code_page( name ))) return 0;
1300 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1301 name_lang = mac_langid_table[name->language_id];
1302 break;
1303 case TT_PLATFORM_APPLE_UNICODE:
1304 res += 2; /* prefer Unicode encodings */
1305 switch (name->encoding_id)
1307 case TT_APPLE_ID_DEFAULT:
1308 case TT_APPLE_ID_ISO_10646:
1309 case TT_APPLE_ID_UNICODE_2_0:
1310 if (name->language_id >= sizeof(mac_langid_table)/sizeof(mac_langid_table[0])) return 0;
1311 name_lang = mac_langid_table[name->language_id];
1312 break;
1313 default:
1314 return 0;
1316 break;
1317 default:
1318 return 0;
1320 if (name_lang == lang) res += 30;
1321 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
1322 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
1323 return res;
1326 static WCHAR *copy_name_table_string( const FT_SfntName *name )
1328 WCHAR *ret;
1329 WORD codepage;
1330 int i;
1332 switch (name->platform_id)
1334 case TT_PLATFORM_APPLE_UNICODE:
1335 case TT_PLATFORM_MICROSOFT:
1336 ret = HeapAlloc( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
1337 for (i = 0; i < name->string_len / 2; i++)
1338 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
1339 ret[i] = 0;
1340 return ret;
1341 case TT_PLATFORM_MACINTOSH:
1342 codepage = get_mac_code_page( name );
1343 i = MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, NULL, 0 );
1344 ret = HeapAlloc( GetProcessHeap(), 0, (i + 1) * sizeof(WCHAR) );
1345 MultiByteToWideChar( codepage, 0, (char *)name->string, name->string_len, ret, i );
1346 ret[i] = 0;
1347 return ret;
1349 return NULL;
1352 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
1354 FT_SfntName name;
1355 FT_UInt num_names, name_index;
1356 int res, best_lang = 0, best_index = -1;
1358 if (!FT_IS_SFNT(ft_face)) return NULL;
1360 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
1362 for (name_index = 0; name_index < num_names; name_index++)
1364 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
1365 if (name.name_id != name_id) continue;
1366 res = match_name_table_language( &name, language_id );
1367 if (res > best_lang)
1369 best_lang = res;
1370 best_index = name_index;
1374 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
1376 WCHAR *ret = copy_name_table_string( &name );
1377 TRACE( "name %u found platform %u lang %04x %s\n",
1378 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
1379 return ret;
1381 return NULL;
1384 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1386 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1387 if (f1->scalable) return TRUE;
1388 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1389 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1392 static void release_family( Family *family )
1394 if (--family->refcount) return;
1395 assert( list_empty( &family->faces ));
1396 list_remove( &family->entry );
1397 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1398 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1399 HeapFree( GetProcessHeap(), 0, family );
1402 static void release_face( Face *face )
1404 if (--face->refcount) return;
1405 if (face->family)
1407 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1408 list_remove( &face->entry );
1409 release_family( face->family );
1411 HeapFree( GetProcessHeap(), 0, face->file );
1412 HeapFree( GetProcessHeap(), 0, face->StyleName );
1413 HeapFree( GetProcessHeap(), 0, face->FullName );
1414 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1415 HeapFree( GetProcessHeap(), 0, face );
1418 static inline int style_order(const Face *face)
1420 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1422 case NTM_REGULAR:
1423 return 0;
1424 case NTM_BOLD:
1425 return 1;
1426 case NTM_ITALIC:
1427 return 2;
1428 case NTM_BOLD | NTM_ITALIC:
1429 return 3;
1430 default:
1431 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1432 debugstr_w(face->family->FamilyName),
1433 debugstr_w(face->StyleName),
1434 face->ntmFlags);
1435 return 9999;
1439 static BOOL insert_face_in_family_list( Face *face, Family *family )
1441 Face *cursor;
1443 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1445 if (faces_equal( face, cursor ))
1447 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1448 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1449 cursor->font_version, face->font_version);
1451 if (face->file && face->dev == cursor->dev && face->ino == cursor->ino)
1453 cursor->refcount++;
1454 TRACE("Font %s already in list, refcount now %d\n",
1455 debugstr_w(face->file), cursor->refcount);
1456 return FALSE;
1458 if (face->font_version <= cursor->font_version)
1460 TRACE("Original font %s is newer so skipping %s\n",
1461 debugstr_w(cursor->file), debugstr_w(face->file));
1462 return FALSE;
1464 else
1466 TRACE("Replacing original %s with %s\n",
1467 debugstr_w(cursor->file), debugstr_w(face->file));
1468 list_add_before( &cursor->entry, &face->entry );
1469 face->family = family;
1470 family->refcount++;
1471 face->refcount++;
1472 release_face( cursor );
1473 return TRUE;
1476 else
1477 TRACE("Adding new %s\n", debugstr_w(face->file));
1479 if (style_order( face ) < style_order( cursor )) break;
1482 list_add_before( &cursor->entry, &face->entry );
1483 face->family = family;
1484 family->refcount++;
1485 face->refcount++;
1486 return TRUE;
1489 /****************************************************************
1490 * NB This function stores the ptrs to the strings to save copying.
1491 * Don't free them after calling.
1493 static Family *create_family( WCHAR *name, WCHAR *english_name )
1495 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1496 family->refcount = 1;
1497 family->FamilyName = name;
1498 family->EnglishName = english_name;
1499 list_init( &family->faces );
1500 family->replacement = &family->faces;
1501 list_add_tail( &font_list, &family->entry );
1503 return family;
1506 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1508 DWORD type, size = sizeof(DWORD);
1510 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1511 type != REG_DWORD || size != sizeof(DWORD))
1513 *data = 0;
1514 return ERROR_BAD_CONFIGURATION;
1516 return ERROR_SUCCESS;
1519 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1521 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1524 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1526 DWORD needed, strike_index = 0;
1527 HKEY hkey_strike;
1529 /* If we have a File Name key then this is a real font, not just the parent
1530 key of a bunch of non-scalable strikes */
1531 needed = buffer_size;
1532 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1534 Face *face;
1535 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1536 face->cached_enum_data = NULL;
1537 face->family = NULL;
1539 face->refcount = 1;
1540 face->file = strdupW( buffer );
1541 face->StyleName = strdupW(face_name);
1543 needed = buffer_size;
1544 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1545 face->FullName = strdupW( buffer );
1546 else
1547 face->FullName = NULL;
1549 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1550 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1551 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1552 reg_load_dword(hkey_face, face_flags_value, (DWORD*)&face->flags);
1554 needed = sizeof(face->fs);
1555 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1557 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1559 face->scalable = TRUE;
1560 memset(&face->size, 0, sizeof(face->size));
1562 else
1564 face->scalable = FALSE;
1565 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1566 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1567 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1568 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1569 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1571 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1572 face->size.height, face->size.width, face->size.size >> 6,
1573 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1576 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1577 face->fs.fsCsb[0], face->fs.fsCsb[1],
1578 face->fs.fsUsb[0], face->fs.fsUsb[1],
1579 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1581 if (insert_face_in_family_list(face, family))
1582 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1584 release_face( face );
1587 /* load bitmap strikes */
1589 needed = buffer_size;
1590 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1592 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1594 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1595 RegCloseKey(hkey_strike);
1597 needed = buffer_size;
1601 /* move vertical fonts after their horizontal counterpart */
1602 /* assumes that font_list is already sorted by family name */
1603 static void reorder_vertical_fonts(void)
1605 Family *family, *next, *vert_family;
1606 struct list *ptr, *vptr;
1607 struct list vertical_families = LIST_INIT( vertical_families );
1609 LIST_FOR_EACH_ENTRY_SAFE( family, next, &font_list, Family, entry )
1611 if (family->FamilyName[0] != '@') continue;
1612 list_remove( &family->entry );
1613 list_add_tail( &vertical_families, &family->entry );
1616 ptr = list_head( &font_list );
1617 vptr = list_head( &vertical_families );
1618 while (ptr && vptr)
1620 family = LIST_ENTRY( ptr, Family, entry );
1621 vert_family = LIST_ENTRY( vptr, Family, entry );
1622 if (strcmpiW( family->FamilyName, vert_family->FamilyName + 1 ) > 0)
1624 list_remove( vptr );
1625 list_add_before( ptr, vptr );
1626 vptr = list_head( &vertical_families );
1628 else ptr = list_next( &font_list, ptr );
1630 list_move_tail( &font_list, &vertical_families );
1633 static void load_font_list_from_cache(HKEY hkey_font_cache)
1635 DWORD size, family_index = 0;
1636 Family *family;
1637 HKEY hkey_family;
1638 WCHAR buffer[4096];
1640 size = sizeof(buffer);
1641 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1643 WCHAR *english_family = NULL;
1644 WCHAR *family_name = strdupW( buffer );
1645 DWORD face_index = 0;
1647 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1648 TRACE("opened family key %s\n", debugstr_w(family_name));
1649 size = sizeof(buffer);
1650 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1651 english_family = strdupW( buffer );
1653 family = create_family(family_name, english_family);
1655 if(english_family)
1657 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1658 subst->from.name = strdupW(english_family);
1659 subst->from.charset = -1;
1660 subst->to.name = strdupW(family_name);
1661 subst->to.charset = -1;
1662 add_font_subst(&font_subst_list, subst, 0);
1665 size = sizeof(buffer);
1666 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1668 WCHAR *face_name = strdupW( buffer );
1669 HKEY hkey_face;
1671 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1673 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1674 RegCloseKey(hkey_face);
1676 HeapFree( GetProcessHeap(), 0, face_name );
1677 size = sizeof(buffer);
1679 RegCloseKey(hkey_family);
1680 release_family( family );
1681 size = sizeof(buffer);
1684 reorder_vertical_fonts();
1687 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1689 LONG ret;
1690 HKEY hkey_wine_fonts;
1692 /* We don't want to create the fonts key as volatile, so open this first */
1693 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1694 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1695 if(ret != ERROR_SUCCESS)
1697 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1698 return ret;
1701 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1702 KEY_ALL_ACCESS, NULL, hkey, disposition);
1703 RegCloseKey(hkey_wine_fonts);
1704 return ret;
1707 static void add_face_to_cache(Face *face)
1709 HKEY hkey_family, hkey_face;
1710 WCHAR *face_key_name;
1712 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1713 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1714 if(face->family->EnglishName)
1715 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1716 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1718 if(face->scalable)
1719 face_key_name = face->StyleName;
1720 else
1722 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1723 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1724 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1726 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1727 &hkey_face, NULL);
1728 if(!face->scalable)
1729 HeapFree(GetProcessHeap(), 0, face_key_name);
1731 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1732 (strlenW(face->file) + 1) * sizeof(WCHAR));
1733 if (face->FullName)
1734 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1735 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1737 reg_save_dword(hkey_face, face_index_value, face->face_index);
1738 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1739 reg_save_dword(hkey_face, face_version_value, face->font_version);
1740 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1742 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1744 if(!face->scalable)
1746 reg_save_dword(hkey_face, face_height_value, face->size.height);
1747 reg_save_dword(hkey_face, face_width_value, face->size.width);
1748 reg_save_dword(hkey_face, face_size_value, face->size.size);
1749 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1750 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1751 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1753 RegCloseKey(hkey_face);
1754 RegCloseKey(hkey_family);
1757 static void remove_face_from_cache( Face *face )
1759 HKEY hkey_family;
1761 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1763 if (face->scalable)
1765 RegDeleteKeyW( hkey_family, face->StyleName );
1767 else
1769 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1770 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1771 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1772 RegDeleteKeyW( hkey_family, face_key_name );
1773 HeapFree(GetProcessHeap(), 0, face_key_name);
1775 RegCloseKey(hkey_family);
1778 static WCHAR *prepend_at(WCHAR *family)
1780 WCHAR *str;
1782 if (!family)
1783 return NULL;
1785 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1786 str[0] = '@';
1787 strcpyW(str + 1, family);
1788 HeapFree(GetProcessHeap(), 0, family);
1789 return str;
1792 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1794 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT) );
1795 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1797 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1798 if (!*name)
1800 *name = *english;
1801 *english = NULL;
1803 else if (!strcmpiW( *name, *english ))
1805 HeapFree( GetProcessHeap(), 0, *english );
1806 *english = NULL;
1809 if (vertical)
1811 *name = prepend_at( *name );
1812 *english = prepend_at( *english );
1816 static Family *get_family( FT_Face ft_face, BOOL vertical )
1818 Family *family;
1819 WCHAR *name, *english_name;
1821 get_family_names( ft_face, &name, &english_name, vertical );
1823 family = find_family_from_name( name );
1825 if (!family)
1827 family = create_family( name, english_name );
1828 if (english_name)
1830 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1831 subst->from.name = strdupW( english_name );
1832 subst->from.charset = -1;
1833 subst->to.name = strdupW( name );
1834 subst->to.charset = -1;
1835 add_font_subst( &font_subst_list, subst, 0 );
1838 else
1840 HeapFree( GetProcessHeap(), 0, name );
1841 HeapFree( GetProcessHeap(), 0, english_name );
1842 family->refcount++;
1845 return family;
1848 static inline FT_Fixed get_font_version( FT_Face ft_face )
1850 FT_Fixed version = 0;
1851 TT_Header *header;
1853 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1854 if (header) version = header->Font_Revision;
1856 return version;
1859 static inline DWORD get_ntm_flags( FT_Face ft_face )
1861 DWORD flags = 0;
1862 FT_ULong table_size = 0;
1864 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1865 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1866 if (flags == 0) flags = NTM_REGULAR;
1868 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1869 flags |= NTM_PS_OPENTYPE;
1871 return flags;
1874 static inline void get_bitmap_size( FT_Face ft_face, Bitmap_Size *face_size )
1876 My_FT_Bitmap_Size *size;
1877 FT_WinFNT_HeaderRec winfnt_header;
1879 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1880 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1881 size->height, size->width, size->size >> 6,
1882 size->x_ppem >> 6, size->y_ppem >> 6);
1883 face_size->height = size->height;
1884 face_size->width = size->width;
1885 face_size->size = size->size;
1886 face_size->x_ppem = size->x_ppem;
1887 face_size->y_ppem = size->y_ppem;
1889 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
1890 face_size->internal_leading = winfnt_header.internal_leading;
1891 if (winfnt_header.external_leading > 0 &&
1892 (face_size->height ==
1893 winfnt_header.pixel_height + winfnt_header.external_leading))
1894 face_size->height = winfnt_header.pixel_height;
1898 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1900 TT_OS2 *os2;
1901 FT_UInt dummy;
1902 CHARSETINFO csi;
1903 FT_WinFNT_HeaderRec winfnt_header;
1904 int i;
1906 memset( fs, 0, sizeof(*fs) );
1908 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1909 if (os2)
1911 fs->fsUsb[0] = os2->ulUnicodeRange1;
1912 fs->fsUsb[1] = os2->ulUnicodeRange2;
1913 fs->fsUsb[2] = os2->ulUnicodeRange3;
1914 fs->fsUsb[3] = os2->ulUnicodeRange4;
1916 if (os2->version == 0)
1918 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1919 fs->fsCsb[0] = FS_LATIN1;
1920 else
1921 fs->fsCsb[0] = FS_SYMBOL;
1923 else
1925 fs->fsCsb[0] = os2->ulCodePageRange1;
1926 fs->fsCsb[1] = os2->ulCodePageRange2;
1929 else
1931 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1933 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1934 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1935 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1936 *fs = csi.fs;
1940 if (fs->fsCsb[0] == 0)
1942 /* let's see if we can find any interesting cmaps */
1943 for (i = 0; i < ft_face->num_charmaps; i++)
1945 switch (ft_face->charmaps[i]->encoding)
1947 case FT_ENCODING_UNICODE:
1948 case FT_ENCODING_APPLE_ROMAN:
1949 fs->fsCsb[0] |= FS_LATIN1;
1950 break;
1951 case FT_ENCODING_MS_SYMBOL:
1952 fs->fsCsb[0] |= FS_SYMBOL;
1953 break;
1954 default:
1955 break;
1961 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1962 DWORD flags )
1964 struct stat st;
1965 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1967 face->refcount = 1;
1968 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1969 if (!face->StyleName) face->StyleName = towstr( CP_ACP, ft_face->style_name );
1971 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1972 if (flags & ADDFONT_VERTICAL_FONT)
1973 face->FullName = prepend_at( face->FullName );
1975 face->dev = 0;
1976 face->ino = 0;
1977 if (file)
1979 face->file = towstr( CP_UNIXCP, file );
1980 face->font_data_ptr = NULL;
1981 face->font_data_size = 0;
1982 if (!stat( file, &st ))
1984 face->dev = st.st_dev;
1985 face->ino = st.st_ino;
1988 else
1990 face->file = NULL;
1991 face->font_data_ptr = font_data_ptr;
1992 face->font_data_size = font_data_size;
1995 face->face_index = face_index;
1996 get_fontsig( ft_face, &face->fs );
1997 face->ntmFlags = get_ntm_flags( ft_face );
1998 face->font_version = get_font_version( ft_face );
2000 if (FT_IS_SCALABLE( ft_face ))
2002 memset( &face->size, 0, sizeof(face->size) );
2003 face->scalable = TRUE;
2005 else
2007 get_bitmap_size( ft_face, &face->size );
2008 face->scalable = FALSE;
2011 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
2012 face->flags = flags;
2013 face->family = NULL;
2014 face->cached_enum_data = NULL;
2016 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2017 face->fs.fsCsb[0], face->fs.fsCsb[1],
2018 face->fs.fsUsb[0], face->fs.fsUsb[1],
2019 face->fs.fsUsb[2], face->fs.fsUsb[3]);
2021 return face;
2024 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
2025 FT_Long face_index, DWORD flags )
2027 Face *face;
2028 Family *family;
2030 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
2031 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
2032 if (insert_face_in_family_list( face, family ))
2034 if (flags & ADDFONT_ADD_TO_CACHE)
2035 add_face_to_cache( face );
2037 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
2038 debugstr_w(face->StyleName));
2040 release_face( face );
2041 release_family( family );
2044 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
2045 FT_Long face_index, BOOL allow_bitmap )
2047 FT_Error err;
2048 TT_OS2 *pOS2;
2049 FT_Face ft_face;
2051 if (file)
2053 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
2054 err = pFT_New_Face(library, file, face_index, &ft_face);
2056 else
2058 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
2059 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
2062 if (err != 0)
2064 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
2065 return NULL;
2068 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2069 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
2071 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
2072 goto fail;
2075 if (!FT_IS_SFNT( ft_face ))
2077 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
2079 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
2080 goto fail;
2083 else
2085 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
2086 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
2087 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
2089 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2090 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
2091 goto fail;
2094 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2095 we don't want to load these. */
2096 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
2098 FT_ULong len = 0;
2100 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
2102 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
2103 goto fail;
2108 if (!ft_face->family_name || !ft_face->style_name)
2110 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
2111 goto fail;
2114 return ft_face;
2115 fail:
2116 pFT_Done_Face( ft_face );
2117 return NULL;
2120 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
2122 FT_Face ft_face;
2123 FT_Long face_index = 0, num_faces;
2124 INT ret = 0;
2126 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2127 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
2129 #ifdef HAVE_CARBON_CARBON_H
2130 if(file)
2132 char **mac_list = expand_mac_font(file);
2133 if(mac_list)
2135 BOOL had_one = FALSE;
2136 char **cursor;
2137 for(cursor = mac_list; *cursor; cursor++)
2139 had_one = TRUE;
2140 AddFontToList(*cursor, NULL, 0, flags);
2141 HeapFree(GetProcessHeap(), 0, *cursor);
2143 HeapFree(GetProcessHeap(), 0, mac_list);
2144 if(had_one)
2145 return 1;
2148 #endif /* HAVE_CARBON_CARBON_H */
2150 do {
2151 const DWORD FS_DBCS_MASK = FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
2152 FONTSIGNATURE fs;
2154 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
2155 if (!ft_face) return 0;
2157 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
2159 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
2160 pFT_Done_Face(ft_face);
2161 return 0;
2164 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
2165 ++ret;
2167 get_fontsig(ft_face, &fs);
2168 if (fs.fsCsb[0] & FS_DBCS_MASK)
2170 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
2171 flags | ADDFONT_VERTICAL_FONT);
2172 ++ret;
2175 num_faces = ft_face->num_faces;
2176 pFT_Done_Face(ft_face);
2177 } while(num_faces > ++face_index);
2178 return ret;
2181 static int remove_font_resource( const char *file, DWORD flags )
2183 Family *family, *family_next;
2184 Face *face, *face_next;
2185 struct stat st;
2186 int count = 0;
2188 if (stat( file, &st ) == -1) return 0;
2189 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2191 family->refcount++;
2192 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2194 if (!face->file) continue;
2195 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2196 if (st.st_dev == face->dev && st.st_ino == face->ino)
2198 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2199 release_face( face );
2200 count++;
2203 release_family( family );
2205 return count;
2208 static void DumpFontList(void)
2210 Family *family;
2211 Face *face;
2213 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2214 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2215 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2216 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2217 if(!face->scalable)
2218 TRACE(" %d", face->size.height);
2219 TRACE("\n");
2222 return;
2225 /***********************************************************
2226 * The replacement list is a way to map an entire font
2227 * family onto another family. For example adding
2229 * [HKCU\Software\Wine\Fonts\Replacements]
2230 * "Wingdings"="Winedings"
2232 * would enumerate the Winedings font both as Winedings and
2233 * Wingdings. However if a real Wingdings font is present the
2234 * replacement does not take place.
2237 static void LoadReplaceList(void)
2239 HKEY hkey;
2240 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2241 LPWSTR value;
2242 LPVOID data;
2244 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2245 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2247 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2248 &valuelen, &datalen, NULL, NULL);
2250 valuelen++; /* returned value doesn't include room for '\0' */
2251 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2252 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2254 dlen = datalen;
2255 vlen = valuelen;
2256 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2257 &dlen) == ERROR_SUCCESS) {
2258 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2259 /* "NewName"="Oldname" */
2260 if(!find_family_from_any_name(value))
2262 Family * const family = find_family_from_any_name(data);
2263 if (family != NULL)
2265 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2266 if (new_family != NULL)
2268 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2269 new_family->FamilyName = strdupW(value);
2270 new_family->EnglishName = NULL;
2271 list_init(&new_family->faces);
2272 new_family->replacement = &family->faces;
2273 list_add_tail(&font_list, &new_family->entry);
2276 else
2278 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2281 else
2283 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2285 /* reset dlen and vlen */
2286 dlen = datalen;
2287 vlen = valuelen;
2289 HeapFree(GetProcessHeap(), 0, data);
2290 HeapFree(GetProcessHeap(), 0, value);
2291 RegCloseKey(hkey);
2295 static const WCHAR *font_links_list[] =
2297 Lucida_Sans_Unicode,
2298 Microsoft_Sans_Serif,
2299 Tahoma
2302 static const struct font_links_defaults_list
2304 /* Keyed off substitution for "MS Shell Dlg" */
2305 const WCHAR *shelldlg;
2306 /* Maximum of four substitutes, plus terminating NULL pointer */
2307 const WCHAR *substitutes[5];
2308 } font_links_defaults_list[] =
2310 /* Non East-Asian */
2311 { Tahoma, /* FIXME unverified ordering */
2312 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2314 /* Below lists are courtesy of
2315 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2317 /* Japanese */
2318 { MS_UI_Gothic,
2319 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2321 /* Chinese Simplified */
2322 { SimSun,
2323 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2325 /* Korean */
2326 { Gulim,
2327 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2329 /* Chinese Traditional */
2330 { PMingLiU,
2331 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2336 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2338 SYSTEM_LINKS *font_link;
2340 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2342 if(!strcmpiW(font_link->font_name, name))
2343 return font_link;
2346 return NULL;
2349 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2351 const WCHAR *value;
2352 int i;
2353 FontSubst *psub;
2354 Family *family;
2355 Face *face;
2356 const WCHAR *file;
2358 if (values)
2360 SYSTEM_LINKS *font_link;
2362 psub = get_font_subst(&font_subst_list, name, -1);
2363 /* Don't store fonts that are only substitutes for other fonts */
2364 if(psub)
2366 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2367 return;
2370 font_link = find_font_link(name);
2371 if (font_link == NULL)
2373 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2374 font_link->font_name = strdupW(name);
2375 list_init(&font_link->links);
2376 list_add_tail(&system_links, &font_link->entry);
2379 memset(&font_link->fs, 0, sizeof font_link->fs);
2380 for (i = 0; values[i] != NULL; i++)
2382 const struct list *face_list;
2383 CHILD_FONT *child_font;
2385 value = values[i];
2386 if (!strcmpiW(name,value))
2387 continue;
2388 psub = get_font_subst(&font_subst_list, value, -1);
2389 if(psub)
2390 value = psub->to.name;
2391 family = find_family_from_name(value);
2392 if (!family)
2393 continue;
2394 file = NULL;
2395 /* Use first extant filename for this Family */
2396 face_list = get_face_list_from_family(family);
2397 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2399 if (!face->file)
2400 continue;
2401 file = strrchrW(face->file, '/');
2402 if (!file)
2403 file = face->file;
2404 else
2405 file++;
2406 break;
2408 if (!file)
2409 continue;
2410 face = find_face_from_filename(file, value);
2411 if(!face)
2413 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2414 continue;
2417 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2418 child_font->face = face;
2419 child_font->font = NULL;
2420 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2421 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2422 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2423 child_font->face->face_index);
2424 list_add_tail(&font_link->links, &child_font->entry);
2426 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2432 /*************************************************************
2433 * init_system_links
2435 static BOOL init_system_links(void)
2437 HKEY hkey;
2438 BOOL ret = FALSE;
2439 DWORD type, max_val, max_data, val_len, data_len, index;
2440 WCHAR *value, *data;
2441 WCHAR *entry, *next;
2442 SYSTEM_LINKS *font_link, *system_font_link;
2443 CHILD_FONT *child_font;
2444 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2445 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2446 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2447 Face *face;
2448 FontSubst *psub;
2449 UINT i, j;
2451 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2453 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2454 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2455 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2456 val_len = max_val + 1;
2457 data_len = max_data;
2458 index = 0;
2459 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2461 psub = get_font_subst(&font_subst_list, value, -1);
2462 /* Don't store fonts that are only substitutes for other fonts */
2463 if(psub)
2465 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2466 goto next;
2468 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2469 font_link->font_name = strdupW(value);
2470 memset(&font_link->fs, 0, sizeof font_link->fs);
2471 list_init(&font_link->links);
2472 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2474 WCHAR *face_name;
2475 CHILD_FONT *child_font;
2477 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2479 next = entry + strlenW(entry) + 1;
2481 face_name = strchrW(entry, ',');
2482 if(face_name)
2484 *face_name++ = 0;
2485 while(isspaceW(*face_name))
2486 face_name++;
2488 psub = get_font_subst(&font_subst_list, face_name, -1);
2489 if(psub)
2490 face_name = psub->to.name;
2492 face = find_face_from_filename(entry, face_name);
2493 if(!face)
2495 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2496 continue;
2499 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2500 child_font->face = face;
2501 child_font->font = NULL;
2502 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2503 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2504 TRACE("Adding file %s index %ld\n",
2505 debugstr_w(child_font->face->file), child_font->face->face_index);
2506 list_add_tail(&font_link->links, &child_font->entry);
2508 list_add_tail(&system_links, &font_link->entry);
2509 next:
2510 val_len = max_val + 1;
2511 data_len = max_data;
2514 HeapFree(GetProcessHeap(), 0, value);
2515 HeapFree(GetProcessHeap(), 0, data);
2516 RegCloseKey(hkey);
2520 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2521 if (!psub) {
2522 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2523 goto skip_internal;
2526 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2528 const FontSubst *psub2;
2529 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2531 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2533 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2534 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2536 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2537 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2539 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2541 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2545 skip_internal:
2547 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2548 that Tahoma has */
2550 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2551 system_font_link->font_name = strdupW(System);
2552 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2553 list_init(&system_font_link->links);
2555 face = find_face_from_filename(tahoma_ttf, Tahoma);
2556 if(face)
2558 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2559 child_font->face = face;
2560 child_font->font = NULL;
2561 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2562 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2563 TRACE("Found Tahoma in %s index %ld\n",
2564 debugstr_w(child_font->face->file), child_font->face->face_index);
2565 list_add_tail(&system_font_link->links, &child_font->entry);
2567 font_link = find_font_link(Tahoma);
2568 if (font_link != NULL)
2570 CHILD_FONT *font_link_entry;
2571 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2573 CHILD_FONT *new_child;
2574 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2575 new_child->face = font_link_entry->face;
2576 new_child->font = NULL;
2577 new_child->face->refcount++;
2578 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2579 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2580 list_add_tail(&system_font_link->links, &new_child->entry);
2583 list_add_tail(&system_links, &system_font_link->entry);
2584 return ret;
2587 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2589 DIR *dir;
2590 struct dirent *dent;
2591 char path[MAX_PATH];
2593 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2595 dir = opendir(dirname);
2596 if(!dir) {
2597 WARN("Can't open directory %s\n", debugstr_a(dirname));
2598 return FALSE;
2600 while((dent = readdir(dir)) != NULL) {
2601 struct stat statbuf;
2603 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2604 continue;
2606 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2608 sprintf(path, "%s/%s", dirname, dent->d_name);
2610 if(stat(path, &statbuf) == -1)
2612 WARN("Can't stat %s\n", debugstr_a(path));
2613 continue;
2615 if(S_ISDIR(statbuf.st_mode))
2616 ReadFontDir(path, external_fonts);
2617 else
2619 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2620 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2621 AddFontToList(path, NULL, 0, addfont_flags);
2624 closedir(dir);
2625 return TRUE;
2628 #ifdef SONAME_LIBFONTCONFIG
2630 static BOOL fontconfig_enabled;
2632 static UINT parse_aa_pattern( FcPattern *pattern )
2634 FcBool antialias;
2635 int rgba;
2636 UINT aa_flags = 0;
2638 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2639 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2641 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2643 switch (rgba)
2645 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2646 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2647 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2648 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2649 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2652 return aa_flags;
2655 static void init_fontconfig(void)
2657 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2659 if (!fc_handle)
2661 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2662 return;
2665 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2666 LOAD_FUNCPTR(FcConfigSubstitute);
2667 LOAD_FUNCPTR(FcFontList);
2668 LOAD_FUNCPTR(FcFontSetDestroy);
2669 LOAD_FUNCPTR(FcInit);
2670 LOAD_FUNCPTR(FcObjectSetAdd);
2671 LOAD_FUNCPTR(FcObjectSetCreate);
2672 LOAD_FUNCPTR(FcObjectSetDestroy);
2673 LOAD_FUNCPTR(FcPatternCreate);
2674 LOAD_FUNCPTR(FcPatternDestroy);
2675 LOAD_FUNCPTR(FcPatternGetBool);
2676 LOAD_FUNCPTR(FcPatternGetInteger);
2677 LOAD_FUNCPTR(FcPatternGetString);
2678 #undef LOAD_FUNCPTR
2680 if (pFcInit())
2682 FcPattern *pattern = pFcPatternCreate();
2683 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2684 default_aa_flags = parse_aa_pattern( pattern );
2685 pFcPatternDestroy( pattern );
2686 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2687 fontconfig_enabled = TRUE;
2691 static void load_fontconfig_fonts(void)
2693 FcPattern *pat;
2694 FcObjectSet *os;
2695 FcFontSet *fontset;
2696 int i, len;
2697 char *file;
2698 const char *ext;
2700 if (!fontconfig_enabled) return;
2702 pat = pFcPatternCreate();
2703 os = pFcObjectSetCreate();
2704 pFcObjectSetAdd(os, FC_FILE);
2705 pFcObjectSetAdd(os, FC_SCALABLE);
2706 pFcObjectSetAdd(os, FC_ANTIALIAS);
2707 pFcObjectSetAdd(os, FC_RGBA);
2708 fontset = pFcFontList(NULL, pat, os);
2709 if(!fontset) return;
2710 for(i = 0; i < fontset->nfont; i++) {
2711 FcBool scalable;
2712 DWORD aa_flags;
2714 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2715 continue;
2717 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2719 /* We're just interested in OT/TT fonts for now, so this hack just
2720 picks up the scalable fonts without extensions .pf[ab] to save time
2721 loading every other font */
2723 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2725 TRACE("not scalable\n");
2726 continue;
2729 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2730 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2732 len = strlen( file );
2733 if(len < 4) continue;
2734 ext = &file[ len - 3 ];
2735 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2736 AddFontToList(file, NULL, 0,
2737 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2739 pFcFontSetDestroy(fontset);
2740 pFcObjectSetDestroy(os);
2741 pFcPatternDestroy(pat);
2744 #elif defined(HAVE_CARBON_CARBON_H)
2746 static void load_mac_font_callback(const void *value, void *context)
2748 CFStringRef pathStr = value;
2749 CFIndex len;
2750 char* path;
2752 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2753 path = HeapAlloc(GetProcessHeap(), 0, len);
2754 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2756 TRACE("font file %s\n", path);
2757 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2759 HeapFree(GetProcessHeap(), 0, path);
2762 static void load_mac_fonts(void)
2764 CFStringRef removeDupesKey;
2765 CFBooleanRef removeDupesValue;
2766 CFDictionaryRef options;
2767 CTFontCollectionRef col;
2768 CFArrayRef descs;
2769 CFMutableSetRef paths;
2770 CFIndex i;
2772 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2773 removeDupesValue = kCFBooleanTrue;
2774 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2775 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2776 col = CTFontCollectionCreateFromAvailableFonts(options);
2777 if (options) CFRelease(options);
2778 if (!col)
2780 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2781 return;
2784 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2785 CFRelease(col);
2786 if (!descs)
2788 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2789 return;
2792 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2793 if (!paths)
2795 WARN("CFSetCreateMutable failed\n");
2796 CFRelease(descs);
2797 return;
2800 for (i = 0; i < CFArrayGetCount(descs); i++)
2802 CTFontDescriptorRef desc;
2803 CTFontRef font;
2804 ATSFontRef atsFont;
2805 OSStatus status;
2806 FSRef fsref;
2807 CFURLRef url;
2808 CFStringRef ext;
2809 CFStringRef path;
2811 desc = CFArrayGetValueAtIndex(descs, i);
2813 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2814 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2815 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2816 if (!font) continue;
2818 atsFont = CTFontGetPlatformFont(font, NULL);
2819 if (!atsFont)
2821 CFRelease(font);
2822 continue;
2825 status = ATSFontGetFileReference(atsFont, &fsref);
2826 CFRelease(font);
2827 if (status != noErr) continue;
2829 url = CFURLCreateFromFSRef(NULL, &fsref);
2830 if (!url) continue;
2832 ext = CFURLCopyPathExtension(url);
2833 if (ext)
2835 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2836 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2837 CFRelease(ext);
2838 if (skip)
2840 CFRelease(url);
2841 continue;
2845 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2846 CFRelease(url);
2847 if (!path) continue;
2849 CFSetAddValue(paths, path);
2850 CFRelease(path);
2853 CFRelease(descs);
2855 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2856 CFRelease(paths);
2859 #endif
2861 static char *get_data_dir_path( LPCWSTR file )
2863 char *unix_name = NULL;
2864 const char *data_dir = wine_get_data_dir();
2866 if (!data_dir) data_dir = wine_get_build_dir();
2868 if (data_dir)
2870 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2872 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2873 strcpy(unix_name, data_dir);
2874 strcat(unix_name, "/fonts/");
2876 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2878 return unix_name;
2881 static BOOL load_font_from_data_dir(LPCWSTR file)
2883 BOOL ret = FALSE;
2884 char *unix_name = get_data_dir_path( file );
2886 if (unix_name)
2888 EnterCriticalSection( &freetype_cs );
2889 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2890 LeaveCriticalSection( &freetype_cs );
2891 HeapFree(GetProcessHeap(), 0, unix_name);
2893 return ret;
2896 static char *get_winfonts_dir_path(LPCWSTR file)
2898 static const WCHAR slashW[] = {'\\','\0'};
2899 WCHAR windowsdir[MAX_PATH];
2901 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2902 strcatW(windowsdir, fontsW);
2903 strcatW(windowsdir, slashW);
2904 strcatW(windowsdir, file);
2905 return wine_get_unix_file_name( windowsdir );
2908 static void load_system_fonts(void)
2910 HKEY hkey;
2911 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2912 const WCHAR * const *value;
2913 DWORD dlen, type;
2914 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2915 char *unixname;
2917 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2918 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2919 strcatW(windowsdir, fontsW);
2920 for(value = SystemFontValues; *value; value++) {
2921 dlen = sizeof(data);
2922 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2923 type == REG_SZ) {
2924 BOOL added = FALSE;
2926 sprintfW(pathW, fmtW, windowsdir, data);
2927 if((unixname = wine_get_unix_file_name(pathW))) {
2928 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2929 HeapFree(GetProcessHeap(), 0, unixname);
2931 if (!added)
2932 load_font_from_data_dir(data);
2935 RegCloseKey(hkey);
2939 /*************************************************************
2941 * This adds registry entries for any externally loaded fonts
2942 * (fonts from fontconfig or FontDirs). It also deletes entries
2943 * of no longer existing fonts.
2946 static void update_reg_entries(void)
2948 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2949 LPWSTR valueW;
2950 DWORD len;
2951 Family *family;
2952 Face *face;
2953 WCHAR *file, *path;
2954 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2956 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2957 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2958 ERR("Can't create Windows font reg key\n");
2959 goto end;
2962 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2963 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2964 ERR("Can't create Windows font reg key\n");
2965 goto end;
2968 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2969 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2970 ERR("Can't create external font reg key\n");
2971 goto end;
2974 /* enumerate the fonts and add external ones to the two keys */
2976 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2977 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2978 char *buffer;
2979 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
2981 if(face->FullName)
2983 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2984 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2985 strcpyW(valueW, face->FullName);
2987 else
2989 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2990 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2991 strcpyW(valueW, family->FamilyName);
2994 buffer = strWtoA( CP_UNIXCP, face->file );
2995 path = wine_get_dos_file_name( buffer );
2996 HeapFree( GetProcessHeap(), 0, buffer );
2998 if (path)
2999 file = path;
3000 else if ((file = strrchrW(face->file, '/')))
3001 file++;
3002 else
3003 file = face->file;
3005 len = strlenW(file) + 1;
3006 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3007 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3008 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
3010 HeapFree(GetProcessHeap(), 0, path);
3011 HeapFree(GetProcessHeap(), 0, valueW);
3014 end:
3015 if(external_key) RegCloseKey(external_key);
3016 if(win9x_key) RegCloseKey(win9x_key);
3017 if(winnt_key) RegCloseKey(winnt_key);
3018 return;
3021 static void delete_external_font_keys(void)
3023 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
3024 DWORD dlen, vlen, datalen, valuelen, i, type;
3025 LPWSTR valueW;
3026 LPVOID data;
3028 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
3029 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
3030 ERR("Can't create Windows font reg key\n");
3031 goto end;
3034 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
3035 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
3036 ERR("Can't create Windows font reg key\n");
3037 goto end;
3040 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
3041 ERR("Can't create external font reg key\n");
3042 goto end;
3045 /* Delete all external fonts added last time */
3047 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3048 &valuelen, &datalen, NULL, NULL);
3049 valuelen++; /* returned value doesn't include room for '\0' */
3050 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3051 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3053 dlen = datalen * sizeof(WCHAR);
3054 vlen = valuelen;
3055 i = 0;
3056 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
3057 &dlen) == ERROR_SUCCESS) {
3059 RegDeleteValueW(winnt_key, valueW);
3060 RegDeleteValueW(win9x_key, valueW);
3061 /* reset dlen and vlen */
3062 dlen = datalen;
3063 vlen = valuelen;
3065 HeapFree(GetProcessHeap(), 0, data);
3066 HeapFree(GetProcessHeap(), 0, valueW);
3068 /* Delete the old external fonts key */
3069 RegCloseKey(external_key);
3070 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
3072 end:
3073 if(win9x_key) RegCloseKey(win9x_key);
3074 if(winnt_key) RegCloseKey(winnt_key);
3077 /*************************************************************
3078 * WineEngAddFontResourceEx
3081 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3083 INT ret = 0;
3085 GDI_CheckNotLock();
3087 if (ft_handle) /* do it only if we have freetype up and running */
3089 char *unixname;
3091 EnterCriticalSection( &freetype_cs );
3093 if((unixname = wine_get_unix_file_name(file)))
3095 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3097 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3098 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
3099 HeapFree(GetProcessHeap(), 0, unixname);
3101 if (!ret && !strchrW(file, '\\')) {
3102 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3103 if ((unixname = get_winfonts_dir_path( file )))
3105 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3106 HeapFree(GetProcessHeap(), 0, unixname);
3108 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3109 if (!ret && (unixname = get_data_dir_path( file )))
3111 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3112 HeapFree(GetProcessHeap(), 0, unixname);
3116 LeaveCriticalSection( &freetype_cs );
3118 return ret;
3121 /*************************************************************
3122 * WineEngAddFontMemResourceEx
3125 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
3127 GDI_CheckNotLock();
3129 if (ft_handle) /* do it only if we have freetype up and running */
3131 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
3133 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
3134 memcpy(pFontCopy, pbFont, cbFont);
3136 EnterCriticalSection( &freetype_cs );
3137 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
3138 LeaveCriticalSection( &freetype_cs );
3140 if (*pcFonts == 0)
3142 TRACE("AddFontToList failed\n");
3143 HeapFree(GetProcessHeap(), 0, pFontCopy);
3144 return 0;
3146 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3147 * For now return something unique but quite random
3149 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
3150 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
3153 *pcFonts = 0;
3154 return 0;
3157 /*************************************************************
3158 * WineEngRemoveFontResourceEx
3161 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3163 INT ret = 0;
3165 GDI_CheckNotLock();
3167 if (ft_handle) /* do it only if we have freetype up and running */
3169 char *unixname;
3171 EnterCriticalSection( &freetype_cs );
3173 if ((unixname = wine_get_unix_file_name(file)))
3175 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
3177 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3178 ret = remove_font_resource( unixname, addfont_flags );
3179 HeapFree(GetProcessHeap(), 0, unixname);
3181 if (!ret && !strchrW(file, '\\'))
3183 if ((unixname = get_winfonts_dir_path( file )))
3185 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3186 HeapFree(GetProcessHeap(), 0, unixname);
3188 if (!ret && (unixname = get_data_dir_path( file )))
3190 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3191 HeapFree(GetProcessHeap(), 0, unixname);
3195 LeaveCriticalSection( &freetype_cs );
3197 return ret;
3200 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3202 WCHAR *fullname;
3203 char *unix_name;
3204 int file_len;
3206 if (!font_file) return NULL;
3208 file_len = strlenW( font_file );
3210 if (font_path && font_path[0])
3212 int path_len = strlenW( font_path );
3213 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3214 if (!fullname) return NULL;
3215 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3216 fullname[path_len] = '\\';
3217 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3219 else
3221 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3222 if (!len) return NULL;
3223 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3224 if (!fullname) return NULL;
3225 GetFullPathNameW( font_file, len, fullname, NULL );
3228 unix_name = wine_get_unix_file_name( fullname );
3229 HeapFree( GetProcessHeap(), 0, fullname );
3230 return unix_name;
3233 #include <pshpack1.h>
3234 struct fontdir
3236 WORD num_of_resources;
3237 WORD res_id;
3238 WORD dfVersion;
3239 DWORD dfSize;
3240 CHAR dfCopyright[60];
3241 WORD dfType;
3242 WORD dfPoints;
3243 WORD dfVertRes;
3244 WORD dfHorizRes;
3245 WORD dfAscent;
3246 WORD dfInternalLeading;
3247 WORD dfExternalLeading;
3248 BYTE dfItalic;
3249 BYTE dfUnderline;
3250 BYTE dfStrikeOut;
3251 WORD dfWeight;
3252 BYTE dfCharSet;
3253 WORD dfPixWidth;
3254 WORD dfPixHeight;
3255 BYTE dfPitchAndFamily;
3256 WORD dfAvgWidth;
3257 WORD dfMaxWidth;
3258 BYTE dfFirstChar;
3259 BYTE dfLastChar;
3260 BYTE dfDefaultChar;
3261 BYTE dfBreakChar;
3262 WORD dfWidthBytes;
3263 DWORD dfDevice;
3264 DWORD dfFace;
3265 DWORD dfReserved;
3266 CHAR szFaceName[LF_FACESIZE];
3269 #include <poppack.h>
3271 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3272 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3274 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3276 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3277 Face *face;
3278 WCHAR *name, *english_name;
3279 ENUMLOGFONTEXW elf;
3280 NEWTEXTMETRICEXW ntm;
3281 DWORD type;
3283 if (!ft_face) return FALSE;
3284 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3285 get_family_names( ft_face, &name, &english_name, FALSE );
3286 pFT_Done_Face( ft_face );
3288 GetEnumStructs( face, name, &elf, &ntm, &type );
3289 release_face( face );
3290 HeapFree( GetProcessHeap(), 0, name );
3291 HeapFree( GetProcessHeap(), 0, english_name );
3293 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3295 memset( fd, 0, sizeof(*fd) );
3297 fd->num_of_resources = 1;
3298 fd->res_id = 0;
3299 fd->dfVersion = 0x200;
3300 fd->dfSize = sizeof(*fd);
3301 strcpy( fd->dfCopyright, "Wine fontdir" );
3302 fd->dfType = 0x4003; /* 0x0080 set if private */
3303 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3304 fd->dfVertRes = 72;
3305 fd->dfHorizRes = 72;
3306 fd->dfAscent = ntm.ntmTm.tmAscent;
3307 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3308 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3309 fd->dfItalic = ntm.ntmTm.tmItalic;
3310 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3311 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3312 fd->dfWeight = ntm.ntmTm.tmWeight;
3313 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3314 fd->dfPixWidth = 0;
3315 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3316 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3317 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3318 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3319 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3320 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3321 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3322 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3323 fd->dfWidthBytes = 0;
3324 fd->dfDevice = 0;
3325 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3326 fd->dfReserved = 0;
3327 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3329 return TRUE;
3332 #define NE_FFLAGS_LIBMODULE 0x8000
3333 #define NE_OSFLAGS_WINDOWS 0x02
3335 static const char dos_string[0x40] = "This is a TrueType resource file";
3336 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3338 #include <pshpack2.h>
3340 struct ne_typeinfo
3342 WORD type_id;
3343 WORD count;
3344 DWORD res;
3347 struct ne_nameinfo
3349 WORD off;
3350 WORD len;
3351 WORD flags;
3352 WORD id;
3353 DWORD res;
3356 struct rsrc_tab
3358 WORD align;
3359 struct ne_typeinfo fontdir_type;
3360 struct ne_nameinfo fontdir_name;
3361 struct ne_typeinfo scalable_type;
3362 struct ne_nameinfo scalable_name;
3363 WORD end_of_rsrc;
3364 BYTE fontdir_res_name[8];
3367 #include <poppack.h>
3369 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3371 BOOL ret = FALSE;
3372 HANDLE file;
3373 DWORD size, written;
3374 BYTE *ptr, *start;
3375 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3376 char *font_fileA, *last_part, *ext;
3377 IMAGE_DOS_HEADER dos;
3378 IMAGE_OS2_HEADER ne =
3380 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3381 0, 0, 0, 0, 0, 0,
3382 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3383 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3385 struct rsrc_tab rsrc_tab =
3388 { 0x8007, 1, 0 },
3389 { 0, 0, 0x0c50, 0x2c, 0 },
3390 { 0x80cc, 1, 0 },
3391 { 0, 0, 0x0c50, 0x8001, 0 },
3393 { 7,'F','O','N','T','D','I','R'}
3396 memset( &dos, 0, sizeof(dos) );
3397 dos.e_magic = IMAGE_DOS_SIGNATURE;
3398 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3400 /* import name is last part\0, resident name is last part without extension
3401 non-resident name is "FONTRES:" + lfFaceName */
3403 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3404 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3405 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3407 last_part = strrchr( font_fileA, '\\' );
3408 if (last_part) last_part++;
3409 else last_part = font_fileA;
3410 import_name_len = strlen( last_part ) + 1;
3412 ext = strchr( last_part, '.' );
3413 if (ext) res_name_len = ext - last_part;
3414 else res_name_len = import_name_len - 1;
3416 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3418 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3419 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3420 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3421 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3422 ne.ne_cbenttab = 2;
3423 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3425 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3426 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3427 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3428 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3430 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3431 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3433 if (!ptr)
3435 HeapFree( GetProcessHeap(), 0, font_fileA );
3436 return FALSE;
3439 memcpy( ptr, &dos, sizeof(dos) );
3440 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3441 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3443 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3444 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3446 ptr = start + dos.e_lfanew + ne.ne_restab;
3447 *ptr++ = res_name_len;
3448 memcpy( ptr, last_part, res_name_len );
3450 ptr = start + dos.e_lfanew + ne.ne_imptab;
3451 *ptr++ = import_name_len;
3452 memcpy( ptr, last_part, import_name_len );
3454 ptr = start + ne.ne_nrestab;
3455 *ptr++ = non_res_name_len;
3456 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3457 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3459 ptr = start + (rsrc_tab.scalable_name.off << 4);
3460 memcpy( ptr, font_fileA, font_file_len );
3462 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3463 memcpy( ptr, fontdir, fontdir->dfSize );
3465 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3466 if (file != INVALID_HANDLE_VALUE)
3468 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3469 ret = TRUE;
3470 CloseHandle( file );
3473 HeapFree( GetProcessHeap(), 0, start );
3474 HeapFree( GetProcessHeap(), 0, font_fileA );
3476 return ret;
3479 /*************************************************************
3480 * WineEngCreateScalableFontResource
3483 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3484 LPCWSTR font_file, LPCWSTR font_path )
3486 char *unix_name = get_ttf_file_name( font_file, font_path );
3487 struct fontdir fontdir;
3488 BOOL ret = FALSE;
3490 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3491 SetLastError( ERROR_INVALID_PARAMETER );
3492 else
3494 if (hidden) fontdir.dfType |= 0x80;
3495 ret = create_fot( resource, font_file, &fontdir );
3498 HeapFree( GetProcessHeap(), 0, unix_name );
3499 return ret;
3502 static const struct nls_update_font_list
3504 UINT ansi_cp, oem_cp;
3505 const char *oem, *fixed, *system;
3506 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3507 /* these are for font substitutes */
3508 const char *shelldlg, *tmsrmn;
3509 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3510 *helv_0, *tmsrmn_0;
3511 const struct subst
3513 const char *from, *to;
3514 } arial_0, courier_new_0, times_new_roman_0;
3515 } nls_update_font_list[] =
3517 /* Latin 1 (United States) */
3518 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3519 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3520 "Tahoma","Times New Roman",
3521 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3522 { 0 }, { 0 }, { 0 }
3524 /* Latin 1 (Multilingual) */
3525 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3526 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3527 "Tahoma","Times New Roman", /* FIXME unverified */
3528 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3529 { 0 }, { 0 }, { 0 }
3531 /* Eastern Europe */
3532 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3533 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3534 "Tahoma","Times New Roman", /* FIXME unverified */
3535 "Fixedsys,238", "System,238",
3536 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3537 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3538 { "Arial CE,0", "Arial,238" },
3539 { "Courier New CE,0", "Courier New,238" },
3540 { "Times New Roman CE,0", "Times New Roman,238" }
3542 /* Cyrillic */
3543 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3544 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3545 "Tahoma","Times New Roman", /* FIXME unverified */
3546 "Fixedsys,204", "System,204",
3547 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3548 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3549 { "Arial Cyr,0", "Arial,204" },
3550 { "Courier New Cyr,0", "Courier New,204" },
3551 { "Times New Roman Cyr,0", "Times New Roman,204" }
3553 /* Greek */
3554 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3555 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3556 "Tahoma","Times New Roman", /* FIXME unverified */
3557 "Fixedsys,161", "System,161",
3558 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3559 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3560 { "Arial Greek,0", "Arial,161" },
3561 { "Courier New Greek,0", "Courier New,161" },
3562 { "Times New Roman Greek,0", "Times New Roman,161" }
3564 /* Turkish */
3565 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3566 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3567 "Tahoma","Times New Roman", /* FIXME unverified */
3568 "Fixedsys,162", "System,162",
3569 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3570 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3571 { "Arial Tur,0", "Arial,162" },
3572 { "Courier New Tur,0", "Courier New,162" },
3573 { "Times New Roman Tur,0", "Times New Roman,162" }
3575 /* Hebrew */
3576 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3577 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3578 "Tahoma","Times New Roman", /* FIXME unverified */
3579 "Fixedsys,177", "System,177",
3580 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3581 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3582 { 0 }, { 0 }, { 0 }
3584 /* Arabic */
3585 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3586 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3587 "Microsoft Sans Serif","Times New Roman",
3588 "Fixedsys,178", "System,178",
3589 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3590 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3591 { 0 }, { 0 }, { 0 }
3593 /* Baltic */
3594 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3595 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3596 "Tahoma","Times New Roman", /* FIXME unverified */
3597 "Fixedsys,186", "System,186",
3598 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3599 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3600 { "Arial Baltic,0", "Arial,186" },
3601 { "Courier New Baltic,0", "Courier New,186" },
3602 { "Times New Roman Baltic,0", "Times New Roman,186" }
3604 /* Vietnamese */
3605 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3606 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3607 "Tahoma","Times New Roman", /* FIXME unverified */
3608 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3609 { 0 }, { 0 }, { 0 }
3611 /* Thai */
3612 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3613 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3614 "Tahoma","Times New Roman", /* FIXME unverified */
3615 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3616 { 0 }, { 0 }, { 0 }
3618 /* Japanese */
3619 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3620 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3621 "MS UI Gothic","MS Serif",
3622 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3623 { 0 }, { 0 }, { 0 }
3625 /* Chinese Simplified */
3626 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3627 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3628 "SimSun", "NSimSun",
3629 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3630 { 0 }, { 0 }, { 0 }
3632 /* Korean */
3633 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3634 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3635 "Gulim", "Batang",
3636 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3637 { 0 }, { 0 }, { 0 }
3639 /* Chinese Traditional */
3640 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3641 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3642 "PMingLiU", "MingLiU",
3643 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3644 { 0 }, { 0 }, { 0 }
3648 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3650 return ( ansi_cp == 932 /* CP932 for Japanese */
3651 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3652 || ansi_cp == 949 /* CP949 for Korean */
3653 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3656 static inline HKEY create_fonts_NT_registry_key(void)
3658 HKEY hkey = 0;
3660 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3661 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3662 return hkey;
3665 static inline HKEY create_fonts_9x_registry_key(void)
3667 HKEY hkey = 0;
3669 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3670 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3671 return hkey;
3674 static inline HKEY create_config_fonts_registry_key(void)
3676 HKEY hkey = 0;
3678 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3679 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3680 return hkey;
3683 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3685 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3687 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3688 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3689 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3690 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3693 static void set_value_key(HKEY hkey, const char *name, const char *value)
3695 if (value)
3696 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3697 else if (name)
3698 RegDeleteValueA(hkey, name);
3701 static void update_font_association_info(UINT current_ansi_codepage)
3703 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3704 static const char *assoc_charset_subkey = "Associated Charset";
3706 if (is_dbcs_ansi_cp(current_ansi_codepage))
3708 HKEY hkey;
3709 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3711 HKEY hsubkey;
3712 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3714 switch (current_ansi_codepage)
3716 case 932:
3717 set_value_key(hsubkey, "ANSI(00)", "NO");
3718 set_value_key(hsubkey, "OEM(FF)", "NO");
3719 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3720 break;
3721 case 936:
3722 case 949:
3723 case 950:
3724 set_value_key(hsubkey, "ANSI(00)", "YES");
3725 set_value_key(hsubkey, "OEM(FF)", "YES");
3726 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3727 break;
3729 RegCloseKey(hsubkey);
3732 /* TODO: Associated DefaultFonts */
3734 RegCloseKey(hkey);
3737 else
3738 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3741 static void update_font_info(void)
3743 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3744 char buf[40], cpbuf[40];
3745 DWORD len, type;
3746 HKEY hkey = 0;
3747 UINT i, ansi_cp = 0, oem_cp = 0;
3748 DWORD screen_dpi = 96, font_dpi = 0;
3749 BOOL done = FALSE;
3751 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3752 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3753 &hkey) == ERROR_SUCCESS)
3755 reg_load_dword(hkey, logpixels, &screen_dpi);
3756 RegCloseKey(hkey);
3759 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3760 return;
3762 reg_load_dword(hkey, logpixels, &font_dpi);
3764 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3765 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3766 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3767 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3768 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3770 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3771 if (is_dbcs_ansi_cp(ansi_cp))
3772 use_default_fallback = TRUE;
3774 buf[0] = 0;
3775 len = sizeof(buf);
3776 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3778 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3780 RegCloseKey(hkey);
3781 return;
3783 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3784 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3786 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3787 ansi_cp, oem_cp, screen_dpi);
3789 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3790 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3791 RegCloseKey(hkey);
3793 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3795 HKEY hkey;
3797 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3798 nls_update_font_list[i].oem_cp == oem_cp)
3800 hkey = create_config_fonts_registry_key();
3801 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3802 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3803 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3804 RegCloseKey(hkey);
3806 hkey = create_fonts_NT_registry_key();
3807 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3808 RegCloseKey(hkey);
3810 hkey = create_fonts_9x_registry_key();
3811 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3812 RegCloseKey(hkey);
3814 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3816 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3817 strlen(nls_update_font_list[i].shelldlg)+1);
3818 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3819 strlen(nls_update_font_list[i].tmsrmn)+1);
3821 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3822 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3823 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3824 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3825 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3826 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3827 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3828 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3830 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3831 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3832 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3834 RegCloseKey(hkey);
3836 done = TRUE;
3838 else
3840 /* Delete the FontSubstitutes from other locales */
3841 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3843 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3844 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3845 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3846 RegCloseKey(hkey);
3850 if (!done)
3851 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3853 /* update locale dependent font association info in registry.
3854 update only when codepages changed, not logpixels. */
3855 if (strcmp(buf, cpbuf) != 0)
3856 update_font_association_info(ansi_cp);
3859 static BOOL init_freetype(void)
3861 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3862 if(!ft_handle) {
3863 WINE_MESSAGE(
3864 "Wine cannot find the FreeType font library. To enable Wine to\n"
3865 "use TrueType fonts please install a version of FreeType greater than\n"
3866 "or equal to 2.0.5.\n"
3867 "http://www.freetype.org\n");
3868 return FALSE;
3871 #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;}
3873 LOAD_FUNCPTR(FT_Done_Face)
3874 LOAD_FUNCPTR(FT_Get_Char_Index)
3875 LOAD_FUNCPTR(FT_Get_First_Char)
3876 LOAD_FUNCPTR(FT_Get_Next_Char)
3877 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3878 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3879 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3880 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3881 LOAD_FUNCPTR(FT_Init_FreeType)
3882 LOAD_FUNCPTR(FT_Library_Version)
3883 LOAD_FUNCPTR(FT_Load_Glyph)
3884 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3885 LOAD_FUNCPTR(FT_Matrix_Multiply)
3886 #ifndef FT_MULFIX_INLINED
3887 LOAD_FUNCPTR(FT_MulFix)
3888 #endif
3889 LOAD_FUNCPTR(FT_New_Face)
3890 LOAD_FUNCPTR(FT_New_Memory_Face)
3891 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3892 LOAD_FUNCPTR(FT_Outline_Get_CBox)
3893 LOAD_FUNCPTR(FT_Outline_Transform)
3894 LOAD_FUNCPTR(FT_Outline_Translate)
3895 LOAD_FUNCPTR(FT_Render_Glyph)
3896 LOAD_FUNCPTR(FT_Select_Charmap)
3897 LOAD_FUNCPTR(FT_Set_Charmap)
3898 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3899 LOAD_FUNCPTR(FT_Vector_Transform)
3900 LOAD_FUNCPTR(FT_Vector_Unit)
3901 #undef LOAD_FUNCPTR
3902 /* Don't warn if these ones are missing */
3903 pFT_Outline_Embolden = wine_dlsym(ft_handle, "FT_Outline_Embolden", NULL, 0);
3904 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3905 #ifdef FT_LCD_FILTER_H
3906 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3907 #endif
3909 if(pFT_Init_FreeType(&library) != 0) {
3910 ERR("Can't init FreeType library\n");
3911 wine_dlclose(ft_handle, NULL, 0);
3912 ft_handle = NULL;
3913 return FALSE;
3915 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3917 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3918 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3919 ((FT_Version.minor << 8) & 0x00ff00) |
3920 ((FT_Version.patch ) & 0x0000ff);
3922 font_driver = &freetype_funcs;
3923 return TRUE;
3925 sym_not_found:
3926 WINE_MESSAGE(
3927 "Wine cannot find certain functions that it needs inside the FreeType\n"
3928 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3929 "FreeType to at least version 2.1.4.\n"
3930 "http://www.freetype.org\n");
3931 wine_dlclose(ft_handle, NULL, 0);
3932 ft_handle = NULL;
3933 return FALSE;
3936 static void init_font_list(void)
3938 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3939 static const WCHAR pathW[] = {'P','a','t','h',0};
3940 HKEY hkey;
3941 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3942 WCHAR windowsdir[MAX_PATH];
3943 char *unixname;
3944 const char *data_dir;
3946 delete_external_font_keys();
3948 /* load the system bitmap fonts */
3949 load_system_fonts();
3951 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3952 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3953 strcatW(windowsdir, fontsW);
3954 if((unixname = wine_get_unix_file_name(windowsdir)))
3956 ReadFontDir(unixname, FALSE);
3957 HeapFree(GetProcessHeap(), 0, unixname);
3960 /* load the system truetype fonts */
3961 data_dir = wine_get_data_dir();
3962 if (!data_dir) data_dir = wine_get_build_dir();
3963 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3965 strcpy(unixname, data_dir);
3966 strcat(unixname, "/fonts/");
3967 ReadFontDir(unixname, TRUE);
3968 HeapFree(GetProcessHeap(), 0, unixname);
3971 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3972 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3973 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3974 will skip these. */
3975 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3976 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3977 &hkey) == ERROR_SUCCESS)
3979 LPWSTR data, valueW;
3980 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3981 &valuelen, &datalen, NULL, NULL);
3983 valuelen++; /* returned value doesn't include room for '\0' */
3984 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3985 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3986 if (valueW && data)
3988 dlen = datalen * sizeof(WCHAR);
3989 vlen = valuelen;
3990 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3991 &dlen) == ERROR_SUCCESS)
3993 if(data[0] && (data[1] == ':'))
3995 if((unixname = wine_get_unix_file_name(data)))
3997 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3998 HeapFree(GetProcessHeap(), 0, unixname);
4001 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
4003 WCHAR pathW[MAX_PATH];
4004 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
4005 BOOL added = FALSE;
4007 sprintfW(pathW, fmtW, windowsdir, data);
4008 if((unixname = wine_get_unix_file_name(pathW)))
4010 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
4011 HeapFree(GetProcessHeap(), 0, unixname);
4013 if (!added)
4014 load_font_from_data_dir(data);
4016 /* reset dlen and vlen */
4017 dlen = datalen;
4018 vlen = valuelen;
4021 HeapFree(GetProcessHeap(), 0, data);
4022 HeapFree(GetProcessHeap(), 0, valueW);
4023 RegCloseKey(hkey);
4026 #ifdef SONAME_LIBFONTCONFIG
4027 load_fontconfig_fonts();
4028 #elif defined(HAVE_CARBON_CARBON_H)
4029 load_mac_fonts();
4030 #endif
4032 /* then look in any directories that we've specified in the config file */
4033 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4034 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
4036 DWORD len;
4037 LPWSTR valueW;
4038 LPSTR valueA, ptr;
4040 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
4042 len += sizeof(WCHAR);
4043 valueW = HeapAlloc( GetProcessHeap(), 0, len );
4044 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
4046 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
4047 valueA = HeapAlloc( GetProcessHeap(), 0, len );
4048 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
4049 TRACE( "got font path %s\n", debugstr_a(valueA) );
4050 ptr = valueA;
4051 while (ptr)
4053 const char* home;
4054 LPSTR next = strchr( ptr, ':' );
4055 if (next) *next++ = 0;
4056 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
4057 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
4059 strcpy( unixname, home );
4060 strcat( unixname, ptr + 1 );
4061 ReadFontDir( unixname, TRUE );
4062 HeapFree( GetProcessHeap(), 0, unixname );
4064 else
4065 ReadFontDir( ptr, TRUE );
4066 ptr = next;
4068 HeapFree( GetProcessHeap(), 0, valueA );
4070 HeapFree( GetProcessHeap(), 0, valueW );
4072 RegCloseKey(hkey);
4076 static BOOL move_to_front(const WCHAR *name)
4078 Family *family, *cursor2;
4079 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
4081 if(!strcmpiW(family->FamilyName, name))
4083 list_remove(&family->entry);
4084 list_add_head(&font_list, &family->entry);
4085 return TRUE;
4088 return FALSE;
4091 static BOOL set_default(const WCHAR **name_list)
4093 while (*name_list)
4095 if (move_to_front(*name_list)) return TRUE;
4096 name_list++;
4099 return FALSE;
4102 static void reorder_font_list(void)
4104 set_default( default_serif_list );
4105 set_default( default_fixed_list );
4106 set_default( default_sans_list );
4109 /*************************************************************
4110 * WineEngInit
4112 * Initialize FreeType library and create a list of available faces
4114 BOOL WineEngInit(void)
4116 DWORD disposition;
4117 HANDLE font_mutex;
4119 /* update locale dependent font info in registry */
4120 update_font_info();
4122 if(!init_freetype()) return FALSE;
4124 #ifdef SONAME_LIBFONTCONFIG
4125 init_fontconfig();
4126 #endif
4128 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
4130 ERR("Failed to create font mutex\n");
4131 return FALSE;
4133 WaitForSingleObject(font_mutex, INFINITE);
4135 create_font_cache_key(&hkey_font_cache, &disposition);
4137 if(disposition == REG_CREATED_NEW_KEY)
4138 init_font_list();
4139 else
4140 load_font_list_from_cache(hkey_font_cache);
4142 reorder_font_list();
4144 DumpFontList();
4145 LoadSubstList();
4146 DumpSubstList();
4147 LoadReplaceList();
4149 if(disposition == REG_CREATED_NEW_KEY)
4150 update_reg_entries();
4152 init_system_links();
4154 ReleaseMutex(font_mutex);
4155 return TRUE;
4159 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
4161 TT_OS2 *pOS2;
4162 TT_HoriHeader *pHori;
4164 LONG ppem;
4165 const LONG MAX_PPEM = (1 << 16) - 1;
4167 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4168 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4170 if(height == 0) height = 16;
4172 /* Calc. height of EM square:
4174 * For +ve lfHeight we have
4175 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4176 * Re-arranging gives:
4177 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4179 * For -ve lfHeight we have
4180 * |lfHeight| = ppem
4181 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4182 * with il = winAscent + winDescent - units_per_em]
4186 if(height > 0) {
4187 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
4188 ppem = MulDiv(ft_face->units_per_EM, height,
4189 pHori->Ascender - pHori->Descender);
4190 else
4191 ppem = MulDiv(ft_face->units_per_EM, height,
4192 pOS2->usWinAscent + pOS2->usWinDescent);
4193 if(ppem > MAX_PPEM) {
4194 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4195 ppem = 1;
4198 else if(height >= -MAX_PPEM)
4199 ppem = -height;
4200 else {
4201 WARN("Ignoring too large height %d\n", height);
4202 ppem = 1;
4205 return ppem;
4208 static struct font_mapping *map_font_file( const char *name )
4210 struct font_mapping *mapping;
4211 struct stat st;
4212 int fd;
4214 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4215 if (fstat( fd, &st ) == -1) goto error;
4217 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4219 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4221 mapping->refcount++;
4222 close( fd );
4223 return mapping;
4226 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4227 goto error;
4229 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4230 close( fd );
4232 if (mapping->data == MAP_FAILED)
4234 HeapFree( GetProcessHeap(), 0, mapping );
4235 return NULL;
4237 mapping->refcount = 1;
4238 mapping->dev = st.st_dev;
4239 mapping->ino = st.st_ino;
4240 mapping->size = st.st_size;
4241 list_add_tail( &mappings_list, &mapping->entry );
4242 return mapping;
4244 error:
4245 close( fd );
4246 return NULL;
4249 static void unmap_font_file( struct font_mapping *mapping )
4251 if (!--mapping->refcount)
4253 list_remove( &mapping->entry );
4254 munmap( mapping->data, mapping->size );
4255 HeapFree( GetProcessHeap(), 0, mapping );
4259 static LONG load_VDMX(GdiFont*, LONG);
4261 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4263 FT_Error err;
4264 FT_Face ft_face;
4265 void *data_ptr;
4266 DWORD data_size;
4268 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4270 if (face->file)
4272 char *filename = strWtoA( CP_UNIXCP, face->file );
4273 font->mapping = map_font_file( filename );
4274 HeapFree( GetProcessHeap(), 0, filename );
4275 if (!font->mapping)
4277 WARN("failed to map %s\n", debugstr_w(face->file));
4278 return 0;
4280 data_ptr = font->mapping->data;
4281 data_size = font->mapping->size;
4283 else
4285 data_ptr = face->font_data_ptr;
4286 data_size = face->font_data_size;
4289 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4290 if(err) {
4291 ERR("FT_New_Face rets %d\n", err);
4292 return 0;
4295 /* set it here, as load_VDMX needs it */
4296 font->ft_face = ft_face;
4298 if(FT_IS_SCALABLE(ft_face)) {
4299 /* load the VDMX table if we have one */
4300 font->ppem = load_VDMX(font, height);
4301 if(font->ppem == 0)
4302 font->ppem = calc_ppem_for_height(ft_face, height);
4303 TRACE("height %d => ppem %d\n", height, font->ppem);
4305 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4306 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4307 } else {
4308 font->ppem = height;
4309 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4310 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4312 return ft_face;
4316 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4318 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4319 a single face with the requested charset. The idea is to check if
4320 the selected font supports the current ANSI codepage, if it does
4321 return the corresponding charset, else return the first charset */
4323 CHARSETINFO csi;
4324 int acp = GetACP(), i;
4325 DWORD fs0;
4327 *cp = acp;
4328 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4330 const SYSTEM_LINKS *font_link;
4332 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4333 return csi.ciCharset;
4335 font_link = find_font_link(family_name);
4336 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4337 return csi.ciCharset;
4340 for(i = 0; i < 32; i++) {
4341 fs0 = 1L << i;
4342 if(face->fs.fsCsb[0] & fs0) {
4343 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4344 *cp = csi.ciACP;
4345 return csi.ciCharset;
4347 else
4348 FIXME("TCI failing on %x\n", fs0);
4352 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4353 face->fs.fsCsb[0], debugstr_w(face->file));
4354 *cp = acp;
4355 return DEFAULT_CHARSET;
4358 static GdiFont *alloc_font(void)
4360 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4361 ret->refcount = 1;
4362 ret->gmsize = 1;
4363 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4364 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4365 ret->potm = NULL;
4366 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4367 ret->total_kern_pairs = (DWORD)-1;
4368 ret->kern_pairs = NULL;
4369 list_init(&ret->child_fonts);
4370 return ret;
4373 static void free_font(GdiFont *font)
4375 CHILD_FONT *child, *child_next;
4376 DWORD i;
4378 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4380 list_remove(&child->entry);
4381 if(child->font)
4382 free_font(child->font);
4383 release_face( child->face );
4384 HeapFree(GetProcessHeap(), 0, child);
4387 if (font->ft_face) pFT_Done_Face(font->ft_face);
4388 if (font->mapping) unmap_font_file( font->mapping );
4389 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4390 HeapFree(GetProcessHeap(), 0, font->potm);
4391 HeapFree(GetProcessHeap(), 0, font->name);
4392 for (i = 0; i < font->gmsize; i++)
4393 HeapFree(GetProcessHeap(),0,font->gm[i]);
4394 HeapFree(GetProcessHeap(), 0, font->gm);
4395 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4396 HeapFree(GetProcessHeap(), 0, font);
4400 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4402 FT_Face ft_face = font->ft_face;
4403 FT_ULong len;
4404 FT_Error err;
4406 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4408 if(!buf)
4409 len = 0;
4410 else
4411 len = cbData;
4413 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4415 /* make sure value of len is the value freetype says it needs */
4416 if (buf && len)
4418 FT_ULong needed = 0;
4419 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4420 if( !err && needed < len) len = needed;
4422 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4423 if (err)
4425 TRACE("Can't find table %c%c%c%c\n",
4426 /* bytes were reversed */
4427 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4428 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4429 return GDI_ERROR;
4431 return len;
4434 /*************************************************************
4435 * load_VDMX
4437 * load the vdmx entry for the specified height
4440 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4441 ( ( (FT_ULong)_x4 << 24 ) | \
4442 ( (FT_ULong)_x3 << 16 ) | \
4443 ( (FT_ULong)_x2 << 8 ) | \
4444 (FT_ULong)_x1 )
4446 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4448 typedef struct {
4449 BYTE bCharSet;
4450 BYTE xRatio;
4451 BYTE yStartRatio;
4452 BYTE yEndRatio;
4453 } Ratios;
4455 typedef struct {
4456 WORD recs;
4457 BYTE startsz;
4458 BYTE endsz;
4459 } VDMX_group;
4461 static LONG load_VDMX(GdiFont *font, LONG height)
4463 WORD hdr[3], tmp;
4464 VDMX_group group;
4465 BYTE devXRatio, devYRatio;
4466 USHORT numRecs, numRatios;
4467 DWORD result, offset = -1;
4468 LONG ppem = 0;
4469 int i;
4471 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4473 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4474 return ppem;
4476 /* FIXME: need the real device aspect ratio */
4477 devXRatio = 1;
4478 devYRatio = 1;
4480 numRecs = GET_BE_WORD(hdr[1]);
4481 numRatios = GET_BE_WORD(hdr[2]);
4483 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4484 for(i = 0; i < numRatios; i++) {
4485 Ratios ratio;
4487 offset = (3 * 2) + (i * sizeof(Ratios));
4488 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4489 offset = -1;
4491 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4493 if (!ratio.bCharSet) continue;
4495 if((ratio.xRatio == 0 &&
4496 ratio.yStartRatio == 0 &&
4497 ratio.yEndRatio == 0) ||
4498 (devXRatio == ratio.xRatio &&
4499 devYRatio >= ratio.yStartRatio &&
4500 devYRatio <= ratio.yEndRatio))
4502 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4503 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4504 offset = GET_BE_WORD(tmp);
4505 break;
4509 if(offset == -1) return 0;
4511 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4512 USHORT recs;
4513 BYTE startsz, endsz;
4514 WORD *vTable;
4516 recs = GET_BE_WORD(group.recs);
4517 startsz = group.startsz;
4518 endsz = group.endsz;
4520 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4522 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4523 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4524 if(result == GDI_ERROR) {
4525 FIXME("Failed to retrieve vTable\n");
4526 goto end;
4529 if(height > 0) {
4530 for(i = 0; i < recs; i++) {
4531 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4532 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4533 ppem = GET_BE_WORD(vTable[i * 3]);
4535 if(yMax + -yMin == height) {
4536 font->yMax = yMax;
4537 font->yMin = yMin;
4538 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4539 break;
4541 if(yMax + -yMin > height) {
4542 if(--i < 0) {
4543 ppem = 0;
4544 goto end; /* failed */
4546 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4547 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4548 ppem = GET_BE_WORD(vTable[i * 3]);
4549 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4550 break;
4553 if(!font->yMax) {
4554 ppem = 0;
4555 TRACE("ppem not found for height %d\n", height);
4557 } else {
4558 ppem = -height;
4559 if(ppem < startsz || ppem > endsz)
4561 ppem = 0;
4562 goto end;
4565 for(i = 0; i < recs; i++) {
4566 USHORT yPelHeight;
4567 yPelHeight = GET_BE_WORD(vTable[i * 3]);
4569 if(yPelHeight > ppem)
4571 ppem = 0;
4572 break; /* failed */
4575 if(yPelHeight == ppem) {
4576 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4577 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4578 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
4579 break;
4583 end:
4584 HeapFree(GetProcessHeap(), 0, vTable);
4587 return ppem;
4590 static void dump_gdi_font_list(void)
4592 GdiFont *font;
4594 TRACE("---------- Font Cache ----------\n");
4595 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4596 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4597 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4600 static void grab_font( GdiFont *font )
4602 if (!font->refcount++)
4604 list_remove( &font->unused_entry );
4605 unused_font_count--;
4609 static void release_font( GdiFont *font )
4611 if (!font) return;
4612 if (!--font->refcount)
4614 TRACE( "font %p\n", font );
4616 /* add it to the unused list */
4617 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4618 if (unused_font_count > UNUSED_CACHE_SIZE)
4620 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4621 TRACE( "freeing %p\n", font );
4622 list_remove( &font->entry );
4623 list_remove( &font->unused_entry );
4624 free_font( font );
4626 else unused_font_count++;
4628 if (TRACE_ON(font)) dump_gdi_font_list();
4632 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4634 if(font->font_desc.hash != fd->hash) return TRUE;
4635 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4636 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4637 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4638 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4641 static void calc_hash(FONT_DESC *pfd)
4643 DWORD hash = 0, *ptr, two_chars;
4644 WORD *pwc;
4645 unsigned int i;
4647 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4648 hash ^= *ptr;
4649 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4650 hash ^= *ptr;
4651 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4652 two_chars = *ptr;
4653 pwc = (WCHAR *)&two_chars;
4654 if(!*pwc) break;
4655 *pwc = toupperW(*pwc);
4656 pwc++;
4657 *pwc = toupperW(*pwc);
4658 hash ^= two_chars;
4659 if(!*pwc) break;
4661 hash ^= !pfd->can_use_bitmap;
4662 pfd->hash = hash;
4663 return;
4666 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4668 GdiFont *ret;
4669 FONT_DESC fd;
4671 fd.lf = *plf;
4672 fd.matrix = *pmat;
4673 fd.can_use_bitmap = can_use_bitmap;
4674 calc_hash(&fd);
4676 /* try the in-use list */
4677 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4679 if(fontcmp(ret, &fd)) continue;
4680 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4681 list_remove( &ret->entry );
4682 list_add_head( &gdi_font_list, &ret->entry );
4683 grab_font( ret );
4684 return ret;
4686 return NULL;
4689 static void add_to_cache(GdiFont *font)
4691 static DWORD cache_num = 1;
4693 font->cache_num = cache_num++;
4694 list_add_head(&gdi_font_list, &font->entry);
4695 TRACE( "font %p\n", font );
4698 /*************************************************************
4699 * create_child_font_list
4701 static BOOL create_child_font_list(GdiFont *font)
4703 BOOL ret = FALSE;
4704 SYSTEM_LINKS *font_link;
4705 CHILD_FONT *font_link_entry, *new_child;
4706 FontSubst *psub;
4707 WCHAR* font_name;
4709 psub = get_font_subst(&font_subst_list, font->name, -1);
4710 font_name = psub ? psub->to.name : font->name;
4711 font_link = find_font_link(font_name);
4712 if (font_link != NULL)
4714 TRACE("found entry in system list\n");
4715 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4717 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4718 new_child->face = font_link_entry->face;
4719 new_child->font = NULL;
4720 new_child->face->refcount++;
4721 list_add_tail(&font->child_fonts, &new_child->entry);
4722 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4724 ret = TRUE;
4727 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4728 * Sans Serif. This is how asian windows get default fallbacks for fonts
4730 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4731 font->charset != OEM_CHARSET &&
4732 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4734 font_link = find_font_link(szDefaultFallbackLink);
4735 if (font_link != NULL)
4737 TRACE("found entry in default fallback list\n");
4738 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4740 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4741 new_child->face = font_link_entry->face;
4742 new_child->font = NULL;
4743 new_child->face->refcount++;
4744 list_add_tail(&font->child_fonts, &new_child->entry);
4745 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4747 ret = TRUE;
4751 return ret;
4754 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4756 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4758 if (pFT_Set_Charmap)
4760 FT_Int i;
4761 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4763 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4765 for (i = 0; i < ft_face->num_charmaps; i++)
4767 if (ft_face->charmaps[i]->encoding == encoding)
4769 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4770 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4772 switch (ft_face->charmaps[i]->platform_id)
4774 default:
4775 cmap_def = ft_face->charmaps[i];
4776 break;
4777 case 0: /* Apple Unicode */
4778 cmap0 = ft_face->charmaps[i];
4779 break;
4780 case 1: /* Macintosh */
4781 cmap1 = ft_face->charmaps[i];
4782 break;
4783 case 2: /* ISO */
4784 cmap2 = ft_face->charmaps[i];
4785 break;
4786 case 3: /* Microsoft */
4787 cmap3 = ft_face->charmaps[i];
4788 break;
4792 if (cmap3) /* prefer Microsoft cmap table */
4793 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4794 else if (cmap1)
4795 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4796 else if (cmap2)
4797 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4798 else if (cmap0)
4799 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4800 else if (cmap_def)
4801 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4803 return ft_err == FT_Err_Ok;
4806 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4810 /*************************************************************
4811 * freetype_CreateDC
4813 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4814 LPCWSTR output, const DEVMODEW *devmode )
4816 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4818 if (!physdev) return FALSE;
4819 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4820 return TRUE;
4824 /*************************************************************
4825 * freetype_DeleteDC
4827 static BOOL freetype_DeleteDC( PHYSDEV dev )
4829 struct freetype_physdev *physdev = get_freetype_dev( dev );
4830 release_font( physdev->font );
4831 HeapFree( GetProcessHeap(), 0, physdev );
4832 return TRUE;
4835 static FT_Encoding pick_charmap( FT_Face face, int charset )
4837 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4838 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4839 const FT_Encoding *encs = regular_order;
4841 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4843 while (*encs != 0)
4845 if (select_charmap( face, *encs )) break;
4846 encs++;
4848 return *encs;
4851 #define GASP_GRIDFIT 0x01
4852 #define GASP_DOGRAY 0x02
4853 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4855 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4857 DWORD size;
4858 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4859 WORD *alloced = NULL, *ptr = buf;
4860 WORD num_recs, version;
4861 BOOL ret = FALSE;
4863 *flags = 0;
4864 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4865 if (size == GDI_ERROR) return FALSE;
4866 if (size < 4 * sizeof(WORD)) return FALSE;
4867 if (size > sizeof(buf))
4869 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4870 if (!ptr) return FALSE;
4873 get_font_data( font, GASP_TAG, 0, ptr, size );
4875 version = GET_BE_WORD( *ptr++ );
4876 num_recs = GET_BE_WORD( *ptr++ );
4878 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4880 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4881 goto done;
4884 while (num_recs--)
4886 *flags = GET_BE_WORD( *(ptr + 1) );
4887 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4888 ptr += 2;
4890 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4891 ret = TRUE;
4893 done:
4894 HeapFree( GetProcessHeap(), 0, alloced );
4895 return ret;
4898 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4900 const GSUB_ScriptList *script;
4901 const GSUB_Script *deflt = NULL;
4902 int i;
4903 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4905 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4906 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4908 const GSUB_Script *scr;
4909 int offset;
4911 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4912 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4914 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4915 return scr;
4916 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4917 deflt = scr;
4919 return deflt;
4922 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4924 int i;
4925 int offset;
4926 const GSUB_LangSys *Lang;
4928 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4930 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4932 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4933 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4935 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4936 return Lang;
4938 offset = GET_BE_WORD(script->DefaultLangSys);
4939 if (offset)
4941 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4942 return Lang;
4944 return NULL;
4947 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4949 int i;
4950 const GSUB_FeatureList *feature;
4951 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4953 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4954 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4956 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4957 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4959 const GSUB_Feature *feat;
4960 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4961 return feat;
4964 return NULL;
4967 static const char* get_opentype_script(const GdiFont *font)
4970 * I am not sure if this is the correct way to generate our script tag
4973 switch (font->charset)
4975 case ANSI_CHARSET: return "latn";
4976 case BALTIC_CHARSET: return "latn"; /* ?? */
4977 case CHINESEBIG5_CHARSET: return "hani";
4978 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4979 case GB2312_CHARSET: return "hani";
4980 case GREEK_CHARSET: return "grek";
4981 case HANGUL_CHARSET: return "hang";
4982 case RUSSIAN_CHARSET: return "cyrl";
4983 case SHIFTJIS_CHARSET: return "kana";
4984 case TURKISH_CHARSET: return "latn"; /* ?? */
4985 case VIETNAMESE_CHARSET: return "latn";
4986 case JOHAB_CHARSET: return "latn"; /* ?? */
4987 case ARABIC_CHARSET: return "arab";
4988 case HEBREW_CHARSET: return "hebr";
4989 case THAI_CHARSET: return "thai";
4990 default: return "latn";
4994 static const VOID * get_GSUB_vert_feature(const GdiFont *font)
4996 const GSUB_Header *header;
4997 const GSUB_Script *script;
4998 const GSUB_LangSys *language;
4999 const GSUB_Feature *feature;
5001 if (!font->GSUB_Table)
5002 return NULL;
5004 header = font->GSUB_Table;
5006 script = GSUB_get_script_table(header, get_opentype_script(font));
5007 if (!script)
5009 TRACE("Script not found\n");
5010 return NULL;
5012 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5013 if (!language)
5015 TRACE("Language not found\n");
5016 return NULL;
5018 feature = GSUB_get_feature(header, language, "vrt2");
5019 if (!feature)
5020 feature = GSUB_get_feature(header, language, "vert");
5021 if (!feature)
5023 TRACE("vrt2/vert feature not found\n");
5024 return NULL;
5026 return feature;
5029 /*************************************************************
5030 * freetype_SelectFont
5032 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
5034 struct freetype_physdev *physdev = get_freetype_dev( dev );
5035 GdiFont *ret;
5036 Face *face, *best, *best_bitmap;
5037 Family *family, *last_resort_family;
5038 const struct list *face_list;
5039 INT height, width = 0;
5040 unsigned int score = 0, new_score;
5041 signed int diff = 0, newdiff;
5042 BOOL bd, it, can_use_bitmap, want_vertical;
5043 LOGFONTW lf;
5044 CHARSETINFO csi;
5045 FMAT2 dcmat;
5046 FontSubst *psub = NULL;
5047 DC *dc = get_dc_ptr( dev->hdc );
5048 const SYSTEM_LINKS *font_link;
5050 if (!hfont) /* notification that the font has been changed by another driver */
5052 release_font( physdev->font );
5053 physdev->font = NULL;
5054 release_dc_ptr( dc );
5055 return 0;
5058 GetObjectW( hfont, sizeof(lf), &lf );
5059 lf.lfWidth = abs(lf.lfWidth);
5061 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
5063 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5064 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
5065 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
5066 lf.lfEscapement);
5068 if(dc->GraphicsMode == GM_ADVANCED)
5070 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
5071 /* Try to avoid not necessary glyph transformations */
5072 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
5074 lf.lfHeight *= fabs(dcmat.eM11);
5075 lf.lfWidth *= fabs(dcmat.eM11);
5076 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
5079 else
5081 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5082 font scaling abilities. */
5083 dcmat.eM11 = dcmat.eM22 = 1.0;
5084 dcmat.eM21 = dcmat.eM12 = 0;
5085 lf.lfOrientation = lf.lfEscapement;
5086 if (dc->vport2WorldValid)
5088 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
5089 lf.lfOrientation = -lf.lfOrientation;
5090 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
5091 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
5095 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
5096 dcmat.eM21, dcmat.eM22);
5098 GDI_CheckNotLock();
5099 EnterCriticalSection( &freetype_cs );
5101 /* check the cache first */
5102 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5103 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
5104 goto done;
5107 TRACE("not in cache\n");
5108 ret = alloc_font();
5110 ret->font_desc.matrix = dcmat;
5111 ret->font_desc.lf = lf;
5112 ret->font_desc.can_use_bitmap = can_use_bitmap;
5113 calc_hash(&ret->font_desc);
5115 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5116 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5117 original value lfCharSet. Note this is a special case for
5118 Symbol and doesn't happen at least for "Wingdings*" */
5120 if(!strcmpiW(lf.lfFaceName, SymbolW))
5121 lf.lfCharSet = SYMBOL_CHARSET;
5123 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
5124 switch(lf.lfCharSet) {
5125 case DEFAULT_CHARSET:
5126 csi.fs.fsCsb[0] = 0;
5127 break;
5128 default:
5129 FIXME("Untranslated charset %d\n", lf.lfCharSet);
5130 csi.fs.fsCsb[0] = 0;
5131 break;
5135 family = NULL;
5136 if(lf.lfFaceName[0] != '\0') {
5137 CHILD_FONT *font_link_entry;
5138 LPWSTR FaceName = lf.lfFaceName;
5140 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
5142 if(psub) {
5143 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
5144 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
5145 if (psub->to.charset != -1)
5146 lf.lfCharSet = psub->to.charset;
5149 /* We want a match on name and charset or just name if
5150 charset was DEFAULT_CHARSET. If the latter then
5151 we fixup the returned charset later in get_nearest_charset
5152 where we'll either use the charset of the current ansi codepage
5153 or if that's unavailable the first charset that the font supports.
5155 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5156 if (!strcmpiW(family->FamilyName, FaceName) ||
5157 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
5159 font_link = find_font_link(family->FamilyName);
5160 face_list = get_face_list_from_family(family);
5161 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5162 if (!(face->scalable || can_use_bitmap))
5163 continue;
5164 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5165 goto found;
5166 if (font_link != NULL &&
5167 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5168 goto found;
5169 if (!csi.fs.fsCsb[0])
5170 goto found;
5175 /* Search by full face name. */
5176 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5177 face_list = get_face_list_from_family(family);
5178 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5179 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
5180 (face->scalable || can_use_bitmap))
5182 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5183 goto found_face;
5184 font_link = find_font_link(family->FamilyName);
5185 if (font_link != NULL &&
5186 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5187 goto found_face;
5193 * Try check the SystemLink list first for a replacement font.
5194 * We may find good replacements there.
5196 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
5198 if(!strcmpiW(font_link->font_name, FaceName) ||
5199 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
5201 TRACE("found entry in system list\n");
5202 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
5204 const SYSTEM_LINKS *links;
5206 face = font_link_entry->face;
5207 if (!(face->scalable || can_use_bitmap))
5208 continue;
5209 family = face->family;
5210 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
5211 goto found;
5212 links = find_font_link(family->FamilyName);
5213 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
5214 goto found;
5220 psub = NULL; /* substitution is no more relevant */
5222 /* If requested charset was DEFAULT_CHARSET then try using charset
5223 corresponding to the current ansi codepage */
5224 if (!csi.fs.fsCsb[0])
5226 INT acp = GetACP();
5227 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
5228 FIXME("TCI failed on codepage %d\n", acp);
5229 csi.fs.fsCsb[0] = 0;
5230 } else
5231 lf.lfCharSet = csi.ciCharset;
5234 want_vertical = (lf.lfFaceName[0] == '@');
5236 /* Face families are in the top 4 bits of lfPitchAndFamily,
5237 so mask with 0xF0 before testing */
5239 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
5240 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
5241 strcpyW(lf.lfFaceName, defFixed);
5242 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
5243 strcpyW(lf.lfFaceName, defSerif);
5244 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
5245 strcpyW(lf.lfFaceName, defSans);
5246 else
5247 strcpyW(lf.lfFaceName, defSans);
5248 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5249 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
5250 font_link = find_font_link(family->FamilyName);
5251 face_list = get_face_list_from_family(family);
5252 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5253 if (!(face->scalable || can_use_bitmap))
5254 continue;
5255 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
5256 goto found;
5257 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
5258 goto found;
5263 last_resort_family = NULL;
5264 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5265 font_link = find_font_link(family->FamilyName);
5266 face_list = get_face_list_from_family(family);
5267 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5268 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
5269 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5270 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
5271 if(face->scalable)
5272 goto found;
5273 if(can_use_bitmap && !last_resort_family)
5274 last_resort_family = family;
5279 if(last_resort_family) {
5280 family = last_resort_family;
5281 csi.fs.fsCsb[0] = 0;
5282 goto found;
5285 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5286 face_list = get_face_list_from_family(family);
5287 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5288 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
5289 csi.fs.fsCsb[0] = 0;
5290 WARN("just using first face for now\n");
5291 goto found;
5293 if(can_use_bitmap && !last_resort_family)
5294 last_resort_family = family;
5297 if(!last_resort_family) {
5298 FIXME("can't find a single appropriate font - bailing\n");
5299 free_font(ret);
5300 ret = NULL;
5301 goto done;
5304 WARN("could only find a bitmap font - this will probably look awful!\n");
5305 family = last_resort_family;
5306 csi.fs.fsCsb[0] = 0;
5308 found:
5309 it = lf.lfItalic ? 1 : 0;
5310 bd = lf.lfWeight > 550 ? 1 : 0;
5312 height = lf.lfHeight;
5314 face = best = best_bitmap = NULL;
5315 font_link = find_font_link(family->FamilyName);
5316 face_list = get_face_list_from_family(family);
5317 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5319 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
5320 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
5321 !csi.fs.fsCsb[0])
5323 BOOL italic, bold;
5325 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
5326 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
5327 new_score = (italic ^ it) + (bold ^ bd);
5328 if(!best || new_score <= score)
5330 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5331 italic, bold, it, bd);
5332 score = new_score;
5333 best = face;
5334 if(best->scalable && score == 0) break;
5335 if(!best->scalable)
5337 if(height > 0)
5338 newdiff = height - (signed int)(best->size.height);
5339 else
5340 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5341 if(!best_bitmap || new_score < score ||
5342 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5344 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5345 diff = newdiff;
5346 best_bitmap = best;
5347 if(score == 0 && diff == 0) break;
5353 if(best)
5354 face = best->scalable ? best : best_bitmap;
5355 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5356 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5358 found_face:
5359 height = lf.lfHeight;
5361 ret->fs = face->fs;
5363 if(csi.fs.fsCsb[0]) {
5364 ret->charset = lf.lfCharSet;
5365 ret->codepage = csi.ciACP;
5367 else
5368 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5370 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5371 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5373 ret->aveWidth = height ? lf.lfWidth : 0;
5375 if(!face->scalable) {
5376 /* Windows uses integer scaling factors for bitmap fonts */
5377 INT scale, scaled_height;
5378 GdiFont *cachedfont;
5380 /* FIXME: rotation of bitmap fonts is ignored */
5381 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5382 if (ret->aveWidth)
5383 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5384 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5385 dcmat.eM11 = dcmat.eM22 = 1.0;
5386 /* As we changed the matrix, we need to search the cache for the font again,
5387 * otherwise we might explode the cache. */
5388 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5389 TRACE("Found cached font after non-scalable matrix rescale!\n");
5390 free_font( ret );
5391 ret = cachedfont;
5392 goto done;
5394 calc_hash(&ret->font_desc);
5396 if (height != 0) height = diff;
5397 height += face->size.height;
5399 scale = (height + face->size.height - 1) / face->size.height;
5400 scaled_height = scale * face->size.height;
5401 /* Only jump to the next height if the difference <= 25% original height */
5402 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5403 /* The jump between unscaled and doubled is delayed by 1 */
5404 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5405 ret->scale_y = scale;
5407 width = face->size.x_ppem >> 6;
5408 height = face->size.y_ppem >> 6;
5410 else
5411 ret->scale_y = 1.0;
5412 TRACE("font scale y: %f\n", ret->scale_y);
5414 ret->ft_face = OpenFontFace(ret, face, width, height);
5416 if (!ret->ft_face)
5418 free_font( ret );
5419 ret = NULL;
5420 goto done;
5423 ret->ntmFlags = face->ntmFlags;
5425 pick_charmap( ret->ft_face, ret->charset );
5427 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5428 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5429 ret->underline = lf.lfUnderline ? 0xff : 0;
5430 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5431 create_child_font_list(ret);
5433 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5435 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5436 if (length != GDI_ERROR)
5438 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5439 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5440 TRACE("Loaded GSUB table of %i bytes\n",length);
5441 ret->vert_feature = get_GSUB_vert_feature(ret);
5442 if (!ret->vert_feature)
5444 TRACE("Vertical feature not found\n");
5445 HeapFree(GetProcessHeap(), 0, ret->GSUB_Table);
5446 ret->GSUB_Table = NULL;
5450 ret->aa_flags = HIWORD( face->flags );
5452 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5454 add_to_cache(ret);
5455 done:
5456 if (ret)
5458 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5460 switch (lf.lfQuality)
5462 case NONANTIALIASED_QUALITY:
5463 case ANTIALIASED_QUALITY:
5464 next->funcs->pSelectFont( dev, hfont, aa_flags );
5465 break;
5466 case CLEARTYPE_QUALITY:
5467 case CLEARTYPE_NATURAL_QUALITY:
5468 default:
5469 if (!*aa_flags) *aa_flags = ret->aa_flags;
5470 next->funcs->pSelectFont( dev, hfont, aa_flags );
5472 /* fixup the antialiasing flags for that font */
5473 switch (*aa_flags)
5475 case WINE_GGO_HRGB_BITMAP:
5476 case WINE_GGO_HBGR_BITMAP:
5477 case WINE_GGO_VRGB_BITMAP:
5478 case WINE_GGO_VBGR_BITMAP:
5479 if (is_subpixel_rendering_enabled()) break;
5480 *aa_flags = GGO_GRAY4_BITMAP;
5481 /* fall through */
5482 case GGO_GRAY2_BITMAP:
5483 case GGO_GRAY4_BITMAP:
5484 case GGO_GRAY8_BITMAP:
5485 case WINE_GGO_GRAY16_BITMAP:
5486 if (is_hinting_enabled())
5488 WORD gasp_flags;
5489 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5491 TRACE( "font %s %d aa disabled by GASP\n",
5492 debugstr_w(lf.lfFaceName), lf.lfHeight );
5493 *aa_flags = GGO_BITMAP;
5498 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5499 release_font( physdev->font );
5500 physdev->font = ret;
5502 LeaveCriticalSection( &freetype_cs );
5503 release_dc_ptr( dc );
5504 return ret ? hfont : 0;
5507 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5509 HRSRC rsrc;
5510 HGLOBAL hMem;
5511 WCHAR *p;
5512 int i;
5514 id += IDS_FIRST_SCRIPT;
5515 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5516 if (!rsrc) return 0;
5517 hMem = LoadResource( gdi32_module, rsrc );
5518 if (!hMem) return 0;
5520 p = LockResource( hMem );
5521 id &= 0x000f;
5522 while (id--) p += *p + 1;
5524 i = min(LF_FACESIZE - 1, *p);
5525 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5526 buffer[i] = 0;
5527 return i;
5530 static inline BOOL is_complex_script_ansi_cp(UINT ansi_cp)
5532 return (ansi_cp == 874 /* Thai */
5533 || ansi_cp == 1255 /* Hebrew */
5534 || ansi_cp == 1256 /* Arabic */
5538 /***************************************************
5539 * create_enum_charset_list
5541 * This function creates charset enumeration list because in DEFAULT_CHARSET
5542 * case, the ANSI codepage's charset takes precedence over other charsets.
5543 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5544 * This function works as a filter other than DEFAULT_CHARSET case.
5546 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5548 CHARSETINFO csi;
5549 DWORD n = 0;
5551 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5552 csi.fs.fsCsb[0] != 0) {
5553 list->element[n].mask = csi.fs.fsCsb[0];
5554 list->element[n].charset = csi.ciCharset;
5555 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5556 n++;
5558 else { /* charset is DEFAULT_CHARSET or invalid. */
5559 INT acp, i;
5560 DWORD mask = 0;
5562 /* Set the current codepage's charset as the first element. */
5563 acp = GetACP();
5564 if (!is_complex_script_ansi_cp(acp) &&
5565 TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5566 csi.fs.fsCsb[0] != 0) {
5567 list->element[n].mask = csi.fs.fsCsb[0];
5568 list->element[n].charset = csi.ciCharset;
5569 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5570 mask |= csi.fs.fsCsb[0];
5571 n++;
5574 /* Fill out left elements. */
5575 for (i = 0; i < 32; i++) {
5576 FONTSIGNATURE fs;
5577 fs.fsCsb[0] = 1L << i;
5578 fs.fsCsb[1] = 0;
5579 if (fs.fsCsb[0] & mask)
5580 continue; /* skip, already added. */
5581 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5582 continue; /* skip, this is an invalid fsCsb bit. */
5584 list->element[n].mask = fs.fsCsb[0];
5585 list->element[n].charset = csi.ciCharset;
5586 load_script_name( i, list->element[n].name );
5587 mask |= fs.fsCsb[0];
5588 n++;
5591 /* add catch all mask for remaining bits */
5592 if (~mask)
5594 list->element[n].mask = ~mask;
5595 list->element[n].charset = DEFAULT_CHARSET;
5596 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5597 n++;
5600 list->total = n;
5602 return n;
5605 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5606 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5608 GdiFont *font;
5609 LONG width, height;
5611 if (face->cached_enum_data)
5613 TRACE("Cached\n");
5614 *pelf = face->cached_enum_data->elf;
5615 *pntm = face->cached_enum_data->ntm;
5616 *ptype = face->cached_enum_data->type;
5617 return;
5620 font = alloc_font();
5622 if(face->scalable) {
5623 height = 100;
5624 width = 0;
5625 } else {
5626 height = face->size.y_ppem >> 6;
5627 width = face->size.x_ppem >> 6;
5629 font->scale_y = 1.0;
5631 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5633 free_font(font);
5634 return;
5637 font->name = strdupW( family_name );
5638 font->ntmFlags = face->ntmFlags;
5640 if (get_outline_text_metrics(font))
5642 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5644 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5645 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5646 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5648 lstrcpynW(pelf->elfLogFont.lfFaceName,
5649 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5650 LF_FACESIZE);
5651 lstrcpynW(pelf->elfFullName,
5652 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5653 LF_FULLFACESIZE);
5654 lstrcpynW(pelf->elfStyle,
5655 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5656 LF_FACESIZE);
5658 else
5660 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5662 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5663 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5664 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5666 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5667 if (face->FullName)
5668 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5669 else
5670 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5671 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5674 pntm->ntmTm.ntmFlags = face->ntmFlags;
5675 pntm->ntmFontSig = face->fs;
5677 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5679 pelf->elfLogFont.lfEscapement = 0;
5680 pelf->elfLogFont.lfOrientation = 0;
5681 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5682 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5683 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5684 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5685 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5686 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5687 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5688 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5689 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5690 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5691 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5693 *ptype = 0;
5694 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5695 *ptype |= TRUETYPE_FONTTYPE;
5696 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5697 *ptype |= DEVICE_FONTTYPE;
5698 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5699 *ptype |= RASTER_FONTTYPE;
5701 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5702 if (face->cached_enum_data)
5704 face->cached_enum_data->elf = *pelf;
5705 face->cached_enum_data->ntm = *pntm;
5706 face->cached_enum_data->type = *ptype;
5709 free_font(font);
5712 static BOOL family_matches(Family *family, const WCHAR *face_name)
5714 Face *face;
5715 const struct list *face_list;
5717 if (!strcmpiW(face_name, family->FamilyName)) return TRUE;
5719 face_list = get_face_list_from_family(family);
5720 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5721 if (face->FullName && !strcmpiW(face_name, face->FullName)) return TRUE;
5723 return FALSE;
5726 static BOOL face_matches(const WCHAR *family_name, Face *face, const WCHAR *face_name)
5728 if (!strcmpiW(face_name, family_name)) return TRUE;
5730 return (face->FullName && !strcmpiW(face_name, face->FullName));
5733 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5734 FONTENUMPROCW proc, LPARAM lparam)
5736 ENUMLOGFONTEXW elf;
5737 NEWTEXTMETRICEXW ntm;
5738 DWORD type = 0;
5739 DWORD i;
5741 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5742 for(i = 0; i < list->total; i++) {
5743 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5744 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5745 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5746 i = list->total; /* break out of loop after enumeration */
5748 else
5750 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5751 /* use the DEFAULT_CHARSET case only if no other charset is present */
5752 if (list->element[i].charset == DEFAULT_CHARSET &&
5753 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5754 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5755 strcpyW(elf.elfScript, list->element[i].name);
5756 if (!elf.elfScript[0])
5757 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5759 /* Font Replacement */
5760 if (family != face->family)
5762 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5763 if (face->FullName)
5764 strcpyW(elf.elfFullName, face->FullName);
5765 else
5766 strcpyW(elf.elfFullName, family->FamilyName);
5768 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5769 debugstr_w(elf.elfLogFont.lfFaceName),
5770 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5771 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5772 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5773 ntm.ntmTm.ntmFlags);
5774 /* release section before callback (FIXME) */
5775 LeaveCriticalSection( &freetype_cs );
5776 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5777 EnterCriticalSection( &freetype_cs );
5779 return TRUE;
5782 /*************************************************************
5783 * freetype_EnumFonts
5785 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5787 Family *family;
5788 Face *face;
5789 const struct list *face_list;
5790 LOGFONTW lf;
5791 struct enum_charset_list enum_charsets;
5793 if (!plf)
5795 lf.lfCharSet = DEFAULT_CHARSET;
5796 lf.lfPitchAndFamily = 0;
5797 lf.lfFaceName[0] = 0;
5798 plf = &lf;
5801 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5803 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5805 GDI_CheckNotLock();
5806 EnterCriticalSection( &freetype_cs );
5807 if(plf->lfFaceName[0]) {
5808 WCHAR *face_name = plf->lfFaceName;
5809 FontSubst *psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5811 if(psub) {
5812 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5813 debugstr_w(psub->to.name));
5814 face_name = psub->to.name;
5817 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5818 if (!family_matches(family, face_name)) continue;
5819 face_list = get_face_list_from_family(family);
5820 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5821 if (!face_matches(family->FamilyName, face, face_name)) continue;
5822 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5825 } else {
5826 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5827 face_list = get_face_list_from_family(family);
5828 face = LIST_ENTRY(list_head(face_list), Face, entry);
5829 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5832 LeaveCriticalSection( &freetype_cs );
5833 return TRUE;
5836 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5838 pt->x.value = vec->x >> 6;
5839 pt->x.fract = (vec->x & 0x3f) << 10;
5840 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5841 pt->y.value = vec->y >> 6;
5842 pt->y.fract = (vec->y & 0x3f) << 10;
5843 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5844 return;
5847 /***************************************************
5848 * According to the MSDN documentation on WideCharToMultiByte,
5849 * certain codepages cannot set the default_used parameter.
5850 * This returns TRUE if the codepage can set that parameter, false else
5851 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5853 static BOOL codepage_sets_default_used(UINT codepage)
5855 switch (codepage)
5857 case CP_UTF7:
5858 case CP_UTF8:
5859 case CP_SYMBOL:
5860 return FALSE;
5861 default:
5862 return TRUE;
5867 * GSUB Table handling functions
5870 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5872 const GSUB_CoverageFormat1* cf1;
5874 cf1 = table;
5876 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5878 int count = GET_BE_WORD(cf1->GlyphCount);
5879 int i;
5880 TRACE("Coverage Format 1, %i glyphs\n",count);
5881 for (i = 0; i < count; i++)
5882 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5883 return i;
5884 return -1;
5886 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5888 const GSUB_CoverageFormat2* cf2;
5889 int i;
5890 int count;
5891 cf2 = (const GSUB_CoverageFormat2*)cf1;
5893 count = GET_BE_WORD(cf2->RangeCount);
5894 TRACE("Coverage Format 2, %i ranges\n",count);
5895 for (i = 0; i < count; i++)
5897 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5898 return -1;
5899 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5900 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5902 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5903 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5906 return -1;
5908 else
5909 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5911 return -1;
5914 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5916 int i;
5917 int offset;
5918 const GSUB_LookupList *lookup;
5919 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5921 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5922 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5924 const GSUB_LookupTable *look;
5925 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5926 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5927 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5928 if (GET_BE_WORD(look->LookupType) != 1)
5929 FIXME("We only handle SubType 1\n");
5930 else
5932 int j;
5934 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5936 const GSUB_SingleSubstFormat1 *ssf1;
5937 offset = GET_BE_WORD(look->SubTable[j]);
5938 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5939 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5941 int offset = GET_BE_WORD(ssf1->Coverage);
5942 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5943 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5945 TRACE(" Glyph 0x%x ->",glyph);
5946 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5947 TRACE(" 0x%x\n",glyph);
5950 else
5952 const GSUB_SingleSubstFormat2 *ssf2;
5953 INT index;
5954 INT offset;
5956 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5957 offset = GET_BE_WORD(ssf1->Coverage);
5958 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5959 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5960 TRACE(" Coverage index %i\n",index);
5961 if (index != -1)
5963 TRACE(" Glyph is 0x%x ->",glyph);
5964 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5965 TRACE("0x%x\n",glyph);
5971 return glyph;
5975 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5977 const GSUB_Header *header;
5978 const GSUB_Feature *feature;
5980 if (!font->GSUB_Table)
5981 return glyph;
5983 header = font->GSUB_Table;
5984 feature = font->vert_feature;
5986 return GSUB_apply_feature(header, feature, glyph);
5989 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5991 FT_UInt glyphId;
5993 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5994 WCHAR wc = (WCHAR)glyph;
5995 BOOL default_used;
5996 BOOL *default_used_pointer;
5997 FT_UInt ret;
5998 char buf;
5999 default_used_pointer = NULL;
6000 default_used = FALSE;
6001 if (codepage_sets_default_used(font->codepage))
6002 default_used_pointer = &default_used;
6003 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6005 if (font->codepage == CP_SYMBOL && wc < 0x100)
6006 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6007 else
6008 ret = 0;
6010 else
6011 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6012 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6013 return ret;
6016 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6018 if (glyph < 0x100) glyph += 0xf000;
6019 /* there is a number of old pre-Unicode "broken" TTFs, which
6020 do have symbols at U+00XX instead of U+f0XX */
6021 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6022 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6024 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6026 return glyphId;
6029 /* helper for freetype_GetGlyphIndices */
6030 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6032 WCHAR wc = (WCHAR)glyph;
6033 BOOL default_used = FALSE;
6034 BOOL *default_used_pointer = NULL;
6035 FT_UInt ret;
6036 char buf;
6038 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6039 return get_glyph_index(font, glyph);
6041 if (codepage_sets_default_used(font->codepage))
6042 default_used_pointer = &default_used;
6043 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6044 || default_used)
6046 if (font->codepage == CP_SYMBOL && wc < 0x100)
6047 ret = (unsigned char)wc;
6048 else
6049 ret = 0;
6051 else
6052 ret = (unsigned char)buf;
6053 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6054 return ret;
6057 static FT_UInt get_default_char_index(GdiFont *font)
6059 FT_UInt default_char;
6061 if (FT_IS_SFNT(font->ft_face))
6063 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6064 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6066 else
6068 TEXTMETRICW textm;
6069 get_text_metrics(font, &textm);
6070 default_char = textm.tmDefaultChar;
6073 return default_char;
6076 /*************************************************************
6077 * freetype_GetGlyphIndices
6079 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6081 struct freetype_physdev *physdev = get_freetype_dev( dev );
6082 int i;
6083 WORD default_char;
6084 BOOL got_default = FALSE;
6086 if (!physdev->font)
6088 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6089 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6092 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6094 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6095 got_default = TRUE;
6098 GDI_CheckNotLock();
6099 EnterCriticalSection( &freetype_cs );
6101 for(i = 0; i < count; i++)
6103 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6104 if (pgi[i] == 0)
6106 if (!got_default)
6108 default_char = get_default_char_index(physdev->font);
6109 got_default = TRUE;
6111 pgi[i] = default_char;
6113 else
6114 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6116 LeaveCriticalSection( &freetype_cs );
6117 return count;
6120 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6122 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6123 return !memcmp(matrix, &identity, sizeof(FMAT2));
6126 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6128 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6129 return !memcmp(matrix, &identity, sizeof(MAT2));
6132 static void synthesize_bold_glyph(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6134 FT_Error err;
6135 static UINT once;
6137 switch(glyph->format) {
6138 case FT_GLYPH_FORMAT_OUTLINE:
6140 FT_Pos strength;
6141 FT_BBox bbox;
6142 if(!pFT_Outline_Embolden)
6143 break;
6145 strength = MulDiv(ppem, 1 << 6, 24);
6146 err = pFT_Outline_Embolden(&glyph->outline, strength);
6147 if(err) {
6148 TRACE("FT_Ouline_Embolden returns %d, ignored\n", err);
6149 break;
6152 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6153 metrics->width = bbox.xMax - bbox.xMin;
6154 metrics->height = bbox.yMax - bbox.yMin;
6155 metrics->horiBearingX = bbox.xMin;
6156 metrics->horiBearingY = bbox.yMax;
6157 metrics->horiAdvance += (1 << 6);
6158 metrics->vertAdvance += (1 << 6);
6159 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6160 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6161 break;
6163 default:
6164 if (!once++)
6165 WARN("Emboldening format 0x%x is not supported\n", glyph->format);
6166 return;
6170 static inline BYTE get_max_level( UINT format )
6172 switch( format )
6174 case GGO_GRAY2_BITMAP: return 4;
6175 case GGO_GRAY4_BITMAP: return 16;
6176 case GGO_GRAY8_BITMAP: return 64;
6178 return 255;
6181 extern const unsigned short vertical_orientation_table[];
6183 static BOOL check_unicode_tategaki(WCHAR uchar)
6185 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6187 /* We only reach this code if typographical substitution did not occur */
6188 /* Type: U or Type: Tu */
6189 return (orientation == 1 || orientation == 3);
6192 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6194 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6195 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6196 const MAT2* lpmat)
6198 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6199 GLYPHMETRICS gm;
6200 FT_Face ft_face = incoming_font->ft_face;
6201 GdiFont *font = incoming_font;
6202 FT_Glyph_Metrics metrics;
6203 FT_UInt glyph_index;
6204 DWORD width, height, pitch, needed = 0;
6205 FT_Bitmap ft_bitmap;
6206 FT_Error err;
6207 INT left, right, top = 0, bottom = 0, adv;
6208 INT origin_x = 0, origin_y = 0;
6209 FT_Angle angle = 0;
6210 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6211 double widthRatio = 1.0;
6212 FT_Matrix transMat = identityMat;
6213 FT_Matrix transMatUnrotated;
6214 FT_Matrix transMatTategaki;
6215 BOOL needsTransform = FALSE;
6216 BOOL tategaki = (font->name[0] == '@');
6217 BOOL vertical_metrics;
6218 UINT original_index;
6219 LONG avgAdvance = 0;
6220 FT_Fixed em_scale;
6222 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6223 buflen, buf, lpmat);
6225 TRACE("font transform %f %f %f %f\n",
6226 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6227 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6229 if(format & GGO_GLYPH_INDEX) {
6230 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6231 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6232 as glyph index. "Treasure Adventure Game" depends on this. */
6233 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6234 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6235 } else
6236 glyph_index = glyph;
6237 original_index = glyph_index;
6238 format &= ~GGO_GLYPH_INDEX;
6239 /* TODO: Window also turns off tategaki for glyphs passed in by index
6240 if their unicode code points fall outside of the range that is
6241 rotated. */
6242 } else {
6243 BOOL vert;
6244 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6245 ft_face = font->ft_face;
6246 original_index = glyph_index;
6247 if (!vert && tategaki)
6248 tategaki = check_unicode_tategaki(glyph);
6251 if(format & GGO_UNHINTED) {
6252 load_flags |= FT_LOAD_NO_HINTING;
6253 format &= ~GGO_UNHINTED;
6256 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6257 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6258 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6259 font->gmsize * sizeof(GM*));
6260 } else {
6261 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6262 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6264 *lpgm = FONT_GM(font,original_index)->gm;
6265 *abc = FONT_GM(font,original_index)->abc;
6266 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6267 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6268 lpgm->gmCellIncX, lpgm->gmCellIncY);
6269 return 1; /* FIXME */
6273 if (!font->gm[original_index / GM_BLOCK_SIZE])
6274 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6276 /* Scaling factor */
6277 if (font->aveWidth)
6279 TEXTMETRICW tm;
6281 get_text_metrics(font, &tm);
6283 widthRatio = (double)font->aveWidth;
6284 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6286 else
6287 widthRatio = font->scale_y;
6289 /* Scaling transform */
6290 if (widthRatio != 1.0 || font->scale_y != 1.0)
6292 FT_Matrix scaleMat;
6293 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6294 scaleMat.xy = 0;
6295 scaleMat.yx = 0;
6296 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6298 pFT_Matrix_Multiply(&scaleMat, &transMat);
6299 needsTransform = TRUE;
6302 /* Slant transform */
6303 if (font->fake_italic) {
6304 FT_Matrix slantMat;
6306 slantMat.xx = (1 << 16);
6307 slantMat.xy = ((1 << 16) >> 2);
6308 slantMat.yx = 0;
6309 slantMat.yy = (1 << 16);
6310 pFT_Matrix_Multiply(&slantMat, &transMat);
6311 needsTransform = TRUE;
6314 /* Rotation transform */
6315 transMatUnrotated = transMat;
6316 transMatTategaki = transMat;
6317 if(font->orientation || tategaki) {
6318 FT_Matrix rotationMat;
6319 FT_Matrix taterotationMat;
6320 FT_Vector vecAngle;
6322 double orient = font->orientation / 10.0;
6323 double tate_orient = 0.f;
6325 if (tategaki)
6326 tate_orient = ((font->orientation+900)%3600)/10.0;
6327 else
6328 tate_orient = font->orientation/10.0;
6330 if (orient)
6332 angle = FT_FixedFromFloat(orient);
6333 pFT_Vector_Unit(&vecAngle, angle);
6334 rotationMat.xx = vecAngle.x;
6335 rotationMat.xy = -vecAngle.y;
6336 rotationMat.yx = -rotationMat.xy;
6337 rotationMat.yy = rotationMat.xx;
6339 pFT_Matrix_Multiply(&rotationMat, &transMat);
6342 if (tate_orient)
6344 angle = FT_FixedFromFloat(tate_orient);
6345 pFT_Vector_Unit(&vecAngle, angle);
6346 taterotationMat.xx = vecAngle.x;
6347 taterotationMat.xy = -vecAngle.y;
6348 taterotationMat.yx = -taterotationMat.xy;
6349 taterotationMat.yy = taterotationMat.xx;
6350 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6353 needsTransform = TRUE;
6356 /* World transform */
6357 if (!is_identity_FMAT2(&font->font_desc.matrix))
6359 FT_Matrix worldMat;
6360 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6361 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6362 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6363 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6364 pFT_Matrix_Multiply(&worldMat, &transMat);
6365 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6366 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6367 needsTransform = TRUE;
6370 /* Extra transformation specified by caller */
6371 if (!is_identity_MAT2(lpmat))
6373 FT_Matrix extraMat;
6374 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6375 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6376 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6377 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6378 pFT_Matrix_Multiply(&extraMat, &transMat);
6379 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6380 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6381 needsTransform = TRUE;
6384 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6385 /* there is a freetype bug where vertical metrics are only
6386 properly scaled and correct in 2.4.0 or greater */
6387 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6388 vertical_metrics = FALSE;
6390 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6391 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6393 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6395 if(err) {
6396 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6397 return GDI_ERROR;
6400 metrics = ft_face->glyph->metrics;
6401 if(font->fake_bold)
6402 synthesize_bold_glyph(ft_face->glyph, font->ppem, &metrics);
6404 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6405 * by the text metrics. The proper behavior is to clip the glyph metrics to
6406 * fit within the maximums specified in the text metrics. */
6407 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6408 get_bitmap_text_metrics(incoming_font)) {
6409 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6410 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6411 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6412 metrics.horiBearingY = top;
6413 metrics.height = top - bottom;
6415 /* TODO: Are we supposed to clip the width as well...? */
6416 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6419 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6421 if(FT_IS_SCALABLE(incoming_font->ft_face) && !font->fake_bold) {
6422 TEXTMETRICW tm;
6423 if (get_text_metrics(incoming_font, &tm) &&
6424 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6425 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6426 if (avgAdvance &&
6427 (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6428 TRACE("Fixed-pitch full-width character detected\n");
6429 else
6430 avgAdvance = 0; /* cancel this feature */
6434 if(!needsTransform) {
6435 left = (INT)(metrics.horiBearingX) & -64;
6436 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6437 if (!avgAdvance)
6438 adv = (INT)(metrics.horiAdvance + 63) >> 6;
6439 else
6440 adv = (INT)avgAdvance * 2;
6442 top = (metrics.horiBearingY + 63) & -64;
6443 bottom = (metrics.horiBearingY - metrics.height) & -64;
6444 gm.gmCellIncX = adv;
6445 gm.gmCellIncY = 0;
6446 origin_x = left;
6447 origin_y = top;
6448 abc->abcA = origin_x >> 6;
6449 abc->abcB = metrics.width >> 6;
6450 } else {
6451 INT xc, yc;
6452 FT_Vector vec;
6453 FT_Pos lsb;
6455 left = right = 0;
6457 for(xc = 0; xc < 2; xc++) {
6458 for(yc = 0; yc < 2; yc++) {
6459 vec.x = metrics.horiBearingX + xc * metrics.width;
6460 vec.y = metrics.horiBearingY - yc * metrics.height;
6461 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6462 pFT_Vector_Transform(&vec, &transMatTategaki);
6463 if(xc == 0 && yc == 0) {
6464 left = right = vec.x;
6465 top = bottom = vec.y;
6466 } else {
6467 if(vec.x < left) left = vec.x;
6468 else if(vec.x > right) right = vec.x;
6469 if(vec.y < bottom) bottom = vec.y;
6470 else if(vec.y > top) top = vec.y;
6474 left = left & -64;
6475 right = (right + 63) & -64;
6476 bottom = bottom & -64;
6477 top = (top + 63) & -64;
6479 if (tategaki && (font->potm || get_outline_text_metrics(font)))
6481 if (vertical_metrics)
6482 lsb = metrics.horiBearingY + metrics.vertBearingY;
6483 else
6484 lsb = metrics.vertAdvance + (font->potm->otmDescent << 6);
6485 vec.x = lsb;
6486 vec.y = font->potm->otmDescent << 6;
6487 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
6488 pFT_Vector_Transform(&vec, &transMat);
6489 origin_x = (vec.x + left) & -64;
6490 origin_y = (vec.y + top + 63) & -64;
6492 else
6494 origin_x = left;
6495 origin_y = top;
6496 lsb = metrics.horiBearingX;
6499 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6500 if (vertical_metrics)
6501 vec.x = metrics.vertAdvance;
6502 else
6503 vec.x = metrics.horiAdvance;
6504 vec.y = 0;
6505 pFT_Vector_Transform(&vec, &transMat);
6506 gm.gmCellIncY = -((vec.y+63) >> 6);
6507 if (!avgAdvance || vec.y)
6508 gm.gmCellIncX = (vec.x+63) >> 6;
6509 else {
6510 vec.x = incoming_font->ntmAvgWidth;
6511 vec.y = 0;
6512 pFT_Vector_Transform(&vec, &transMat);
6513 gm.gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6516 if (vertical_metrics)
6517 vec.x = metrics.vertAdvance;
6518 else
6519 vec.x = metrics.horiAdvance;
6520 vec.y = 0;
6521 pFT_Vector_Transform(&vec, &transMatUnrotated);
6522 if (!avgAdvance || vec.y)
6523 adv = (vec.x+63) >> 6;
6524 else {
6525 vec.x = incoming_font->ntmAvgWidth;
6526 vec.y = 0;
6527 pFT_Vector_Transform(&vec, &transMatUnrotated);
6528 adv = pFT_MulFix(vec.x, em_scale) * 2;
6531 vec.x = lsb;
6532 vec.y = 0;
6533 pFT_Vector_Transform(&vec, &transMatUnrotated);
6534 abc->abcA = vec.x >> 6;
6536 vec.x = metrics.width;
6537 vec.y = 0;
6538 pFT_Vector_Transform(&vec, &transMatUnrotated);
6539 if (vec.x >= 0)
6540 abc->abcB = vec.x >> 6;
6541 else
6542 abc->abcB = -vec.x >> 6;
6545 width = (right - left) >> 6;
6546 height = (top - bottom) >> 6;
6547 gm.gmBlackBoxX = width ? width : 1;
6548 gm.gmBlackBoxY = height ? height : 1;
6549 gm.gmptGlyphOrigin.x = origin_x >> 6;
6550 gm.gmptGlyphOrigin.y = origin_y >> 6;
6551 if (!abc->abcB) abc->abcB = 1;
6552 abc->abcC = adv - abc->abcA - abc->abcB;
6554 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
6555 wine_dbgstr_point(&gm.gmptGlyphOrigin),
6556 gm.gmCellIncX, gm.gmCellIncY);
6558 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6559 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6561 FONT_GM(font,original_index)->gm = gm;
6562 FONT_GM(font,original_index)->abc = *abc;
6563 FONT_GM(font,original_index)->init = TRUE;
6566 if(format == GGO_METRICS)
6568 *lpgm = gm;
6569 return 1; /* FIXME */
6572 if(ft_face->glyph->format != ft_glyph_format_outline &&
6573 (format == GGO_NATIVE || format == GGO_BEZIER))
6575 TRACE("loaded a bitmap\n");
6576 return GDI_ERROR;
6579 switch(format) {
6580 case GGO_BITMAP:
6581 pitch = ((width + 31) >> 5) << 2;
6582 needed = pitch * height;
6584 if(!buf || !buflen) break;
6585 if (!needed) return GDI_ERROR; /* empty glyph */
6587 switch(ft_face->glyph->format) {
6588 case ft_glyph_format_bitmap:
6590 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6591 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
6592 INT h = min( height, ft_face->glyph->bitmap.rows );
6593 while(h--) {
6594 memcpy(dst, src, w);
6595 src += ft_face->glyph->bitmap.pitch;
6596 dst += pitch;
6598 break;
6601 case ft_glyph_format_outline:
6602 ft_bitmap.width = width;
6603 ft_bitmap.rows = height;
6604 ft_bitmap.pitch = pitch;
6605 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6606 ft_bitmap.buffer = buf;
6608 if(needsTransform)
6609 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6611 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6613 /* Note: FreeType will only set 'black' bits for us. */
6614 memset(buf, 0, needed);
6615 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6616 break;
6618 default:
6619 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6620 return GDI_ERROR;
6622 break;
6624 case GGO_GRAY2_BITMAP:
6625 case GGO_GRAY4_BITMAP:
6626 case GGO_GRAY8_BITMAP:
6627 case WINE_GGO_GRAY16_BITMAP:
6629 unsigned int max_level, row, col;
6630 BYTE *start, *ptr;
6632 pitch = (width + 3) / 4 * 4;
6633 needed = pitch * height;
6635 if(!buf || !buflen) break;
6636 if (!needed) return GDI_ERROR; /* empty glyph */
6638 max_level = get_max_level( format );
6640 switch(ft_face->glyph->format) {
6641 case ft_glyph_format_bitmap:
6643 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6644 INT h = min( height, ft_face->glyph->bitmap.rows );
6645 INT x;
6646 memset( buf, 0, needed );
6647 while(h--) {
6648 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6649 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6650 src += ft_face->glyph->bitmap.pitch;
6651 dst += pitch;
6653 break;
6655 case ft_glyph_format_outline:
6657 ft_bitmap.width = width;
6658 ft_bitmap.rows = height;
6659 ft_bitmap.pitch = pitch;
6660 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6661 ft_bitmap.buffer = buf;
6663 if(needsTransform)
6664 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6666 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6668 memset(ft_bitmap.buffer, 0, buflen);
6670 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6672 if (max_level != 255)
6674 for (row = 0, start = buf; row < height; row++)
6676 for (col = 0, ptr = start; col < width; col++, ptr++)
6677 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6678 start += pitch;
6681 break;
6684 default:
6685 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6686 return GDI_ERROR;
6688 break;
6691 case WINE_GGO_HRGB_BITMAP:
6692 case WINE_GGO_HBGR_BITMAP:
6693 case WINE_GGO_VRGB_BITMAP:
6694 case WINE_GGO_VBGR_BITMAP:
6695 #ifdef FT_LCD_FILTER_H
6697 switch (ft_face->glyph->format)
6699 case FT_GLYPH_FORMAT_BITMAP:
6701 BYTE *src, *dst;
6702 INT src_pitch, x;
6704 pitch = width * 4;
6705 needed = pitch * height;
6707 if (!buf || !buflen) break;
6708 if (!needed) return GDI_ERROR; /* empty glyph */
6710 memset(buf, 0, buflen);
6711 dst = buf;
6712 src = ft_face->glyph->bitmap.buffer;
6713 src_pitch = ft_face->glyph->bitmap.pitch;
6715 height = min( height, ft_face->glyph->bitmap.rows );
6716 while ( height-- )
6718 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6720 if ( src[x / 8] & masks[x % 8] )
6721 ((unsigned int *)dst)[x] = ~0u;
6723 src += src_pitch;
6724 dst += pitch;
6727 break;
6730 case FT_GLYPH_FORMAT_OUTLINE:
6732 unsigned int *dst;
6733 BYTE *src;
6734 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6735 INT x_shift, y_shift;
6736 BOOL rgb;
6737 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6738 FT_Render_Mode render_mode =
6739 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6740 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6742 if (!width || !height)
6744 if (!buf || !buflen) break;
6745 return GDI_ERROR;
6748 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6750 if ( render_mode == FT_RENDER_MODE_LCD)
6752 gm.gmBlackBoxX += 2;
6753 gm.gmptGlyphOrigin.x -= 1;
6754 left -= (1 << 6);
6756 else
6758 gm.gmBlackBoxY += 2;
6759 gm.gmptGlyphOrigin.y += 1;
6760 top += (1 << 6);
6764 width = gm.gmBlackBoxX;
6765 height = gm.gmBlackBoxY;
6766 pitch = width * 4;
6767 needed = pitch * height;
6769 if (!buf || !buflen) break;
6771 memset(buf, 0, buflen);
6772 dst = buf;
6773 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6775 if ( needsTransform )
6776 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
6778 if ( pFT_Library_SetLcdFilter )
6779 pFT_Library_SetLcdFilter( library, lcdfilter );
6780 pFT_Render_Glyph (ft_face->glyph, render_mode);
6782 src = ft_face->glyph->bitmap.buffer;
6783 src_pitch = ft_face->glyph->bitmap.pitch;
6784 src_width = ft_face->glyph->bitmap.width;
6785 src_height = ft_face->glyph->bitmap.rows;
6787 if ( render_mode == FT_RENDER_MODE_LCD)
6789 rgb_interval = 1;
6790 hmul = 3;
6791 vmul = 1;
6793 else
6795 rgb_interval = src_pitch;
6796 hmul = 1;
6797 vmul = 3;
6800 x_shift = ft_face->glyph->bitmap_left - (left >> 6);
6801 if ( x_shift < 0 )
6803 src += hmul * -x_shift;
6804 src_width -= hmul * -x_shift;
6806 else if ( x_shift > 0 )
6808 dst += x_shift;
6809 width -= x_shift;
6812 y_shift = (top >> 6) - ft_face->glyph->bitmap_top;
6813 if ( y_shift < 0 )
6815 src += src_pitch * vmul * -y_shift;
6816 src_height -= vmul * -y_shift;
6818 else if ( y_shift > 0 )
6820 dst += y_shift * ( pitch / sizeof(*dst) );
6821 height -= y_shift;
6824 width = min( width, src_width / hmul );
6825 height = min( height, src_height / vmul );
6827 while ( height-- )
6829 for ( x = 0; x < width; x++ )
6831 if ( rgb )
6833 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6834 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6835 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6836 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6838 else
6840 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6841 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6842 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6843 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6846 src += src_pitch * vmul;
6847 dst += pitch / sizeof(*dst);
6850 break;
6853 default:
6854 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6855 return GDI_ERROR;
6858 break;
6860 #else
6861 return GDI_ERROR;
6862 #endif
6864 case GGO_NATIVE:
6866 int contour, point = 0, first_pt;
6867 FT_Outline *outline = &ft_face->glyph->outline;
6868 TTPOLYGONHEADER *pph;
6869 TTPOLYCURVE *ppc;
6870 DWORD pph_start, cpfx, type;
6872 if(buflen == 0) buf = NULL;
6874 if (needsTransform && buf) {
6875 pFT_Outline_Transform(outline, &transMatTategaki);
6878 for(contour = 0; contour < outline->n_contours; contour++) {
6879 /* Ignore contours containing one point */
6880 if(point == outline->contours[contour]) {
6881 point++;
6882 continue;
6885 pph_start = needed;
6886 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6887 first_pt = point;
6888 if(buf) {
6889 pph->dwType = TT_POLYGON_TYPE;
6890 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6892 needed += sizeof(*pph);
6893 point++;
6894 while(point <= outline->contours[contour]) {
6895 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6896 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6897 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6898 cpfx = 0;
6899 do {
6900 if(buf)
6901 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6902 cpfx++;
6903 point++;
6904 } while(point <= outline->contours[contour] &&
6905 (outline->tags[point] & FT_Curve_Tag_On) ==
6906 (outline->tags[point-1] & FT_Curve_Tag_On));
6907 /* At the end of a contour Windows adds the start point, but
6908 only for Beziers */
6909 if(point > outline->contours[contour] &&
6910 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6911 if(buf)
6912 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6913 cpfx++;
6914 } else if(point <= outline->contours[contour] &&
6915 outline->tags[point] & FT_Curve_Tag_On) {
6916 /* add closing pt for bezier */
6917 if(buf)
6918 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6919 cpfx++;
6920 point++;
6922 if(buf) {
6923 ppc->wType = type;
6924 ppc->cpfx = cpfx;
6926 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6928 if(buf)
6929 pph->cb = needed - pph_start;
6931 break;
6933 case GGO_BEZIER:
6935 /* Convert the quadratic Beziers to cubic Beziers.
6936 The parametric eqn for a cubic Bezier is, from PLRM:
6937 r(t) = at^3 + bt^2 + ct + r0
6938 with the control points:
6939 r1 = r0 + c/3
6940 r2 = r1 + (c + b)/3
6941 r3 = r0 + c + b + a
6943 A quadratic Bezier has the form:
6944 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6946 So equating powers of t leads to:
6947 r1 = 2/3 p1 + 1/3 p0
6948 r2 = 2/3 p1 + 1/3 p2
6949 and of course r0 = p0, r3 = p2
6952 int contour, point = 0, first_pt;
6953 FT_Outline *outline = &ft_face->glyph->outline;
6954 TTPOLYGONHEADER *pph;
6955 TTPOLYCURVE *ppc;
6956 DWORD pph_start, cpfx, type;
6957 FT_Vector cubic_control[4];
6958 if(buflen == 0) buf = NULL;
6960 if (needsTransform && buf) {
6961 pFT_Outline_Transform(outline, &transMat);
6964 for(contour = 0; contour < outline->n_contours; contour++) {
6965 pph_start = needed;
6966 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6967 first_pt = point;
6968 if(buf) {
6969 pph->dwType = TT_POLYGON_TYPE;
6970 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6972 needed += sizeof(*pph);
6973 point++;
6974 while(point <= outline->contours[contour]) {
6975 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6976 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6977 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6978 cpfx = 0;
6979 do {
6980 if(type == TT_PRIM_LINE) {
6981 if(buf)
6982 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6983 cpfx++;
6984 point++;
6985 } else {
6986 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6987 so cpfx = 3n */
6989 /* FIXME: Possible optimization in endpoint calculation
6990 if there are two consecutive curves */
6991 cubic_control[0] = outline->points[point-1];
6992 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6993 cubic_control[0].x += outline->points[point].x + 1;
6994 cubic_control[0].y += outline->points[point].y + 1;
6995 cubic_control[0].x >>= 1;
6996 cubic_control[0].y >>= 1;
6998 if(point+1 > outline->contours[contour])
6999 cubic_control[3] = outline->points[first_pt];
7000 else {
7001 cubic_control[3] = outline->points[point+1];
7002 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
7003 cubic_control[3].x += outline->points[point].x + 1;
7004 cubic_control[3].y += outline->points[point].y + 1;
7005 cubic_control[3].x >>= 1;
7006 cubic_control[3].y >>= 1;
7009 /* r1 = 1/3 p0 + 2/3 p1
7010 r2 = 1/3 p2 + 2/3 p1 */
7011 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
7012 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
7013 cubic_control[2] = cubic_control[1];
7014 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
7015 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
7016 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
7017 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
7018 if(buf) {
7019 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
7020 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
7021 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
7023 cpfx += 3;
7024 point++;
7026 } while(point <= outline->contours[contour] &&
7027 (outline->tags[point] & FT_Curve_Tag_On) ==
7028 (outline->tags[point-1] & FT_Curve_Tag_On));
7029 /* At the end of a contour Windows adds the start point,
7030 but only for Beziers and we've already done that.
7032 if(point <= outline->contours[contour] &&
7033 outline->tags[point] & FT_Curve_Tag_On) {
7034 /* This is the closing pt of a bezier, but we've already
7035 added it, so just inc point and carry on */
7036 point++;
7038 if(buf) {
7039 ppc->wType = type;
7040 ppc->cpfx = cpfx;
7042 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
7044 if(buf)
7045 pph->cb = needed - pph_start;
7047 break;
7050 default:
7051 FIXME("Unsupported format %d\n", format);
7052 return GDI_ERROR;
7054 *lpgm = gm;
7055 return needed;
7058 static BOOL get_bitmap_text_metrics(GdiFont *font)
7060 FT_Face ft_face = font->ft_face;
7061 FT_WinFNT_HeaderRec winfnt_header;
7062 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7063 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7064 font->potm->otmSize = size;
7066 #define TM font->potm->otmTextMetrics
7067 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7069 TM.tmHeight = winfnt_header.pixel_height;
7070 TM.tmAscent = winfnt_header.ascent;
7071 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7072 TM.tmInternalLeading = winfnt_header.internal_leading;
7073 TM.tmExternalLeading = winfnt_header.external_leading;
7074 TM.tmAveCharWidth = winfnt_header.avg_width;
7075 TM.tmMaxCharWidth = winfnt_header.max_width;
7076 TM.tmWeight = winfnt_header.weight;
7077 TM.tmOverhang = 0;
7078 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7079 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7080 TM.tmFirstChar = winfnt_header.first_char;
7081 TM.tmLastChar = winfnt_header.last_char;
7082 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7083 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7084 TM.tmItalic = winfnt_header.italic;
7085 TM.tmUnderlined = font->underline;
7086 TM.tmStruckOut = font->strikeout;
7087 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7088 TM.tmCharSet = winfnt_header.charset;
7090 else
7092 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7093 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7094 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7095 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7096 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7097 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7098 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7099 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7100 TM.tmOverhang = 0;
7101 TM.tmDigitizedAspectX = 96; /* FIXME */
7102 TM.tmDigitizedAspectY = 96; /* FIXME */
7103 TM.tmFirstChar = 1;
7104 TM.tmLastChar = 255;
7105 TM.tmDefaultChar = 32;
7106 TM.tmBreakChar = 32;
7107 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7108 TM.tmUnderlined = font->underline;
7109 TM.tmStruckOut = font->strikeout;
7110 /* NB inverted meaning of TMPF_FIXED_PITCH */
7111 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
7112 TM.tmCharSet = font->charset;
7114 #undef TM
7116 return TRUE;
7120 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7122 double scale_x, scale_y;
7124 if (font->aveWidth)
7126 scale_x = (double)font->aveWidth;
7127 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7129 else
7130 scale_x = font->scale_y;
7132 scale_x *= fabs(font->font_desc.matrix.eM11);
7133 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7135 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7136 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7138 SCALE_Y(ptm->tmHeight);
7139 SCALE_Y(ptm->tmAscent);
7140 SCALE_Y(ptm->tmDescent);
7141 SCALE_Y(ptm->tmInternalLeading);
7142 SCALE_Y(ptm->tmExternalLeading);
7143 SCALE_Y(ptm->tmOverhang);
7145 SCALE_X(ptm->tmAveCharWidth);
7146 SCALE_X(ptm->tmMaxCharWidth);
7148 #undef SCALE_X
7149 #undef SCALE_Y
7152 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7154 double scale_x, scale_y;
7156 if (font->aveWidth)
7158 scale_x = (double)font->aveWidth;
7159 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7161 else
7162 scale_x = font->scale_y;
7164 scale_x *= fabs(font->font_desc.matrix.eM11);
7165 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7167 scale_font_metrics(font, &potm->otmTextMetrics);
7169 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7170 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7172 SCALE_Y(potm->otmAscent);
7173 SCALE_Y(potm->otmDescent);
7174 SCALE_Y(potm->otmLineGap);
7175 SCALE_Y(potm->otmsCapEmHeight);
7176 SCALE_Y(potm->otmsXHeight);
7177 SCALE_Y(potm->otmrcFontBox.top);
7178 SCALE_Y(potm->otmrcFontBox.bottom);
7179 SCALE_X(potm->otmrcFontBox.left);
7180 SCALE_X(potm->otmrcFontBox.right);
7181 SCALE_Y(potm->otmMacAscent);
7182 SCALE_Y(potm->otmMacDescent);
7183 SCALE_Y(potm->otmMacLineGap);
7184 SCALE_X(potm->otmptSubscriptSize.x);
7185 SCALE_Y(potm->otmptSubscriptSize.y);
7186 SCALE_X(potm->otmptSubscriptOffset.x);
7187 SCALE_Y(potm->otmptSubscriptOffset.y);
7188 SCALE_X(potm->otmptSuperscriptSize.x);
7189 SCALE_Y(potm->otmptSuperscriptSize.y);
7190 SCALE_X(potm->otmptSuperscriptOffset.x);
7191 SCALE_Y(potm->otmptSuperscriptOffset.y);
7192 SCALE_Y(potm->otmsStrikeoutSize);
7193 SCALE_Y(potm->otmsStrikeoutPosition);
7194 SCALE_Y(potm->otmsUnderscoreSize);
7195 SCALE_Y(potm->otmsUnderscorePosition);
7197 #undef SCALE_X
7198 #undef SCALE_Y
7201 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7203 if(!font->potm)
7205 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7207 /* Make sure that the font has sane width/height ratio */
7208 if (font->aveWidth)
7210 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7212 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7213 font->aveWidth = 0;
7217 *ptm = font->potm->otmTextMetrics;
7218 scale_font_metrics(font, ptm);
7219 return TRUE;
7222 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7224 int i;
7226 for(i = 0; i < ft_face->num_charmaps; i++)
7228 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7229 return TRUE;
7231 return FALSE;
7234 static BOOL get_outline_text_metrics(GdiFont *font)
7236 BOOL ret = FALSE;
7237 FT_Face ft_face = font->ft_face;
7238 UINT needed, lenfam, lensty, lenface, lenfull;
7239 TT_OS2 *pOS2;
7240 TT_HoriHeader *pHori;
7241 TT_Postscript *pPost;
7242 FT_Fixed em_scale;
7243 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7244 char *cp;
7245 INT ascent, descent;
7247 TRACE("font=%p\n", font);
7249 if(!FT_IS_SCALABLE(ft_face))
7250 return FALSE;
7252 needed = sizeof(*font->potm);
7254 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7255 family_nameW = strdupW(font->name);
7257 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7258 if (!style_nameW)
7260 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7261 style_nameW = towstr( CP_ACP, ft_face->style_name );
7263 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7265 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7266 if (!face_nameW)
7268 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7269 face_nameW = strdupW(font->name);
7271 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7272 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7274 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7275 if (!full_nameW)
7277 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7278 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7279 full_nameW = strdupW(fake_nameW);
7281 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7283 /* These names should be read from the TT name table */
7285 /* length of otmpFamilyName */
7286 needed += lenfam;
7288 /* length of otmpFaceName */
7289 needed += lenface;
7291 /* length of otmpStyleName */
7292 needed += lensty;
7294 /* length of otmpFullName */
7295 needed += lenfull;
7298 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7300 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7301 if(!pOS2) {
7302 FIXME("Can't find OS/2 table - not TT font?\n");
7303 goto end;
7306 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7307 if(!pHori) {
7308 FIXME("Can't find HHEA table - not TT font?\n");
7309 goto end;
7312 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7314 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",
7315 pOS2->usWinAscent, pOS2->usWinDescent,
7316 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7317 pOS2->xAvgCharWidth,
7318 ft_face->ascender, ft_face->descender, ft_face->height,
7319 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7320 ft_face->bbox.yMax, ft_face->bbox.yMin);
7322 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7323 font->potm->otmSize = needed;
7325 #define TM font->potm->otmTextMetrics
7327 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
7328 ascent = pHori->Ascender;
7329 descent = -pHori->Descender;
7330 } else {
7331 ascent = pOS2->usWinAscent;
7332 descent = pOS2->usWinDescent;
7335 font->ntmCellHeight = ascent + descent;
7336 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7338 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7339 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7341 if(font->yMax) {
7342 TM.tmAscent = font->yMax;
7343 TM.tmDescent = -font->yMin;
7344 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7345 } else {
7346 TM.tmAscent = SCALE_Y(ascent);
7347 TM.tmDescent = SCALE_Y(descent);
7348 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7351 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7353 /* MSDN says:
7354 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7356 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7357 ((ascent + descent) -
7358 (pHori->Ascender - pHori->Descender))));
7360 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7361 if (TM.tmAveCharWidth == 0) {
7362 TM.tmAveCharWidth = 1;
7364 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7365 TM.tmWeight = FW_REGULAR;
7366 if (font->fake_bold) {
7367 TM.tmAveCharWidth++;
7368 TM.tmMaxCharWidth++;
7369 TM.tmWeight = FW_BOLD;
7371 else
7373 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7375 if (pOS2->usWeightClass > FW_MEDIUM)
7376 TM.tmWeight = pOS2->usWeightClass;
7378 else if (pOS2->usWeightClass <= FW_MEDIUM)
7379 TM.tmWeight = pOS2->usWeightClass;
7381 TM.tmOverhang = 0;
7382 TM.tmDigitizedAspectX = 96; /* FIXME */
7383 TM.tmDigitizedAspectY = 96; /* FIXME */
7384 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7385 * symbol range to 0 - f0ff
7388 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7390 TM.tmFirstChar = 0;
7391 switch(GetACP())
7393 case 1255: /* Hebrew */
7394 TM.tmLastChar = 0xf896;
7395 break;
7396 case 1257: /* Baltic */
7397 TM.tmLastChar = 0xf8fd;
7398 break;
7399 default:
7400 TM.tmLastChar = 0xf0ff;
7402 TM.tmBreakChar = 0x20;
7403 TM.tmDefaultChar = 0x1f;
7405 else
7407 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7408 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7410 if(pOS2->usFirstCharIndex <= 1)
7411 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7412 else if (pOS2->usFirstCharIndex > 0xff)
7413 TM.tmBreakChar = 0x20;
7414 else
7415 TM.tmBreakChar = pOS2->usFirstCharIndex;
7416 TM.tmDefaultChar = TM.tmBreakChar - 1;
7418 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7419 TM.tmUnderlined = font->underline;
7420 TM.tmStruckOut = font->strikeout;
7422 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7423 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7424 (pOS2->version == 0xFFFFU ||
7425 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7426 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7427 else
7428 TM.tmPitchAndFamily = 0;
7430 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7432 case PAN_FAMILY_SCRIPT:
7433 TM.tmPitchAndFamily |= FF_SCRIPT;
7434 break;
7436 case PAN_FAMILY_DECORATIVE:
7437 TM.tmPitchAndFamily |= FF_DECORATIVE;
7438 break;
7440 case PAN_ANY:
7441 case PAN_NO_FIT:
7442 case PAN_FAMILY_TEXT_DISPLAY:
7443 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7444 /* which is clearly not what the panose spec says. */
7445 default:
7446 if(TM.tmPitchAndFamily == 0 || /* fixed */
7447 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7448 TM.tmPitchAndFamily = FF_MODERN;
7449 else
7451 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7453 case PAN_ANY:
7454 case PAN_NO_FIT:
7455 default:
7456 TM.tmPitchAndFamily |= FF_DONTCARE;
7457 break;
7459 case PAN_SERIF_COVE:
7460 case PAN_SERIF_OBTUSE_COVE:
7461 case PAN_SERIF_SQUARE_COVE:
7462 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7463 case PAN_SERIF_SQUARE:
7464 case PAN_SERIF_THIN:
7465 case PAN_SERIF_BONE:
7466 case PAN_SERIF_EXAGGERATED:
7467 case PAN_SERIF_TRIANGLE:
7468 TM.tmPitchAndFamily |= FF_ROMAN;
7469 break;
7471 case PAN_SERIF_NORMAL_SANS:
7472 case PAN_SERIF_OBTUSE_SANS:
7473 case PAN_SERIF_PERP_SANS:
7474 case PAN_SERIF_FLARED:
7475 case PAN_SERIF_ROUNDED:
7476 TM.tmPitchAndFamily |= FF_SWISS;
7477 break;
7480 break;
7483 if(FT_IS_SCALABLE(ft_face))
7484 TM.tmPitchAndFamily |= TMPF_VECTOR;
7486 if(FT_IS_SFNT(ft_face))
7488 if (font->ntmFlags & NTM_PS_OPENTYPE)
7489 TM.tmPitchAndFamily |= TMPF_DEVICE;
7490 else
7491 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7494 TM.tmCharSet = font->charset;
7496 font->potm->otmFiller = 0;
7497 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7498 font->potm->otmfsSelection = pOS2->fsSelection;
7499 font->potm->otmfsType = pOS2->fsType;
7500 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7501 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7502 font->potm->otmItalicAngle = 0; /* POST table */
7503 font->potm->otmEMSquare = ft_face->units_per_EM;
7504 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7505 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7506 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7507 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7508 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7509 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7510 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7511 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7512 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7513 font->potm->otmMacAscent = TM.tmAscent;
7514 font->potm->otmMacDescent = -TM.tmDescent;
7515 font->potm->otmMacLineGap = font->potm->otmLineGap;
7516 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7517 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7518 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7519 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7520 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7521 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7522 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7523 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7524 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7525 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7526 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7527 if(!pPost) {
7528 font->potm->otmsUnderscoreSize = 0;
7529 font->potm->otmsUnderscorePosition = 0;
7530 } else {
7531 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7532 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7534 #undef SCALE_X
7535 #undef SCALE_Y
7536 #undef TM
7538 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7539 cp = (char*)font->potm + sizeof(*font->potm);
7540 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7541 strcpyW((WCHAR*)cp, family_nameW);
7542 cp += lenfam;
7543 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7544 strcpyW((WCHAR*)cp, style_nameW);
7545 cp += lensty;
7546 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7547 strcpyW((WCHAR*)cp, face_nameW);
7548 cp += lenface;
7549 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7550 strcpyW((WCHAR*)cp, full_nameW);
7551 ret = TRUE;
7553 end:
7554 HeapFree(GetProcessHeap(), 0, style_nameW);
7555 HeapFree(GetProcessHeap(), 0, family_nameW);
7556 HeapFree(GetProcessHeap(), 0, face_nameW);
7557 HeapFree(GetProcessHeap(), 0, full_nameW);
7558 return ret;
7561 /*************************************************************
7562 * freetype_GetGlyphOutline
7564 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7565 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7567 struct freetype_physdev *physdev = get_freetype_dev( dev );
7568 DWORD ret;
7569 ABC abc;
7571 if (!physdev->font)
7573 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7574 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7577 GDI_CheckNotLock();
7578 EnterCriticalSection( &freetype_cs );
7579 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7580 LeaveCriticalSection( &freetype_cs );
7581 return ret;
7584 /*************************************************************
7585 * freetype_GetTextMetrics
7587 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7589 struct freetype_physdev *physdev = get_freetype_dev( dev );
7590 BOOL ret;
7592 if (!physdev->font)
7594 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7595 return dev->funcs->pGetTextMetrics( dev, metrics );
7598 GDI_CheckNotLock();
7599 EnterCriticalSection( &freetype_cs );
7600 ret = get_text_metrics( physdev->font, metrics );
7601 LeaveCriticalSection( &freetype_cs );
7602 return ret;
7605 /*************************************************************
7606 * freetype_GetOutlineTextMetrics
7608 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7610 struct freetype_physdev *physdev = get_freetype_dev( dev );
7611 UINT ret = 0;
7613 if (!physdev->font)
7615 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7616 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7619 TRACE("font=%p\n", physdev->font);
7621 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7623 GDI_CheckNotLock();
7624 EnterCriticalSection( &freetype_cs );
7626 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7628 if(cbSize >= physdev->font->potm->otmSize)
7630 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7631 scale_outline_font_metrics(physdev->font, potm);
7633 ret = physdev->font->potm->otmSize;
7635 LeaveCriticalSection( &freetype_cs );
7636 return ret;
7639 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7641 child->font = alloc_font();
7642 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7643 if(!child->font->ft_face)
7645 free_font(child->font);
7646 child->font = NULL;
7647 return FALSE;
7650 child->font->font_desc = font->font_desc;
7651 child->font->ntmFlags = child->face->ntmFlags;
7652 child->font->orientation = font->orientation;
7653 child->font->scale_y = font->scale_y;
7654 child->font->name = strdupW(child->face->family->FamilyName);
7655 child->font->base_font = font;
7656 TRACE("created child font %p for base %p\n", child->font, font);
7657 return TRUE;
7660 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
7662 FT_UInt g,o;
7663 CHILD_FONT *child_font;
7665 if(font->base_font)
7666 font = font->base_font;
7668 *linked_font = font;
7670 if((*glyph = get_glyph_index(font, c)))
7672 o = *glyph;
7673 *glyph = get_GSUB_vert_glyph(font, *glyph);
7674 *vert = (o != *glyph);
7675 return TRUE;
7678 if (c < 32) goto done; /* don't check linked fonts for control characters */
7680 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7682 if(!child_font->font)
7683 if(!load_child_font(font, child_font))
7684 continue;
7686 if(!child_font->font->ft_face)
7687 continue;
7688 g = get_glyph_index(child_font->font, c);
7689 o = g;
7690 g = get_GSUB_vert_glyph(child_font->font, g);
7691 if(g)
7693 *glyph = g;
7694 *linked_font = child_font->font;
7695 *vert = (o != g);
7696 return TRUE;
7700 done:
7701 *vert = FALSE;
7702 return FALSE;
7705 /*************************************************************
7706 * freetype_GetCharWidth
7708 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7710 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7711 UINT c;
7712 GLYPHMETRICS gm;
7713 ABC abc;
7714 struct freetype_physdev *physdev = get_freetype_dev( dev );
7716 if (!physdev->font)
7718 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7719 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7722 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7724 GDI_CheckNotLock();
7725 EnterCriticalSection( &freetype_cs );
7726 for(c = firstChar; c <= lastChar; c++) {
7727 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7728 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7730 LeaveCriticalSection( &freetype_cs );
7731 return TRUE;
7734 /*************************************************************
7735 * freetype_GetCharABCWidths
7737 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7739 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7740 UINT c;
7741 GLYPHMETRICS gm;
7742 struct freetype_physdev *physdev = get_freetype_dev( dev );
7744 if (!physdev->font)
7746 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7747 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7750 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7752 GDI_CheckNotLock();
7753 EnterCriticalSection( &freetype_cs );
7755 for(c = firstChar; c <= lastChar; c++, buffer++)
7756 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7758 LeaveCriticalSection( &freetype_cs );
7759 return TRUE;
7762 /*************************************************************
7763 * freetype_GetCharABCWidthsI
7765 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7767 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7768 UINT c;
7769 GLYPHMETRICS gm;
7770 struct freetype_physdev *physdev = get_freetype_dev( dev );
7772 if (!physdev->font)
7774 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7775 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7778 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7779 return FALSE;
7781 GDI_CheckNotLock();
7782 EnterCriticalSection( &freetype_cs );
7784 for(c = 0; c < count; c++, buffer++)
7785 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7786 &gm, buffer, 0, NULL, &identity );
7788 LeaveCriticalSection( &freetype_cs );
7789 return TRUE;
7792 /*************************************************************
7793 * freetype_GetTextExtentExPoint
7795 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7797 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7798 INT idx, pos;
7799 ABC abc;
7800 GLYPHMETRICS gm;
7801 struct freetype_physdev *physdev = get_freetype_dev( dev );
7803 if (!physdev->font)
7805 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7806 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7809 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7811 GDI_CheckNotLock();
7812 EnterCriticalSection( &freetype_cs );
7814 for (idx = pos = 0; idx < count; idx++)
7816 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7817 pos += abc.abcA + abc.abcB + abc.abcC;
7818 dxs[idx] = pos;
7821 LeaveCriticalSection( &freetype_cs );
7822 return TRUE;
7825 /*************************************************************
7826 * freetype_GetTextExtentExPointI
7828 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7830 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7831 INT idx, pos;
7832 ABC abc;
7833 GLYPHMETRICS gm;
7834 struct freetype_physdev *physdev = get_freetype_dev( dev );
7836 if (!physdev->font)
7838 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7839 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7842 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7844 GDI_CheckNotLock();
7845 EnterCriticalSection( &freetype_cs );
7847 for (idx = pos = 0; idx < count; idx++)
7849 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7850 &gm, &abc, 0, NULL, &identity );
7851 pos += abc.abcA + abc.abcB + abc.abcC;
7852 dxs[idx] = pos;
7855 LeaveCriticalSection( &freetype_cs );
7856 return TRUE;
7859 /*************************************************************
7860 * freetype_GetFontData
7862 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7864 struct freetype_physdev *physdev = get_freetype_dev( dev );
7866 if (!physdev->font)
7868 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7869 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7872 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7873 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7874 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7876 return get_font_data( physdev->font, table, offset, buf, cbData );
7879 /*************************************************************
7880 * freetype_GetTextFace
7882 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7884 INT n;
7885 struct freetype_physdev *physdev = get_freetype_dev( dev );
7887 if (!physdev->font)
7889 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7890 return dev->funcs->pGetTextFace( dev, count, str );
7893 n = strlenW(physdev->font->name) + 1;
7894 if (str)
7896 lstrcpynW(str, physdev->font->name, count);
7897 n = min(count, n);
7899 return n;
7902 /*************************************************************
7903 * freetype_GetTextCharsetInfo
7905 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7907 struct freetype_physdev *physdev = get_freetype_dev( dev );
7909 if (!physdev->font)
7911 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7912 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7914 if (fs) *fs = physdev->font->fs;
7915 return physdev->font->charset;
7918 /* Retrieve a list of supported Unicode ranges for a given font.
7919 * Can be called with NULL gs to calculate the buffer size. Returns
7920 * the number of ranges found.
7922 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7924 DWORD num_ranges = 0;
7926 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7928 FT_UInt glyph_code;
7929 FT_ULong char_code, char_code_prev;
7931 glyph_code = 0;
7932 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7934 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7935 face->num_glyphs, glyph_code, char_code);
7937 if (!glyph_code) return 0;
7939 if (gs)
7941 gs->ranges[0].wcLow = (USHORT)char_code;
7942 gs->ranges[0].cGlyphs = 0;
7943 gs->cGlyphsSupported = 0;
7946 num_ranges = 1;
7947 while (glyph_code)
7949 if (char_code < char_code_prev)
7951 ERR("expected increasing char code from FT_Get_Next_Char\n");
7952 return 0;
7954 if (char_code - char_code_prev > 1)
7956 num_ranges++;
7957 if (gs)
7959 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7960 gs->ranges[num_ranges - 1].cGlyphs = 1;
7961 gs->cGlyphsSupported++;
7964 else if (gs)
7966 gs->ranges[num_ranges - 1].cGlyphs++;
7967 gs->cGlyphsSupported++;
7969 char_code_prev = char_code;
7970 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7973 else
7974 FIXME("encoding %u not supported\n", face->charmap->encoding);
7976 return num_ranges;
7979 /*************************************************************
7980 * freetype_GetFontUnicodeRanges
7982 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7984 struct freetype_physdev *physdev = get_freetype_dev( dev );
7985 DWORD size, num_ranges;
7987 if (!physdev->font)
7989 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7990 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7993 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7994 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7995 if (glyphset)
7997 glyphset->cbThis = size;
7998 glyphset->cRanges = num_ranges;
7999 glyphset->flAccel = 0;
8001 return size;
8004 /*************************************************************
8005 * freetype_FontIsLinked
8007 static BOOL freetype_FontIsLinked( PHYSDEV dev )
8009 struct freetype_physdev *physdev = get_freetype_dev( dev );
8010 BOOL ret;
8012 if (!physdev->font)
8014 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8015 return dev->funcs->pFontIsLinked( dev );
8018 GDI_CheckNotLock();
8019 EnterCriticalSection( &freetype_cs );
8020 ret = !list_empty(&physdev->font->child_fonts);
8021 LeaveCriticalSection( &freetype_cs );
8022 return ret;
8025 /*************************************************************************
8026 * GetRasterizerCaps (GDI32.@)
8028 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8030 lprs->nSize = sizeof(RASTERIZER_STATUS);
8031 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8032 lprs->nLanguageID = 0;
8033 return TRUE;
8036 /*************************************************************
8037 * freetype_GdiRealizationInfo
8039 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
8041 struct freetype_physdev *physdev = get_freetype_dev( dev );
8042 realization_info_t *info = ptr;
8044 if (!physdev->font)
8046 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
8047 return dev->funcs->pGdiRealizationInfo( dev, ptr );
8050 FIXME("(%p, %p): stub!\n", physdev->font, info);
8052 info->flags = 1;
8053 if(FT_IS_SCALABLE(physdev->font->ft_face))
8054 info->flags |= 2;
8056 info->cache_num = physdev->font->cache_num;
8057 info->unknown2 = -1;
8058 return TRUE;
8061 /*************************************************************************
8062 * Kerning support for TrueType fonts
8064 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8066 struct TT_kern_table
8068 USHORT version;
8069 USHORT nTables;
8072 struct TT_kern_subtable
8074 USHORT version;
8075 USHORT length;
8076 union
8078 USHORT word;
8079 struct
8081 USHORT horizontal : 1;
8082 USHORT minimum : 1;
8083 USHORT cross_stream: 1;
8084 USHORT override : 1;
8085 USHORT reserved1 : 4;
8086 USHORT format : 8;
8087 } bits;
8088 } coverage;
8091 struct TT_format0_kern_subtable
8093 USHORT nPairs;
8094 USHORT searchRange;
8095 USHORT entrySelector;
8096 USHORT rangeShift;
8099 struct TT_kern_pair
8101 USHORT left;
8102 USHORT right;
8103 short value;
8106 static DWORD parse_format0_kern_subtable(GdiFont *font,
8107 const struct TT_format0_kern_subtable *tt_f0_ks,
8108 const USHORT *glyph_to_char,
8109 KERNINGPAIR *kern_pair, DWORD cPairs)
8111 USHORT i, nPairs;
8112 const struct TT_kern_pair *tt_kern_pair;
8114 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8116 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8118 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8119 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8120 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8122 if (!kern_pair || !cPairs)
8123 return nPairs;
8125 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8127 nPairs = min(nPairs, cPairs);
8129 for (i = 0; i < nPairs; i++)
8131 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8132 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8133 /* this algorithm appears to better match what Windows does */
8134 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8135 if (kern_pair->iKernAmount < 0)
8137 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8138 kern_pair->iKernAmount -= font->ppem;
8140 else if (kern_pair->iKernAmount > 0)
8142 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8143 kern_pair->iKernAmount += font->ppem;
8145 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8147 TRACE("left %u right %u value %d\n",
8148 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8150 kern_pair++;
8152 TRACE("copied %u entries\n", nPairs);
8153 return nPairs;
8156 /*************************************************************
8157 * freetype_GetKerningPairs
8159 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8161 DWORD length;
8162 void *buf;
8163 const struct TT_kern_table *tt_kern_table;
8164 const struct TT_kern_subtable *tt_kern_subtable;
8165 USHORT i, nTables;
8166 USHORT *glyph_to_char;
8167 GdiFont *font;
8168 struct freetype_physdev *physdev = get_freetype_dev( dev );
8170 if (!(font = physdev->font))
8172 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8173 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8176 GDI_CheckNotLock();
8177 EnterCriticalSection( &freetype_cs );
8178 if (font->total_kern_pairs != (DWORD)-1)
8180 if (cPairs && kern_pair)
8182 cPairs = min(cPairs, font->total_kern_pairs);
8183 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8185 else cPairs = font->total_kern_pairs;
8187 LeaveCriticalSection( &freetype_cs );
8188 return cPairs;
8191 font->total_kern_pairs = 0;
8193 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8195 if (length == GDI_ERROR)
8197 TRACE("no kerning data in the font\n");
8198 LeaveCriticalSection( &freetype_cs );
8199 return 0;
8202 buf = HeapAlloc(GetProcessHeap(), 0, length);
8203 if (!buf)
8205 WARN("Out of memory\n");
8206 LeaveCriticalSection( &freetype_cs );
8207 return 0;
8210 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8212 /* build a glyph index to char code map */
8213 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8214 if (!glyph_to_char)
8216 WARN("Out of memory allocating a glyph index to char code map\n");
8217 HeapFree(GetProcessHeap(), 0, buf);
8218 LeaveCriticalSection( &freetype_cs );
8219 return 0;
8222 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8224 FT_UInt glyph_code;
8225 FT_ULong char_code;
8227 glyph_code = 0;
8228 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8230 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8231 font->ft_face->num_glyphs, glyph_code, char_code);
8233 while (glyph_code)
8235 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8237 /* FIXME: This doesn't match what Windows does: it does some fancy
8238 * things with duplicate glyph index to char code mappings, while
8239 * we just avoid overriding existing entries.
8241 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8242 glyph_to_char[glyph_code] = (USHORT)char_code;
8244 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8247 else
8249 ULONG n;
8251 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
8252 for (n = 0; n <= 65535; n++)
8253 glyph_to_char[n] = (USHORT)n;
8256 tt_kern_table = buf;
8257 nTables = GET_BE_WORD(tt_kern_table->nTables);
8258 TRACE("version %u, nTables %u\n",
8259 GET_BE_WORD(tt_kern_table->version), nTables);
8261 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8263 for (i = 0; i < nTables; i++)
8265 struct TT_kern_subtable tt_kern_subtable_copy;
8267 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8268 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8269 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8271 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8272 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8273 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8275 /* According to the TrueType specification this is the only format
8276 * that will be properly interpreted by Windows and OS/2
8278 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8280 DWORD new_chunk, old_total = font->total_kern_pairs;
8282 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8283 glyph_to_char, NULL, 0);
8284 font->total_kern_pairs += new_chunk;
8286 if (!font->kern_pairs)
8287 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8288 font->total_kern_pairs * sizeof(*font->kern_pairs));
8289 else
8290 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8291 font->total_kern_pairs * sizeof(*font->kern_pairs));
8293 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8294 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8296 else
8297 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8299 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8302 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8303 HeapFree(GetProcessHeap(), 0, buf);
8305 if (cPairs && kern_pair)
8307 cPairs = min(cPairs, font->total_kern_pairs);
8308 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8310 else cPairs = font->total_kern_pairs;
8312 LeaveCriticalSection( &freetype_cs );
8313 return cPairs;
8316 static const struct gdi_dc_funcs freetype_funcs =
8318 NULL, /* pAbortDoc */
8319 NULL, /* pAbortPath */
8320 NULL, /* pAlphaBlend */
8321 NULL, /* pAngleArc */
8322 NULL, /* pArc */
8323 NULL, /* pArcTo */
8324 NULL, /* pBeginPath */
8325 NULL, /* pBlendImage */
8326 NULL, /* pChord */
8327 NULL, /* pCloseFigure */
8328 NULL, /* pCreateCompatibleDC */
8329 freetype_CreateDC, /* pCreateDC */
8330 freetype_DeleteDC, /* pDeleteDC */
8331 NULL, /* pDeleteObject */
8332 NULL, /* pDeviceCapabilities */
8333 NULL, /* pEllipse */
8334 NULL, /* pEndDoc */
8335 NULL, /* pEndPage */
8336 NULL, /* pEndPath */
8337 freetype_EnumFonts, /* pEnumFonts */
8338 NULL, /* pEnumICMProfiles */
8339 NULL, /* pExcludeClipRect */
8340 NULL, /* pExtDeviceMode */
8341 NULL, /* pExtEscape */
8342 NULL, /* pExtFloodFill */
8343 NULL, /* pExtSelectClipRgn */
8344 NULL, /* pExtTextOut */
8345 NULL, /* pFillPath */
8346 NULL, /* pFillRgn */
8347 NULL, /* pFlattenPath */
8348 freetype_FontIsLinked, /* pFontIsLinked */
8349 NULL, /* pFrameRgn */
8350 NULL, /* pGdiComment */
8351 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
8352 NULL, /* pGetBoundsRect */
8353 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8354 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8355 freetype_GetCharWidth, /* pGetCharWidth */
8356 NULL, /* pGetDeviceCaps */
8357 NULL, /* pGetDeviceGammaRamp */
8358 freetype_GetFontData, /* pGetFontData */
8359 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8360 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8361 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8362 NULL, /* pGetICMProfile */
8363 NULL, /* pGetImage */
8364 freetype_GetKerningPairs, /* pGetKerningPairs */
8365 NULL, /* pGetNearestColor */
8366 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8367 NULL, /* pGetPixel */
8368 NULL, /* pGetSystemPaletteEntries */
8369 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8370 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8371 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8372 freetype_GetTextFace, /* pGetTextFace */
8373 freetype_GetTextMetrics, /* pGetTextMetrics */
8374 NULL, /* pGradientFill */
8375 NULL, /* pIntersectClipRect */
8376 NULL, /* pInvertRgn */
8377 NULL, /* pLineTo */
8378 NULL, /* pModifyWorldTransform */
8379 NULL, /* pMoveTo */
8380 NULL, /* pOffsetClipRgn */
8381 NULL, /* pOffsetViewportOrg */
8382 NULL, /* pOffsetWindowOrg */
8383 NULL, /* pPaintRgn */
8384 NULL, /* pPatBlt */
8385 NULL, /* pPie */
8386 NULL, /* pPolyBezier */
8387 NULL, /* pPolyBezierTo */
8388 NULL, /* pPolyDraw */
8389 NULL, /* pPolyPolygon */
8390 NULL, /* pPolyPolyline */
8391 NULL, /* pPolygon */
8392 NULL, /* pPolyline */
8393 NULL, /* pPolylineTo */
8394 NULL, /* pPutImage */
8395 NULL, /* pRealizeDefaultPalette */
8396 NULL, /* pRealizePalette */
8397 NULL, /* pRectangle */
8398 NULL, /* pResetDC */
8399 NULL, /* pRestoreDC */
8400 NULL, /* pRoundRect */
8401 NULL, /* pSaveDC */
8402 NULL, /* pScaleViewportExt */
8403 NULL, /* pScaleWindowExt */
8404 NULL, /* pSelectBitmap */
8405 NULL, /* pSelectBrush */
8406 NULL, /* pSelectClipPath */
8407 freetype_SelectFont, /* pSelectFont */
8408 NULL, /* pSelectPalette */
8409 NULL, /* pSelectPen */
8410 NULL, /* pSetArcDirection */
8411 NULL, /* pSetBkColor */
8412 NULL, /* pSetBkMode */
8413 NULL, /* pSetDCBrushColor */
8414 NULL, /* pSetDCPenColor */
8415 NULL, /* pSetDIBColorTable */
8416 NULL, /* pSetDIBitsToDevice */
8417 NULL, /* pSetDeviceClipping */
8418 NULL, /* pSetDeviceGammaRamp */
8419 NULL, /* pSetLayout */
8420 NULL, /* pSetMapMode */
8421 NULL, /* pSetMapperFlags */
8422 NULL, /* pSetPixel */
8423 NULL, /* pSetPolyFillMode */
8424 NULL, /* pSetROP2 */
8425 NULL, /* pSetRelAbs */
8426 NULL, /* pSetStretchBltMode */
8427 NULL, /* pSetTextAlign */
8428 NULL, /* pSetTextCharacterExtra */
8429 NULL, /* pSetTextColor */
8430 NULL, /* pSetTextJustification */
8431 NULL, /* pSetViewportExt */
8432 NULL, /* pSetViewportOrg */
8433 NULL, /* pSetWindowExt */
8434 NULL, /* pSetWindowOrg */
8435 NULL, /* pSetWorldTransform */
8436 NULL, /* pStartDoc */
8437 NULL, /* pStartPage */
8438 NULL, /* pStretchBlt */
8439 NULL, /* pStretchDIBits */
8440 NULL, /* pStrokeAndFillPath */
8441 NULL, /* pStrokePath */
8442 NULL, /* pUnrealizePalette */
8443 NULL, /* pWidenPath */
8444 NULL, /* wine_get_wgl_driver */
8445 GDI_PRIORITY_FONT_DRV /* priority */
8448 #else /* HAVE_FREETYPE */
8450 /*************************************************************************/
8452 BOOL WineEngInit(void)
8454 return FALSE;
8457 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8459 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8460 return 1;
8463 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8465 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8466 return TRUE;
8469 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8471 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8472 return NULL;
8475 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8476 LPCWSTR font_file, LPCWSTR font_path )
8478 FIXME("stub\n");
8479 return FALSE;
8482 /*************************************************************************
8483 * GetRasterizerCaps (GDI32.@)
8485 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8487 lprs->nSize = sizeof(RASTERIZER_STATUS);
8488 lprs->wFlags = 0;
8489 lprs->nLanguageID = 0;
8490 return TRUE;
8493 #endif /* HAVE_FREETYPE */