wined3d: Add NVIDIA Geforce GTX 750 to device list.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blobcece358acebb165bb04afb73f7290e140c0e6070
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 LOGFONTW *lf)
5714 Face *face;
5715 const struct list *face_list;
5717 if (!strcmpiW(lf->lfFaceName, 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(lf->lfFaceName, face->FullName)) return TRUE;
5723 return FALSE;
5726 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5728 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5730 return (face->FullName && !strcmpiW(lf->lfFaceName, 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 FontSubst *psub;
5809 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 lf = *plf;
5815 strcpyW(lf.lfFaceName, psub->to.name);
5816 plf = &lf;
5819 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5820 if (!family_matches(family, plf)) continue;
5821 face_list = get_face_list_from_family(family);
5822 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5823 if (!face_matches(family->FamilyName, face, plf)) continue;
5824 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5827 } else {
5828 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5829 face_list = get_face_list_from_family(family);
5830 face = LIST_ENTRY(list_head(face_list), Face, entry);
5831 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5834 LeaveCriticalSection( &freetype_cs );
5835 return TRUE;
5838 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5840 pt->x.value = vec->x >> 6;
5841 pt->x.fract = (vec->x & 0x3f) << 10;
5842 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5843 pt->y.value = vec->y >> 6;
5844 pt->y.fract = (vec->y & 0x3f) << 10;
5845 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5846 return;
5849 /***************************************************
5850 * According to the MSDN documentation on WideCharToMultiByte,
5851 * certain codepages cannot set the default_used parameter.
5852 * This returns TRUE if the codepage can set that parameter, false else
5853 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5855 static BOOL codepage_sets_default_used(UINT codepage)
5857 switch (codepage)
5859 case CP_UTF7:
5860 case CP_UTF8:
5861 case CP_SYMBOL:
5862 return FALSE;
5863 default:
5864 return TRUE;
5869 * GSUB Table handling functions
5872 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5874 const GSUB_CoverageFormat1* cf1;
5876 cf1 = table;
5878 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5880 int count = GET_BE_WORD(cf1->GlyphCount);
5881 int i;
5882 TRACE("Coverage Format 1, %i glyphs\n",count);
5883 for (i = 0; i < count; i++)
5884 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5885 return i;
5886 return -1;
5888 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5890 const GSUB_CoverageFormat2* cf2;
5891 int i;
5892 int count;
5893 cf2 = (const GSUB_CoverageFormat2*)cf1;
5895 count = GET_BE_WORD(cf2->RangeCount);
5896 TRACE("Coverage Format 2, %i ranges\n",count);
5897 for (i = 0; i < count; i++)
5899 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5900 return -1;
5901 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5902 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5904 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5905 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5908 return -1;
5910 else
5911 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5913 return -1;
5916 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5918 int i;
5919 int offset;
5920 const GSUB_LookupList *lookup;
5921 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5923 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5924 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5926 const GSUB_LookupTable *look;
5927 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5928 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5929 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5930 if (GET_BE_WORD(look->LookupType) != 1)
5931 FIXME("We only handle SubType 1\n");
5932 else
5934 int j;
5936 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5938 const GSUB_SingleSubstFormat1 *ssf1;
5939 offset = GET_BE_WORD(look->SubTable[j]);
5940 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5941 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5943 int offset = GET_BE_WORD(ssf1->Coverage);
5944 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5945 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5947 TRACE(" Glyph 0x%x ->",glyph);
5948 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5949 TRACE(" 0x%x\n",glyph);
5952 else
5954 const GSUB_SingleSubstFormat2 *ssf2;
5955 INT index;
5956 INT offset;
5958 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5959 offset = GET_BE_WORD(ssf1->Coverage);
5960 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5961 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5962 TRACE(" Coverage index %i\n",index);
5963 if (index != -1)
5965 TRACE(" Glyph is 0x%x ->",glyph);
5966 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5967 TRACE("0x%x\n",glyph);
5973 return glyph;
5977 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5979 const GSUB_Header *header;
5980 const GSUB_Feature *feature;
5982 if (!font->GSUB_Table)
5983 return glyph;
5985 header = font->GSUB_Table;
5986 feature = font->vert_feature;
5988 return GSUB_apply_feature(header, feature, glyph);
5991 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5993 FT_UInt glyphId;
5995 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5996 WCHAR wc = (WCHAR)glyph;
5997 BOOL default_used;
5998 BOOL *default_used_pointer;
5999 FT_UInt ret;
6000 char buf;
6001 default_used_pointer = NULL;
6002 default_used = FALSE;
6003 if (codepage_sets_default_used(font->codepage))
6004 default_used_pointer = &default_used;
6005 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
6007 if (font->codepage == CP_SYMBOL && wc < 0x100)
6008 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
6009 else
6010 ret = 0;
6012 else
6013 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
6014 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6015 return ret;
6018 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
6020 if (glyph < 0x100) glyph += 0xf000;
6021 /* there is a number of old pre-Unicode "broken" TTFs, which
6022 do have symbols at U+00XX instead of U+f0XX */
6023 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
6024 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
6026 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
6028 return glyphId;
6031 /* helper for freetype_GetGlyphIndices */
6032 static FT_UInt get_gdi_glyph_index(const GdiFont *font, UINT glyph)
6034 WCHAR wc = (WCHAR)glyph;
6035 BOOL default_used = FALSE;
6036 BOOL *default_used_pointer = NULL;
6037 FT_UInt ret;
6038 char buf;
6040 if(font->ft_face->charmap->encoding != FT_ENCODING_NONE)
6041 return get_glyph_index(font, glyph);
6043 if (codepage_sets_default_used(font->codepage))
6044 default_used_pointer = &default_used;
6045 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer)
6046 || default_used)
6048 if (font->codepage == CP_SYMBOL && wc < 0x100)
6049 ret = (unsigned char)wc;
6050 else
6051 ret = 0;
6053 else
6054 ret = (unsigned char)buf;
6055 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, (unsigned char)buf, ret, default_used);
6056 return ret;
6059 static FT_UInt get_default_char_index(GdiFont *font)
6061 FT_UInt default_char;
6063 if (FT_IS_SFNT(font->ft_face))
6065 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
6066 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
6068 else
6070 TEXTMETRICW textm;
6071 get_text_metrics(font, &textm);
6072 default_char = textm.tmDefaultChar;
6075 return default_char;
6078 /*************************************************************
6079 * freetype_GetGlyphIndices
6081 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
6083 struct freetype_physdev *physdev = get_freetype_dev( dev );
6084 int i;
6085 WORD default_char;
6086 BOOL got_default = FALSE;
6088 if (!physdev->font)
6090 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
6091 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
6094 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
6096 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
6097 got_default = TRUE;
6100 GDI_CheckNotLock();
6101 EnterCriticalSection( &freetype_cs );
6103 for(i = 0; i < count; i++)
6105 pgi[i] = get_gdi_glyph_index(physdev->font, lpstr[i]);
6106 if (pgi[i] == 0)
6108 if (!got_default)
6110 default_char = get_default_char_index(physdev->font);
6111 got_default = TRUE;
6113 pgi[i] = default_char;
6115 else
6116 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
6118 LeaveCriticalSection( &freetype_cs );
6119 return count;
6122 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
6124 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
6125 return !memcmp(matrix, &identity, sizeof(FMAT2));
6128 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
6130 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
6131 return !memcmp(matrix, &identity, sizeof(MAT2));
6134 static void synthesize_bold_glyph(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
6136 FT_Error err;
6137 static UINT once;
6139 switch(glyph->format) {
6140 case FT_GLYPH_FORMAT_OUTLINE:
6142 FT_Pos strength;
6143 FT_BBox bbox;
6144 if(!pFT_Outline_Embolden)
6145 break;
6147 strength = MulDiv(ppem, 1 << 6, 24);
6148 err = pFT_Outline_Embolden(&glyph->outline, strength);
6149 if(err) {
6150 TRACE("FT_Ouline_Embolden returns %d, ignored\n", err);
6151 break;
6154 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
6155 metrics->width = bbox.xMax - bbox.xMin;
6156 metrics->height = bbox.yMax - bbox.yMin;
6157 metrics->horiBearingX = bbox.xMin;
6158 metrics->horiBearingY = bbox.yMax;
6159 metrics->horiAdvance += (1 << 6);
6160 metrics->vertAdvance += (1 << 6);
6161 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
6162 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
6163 break;
6165 default:
6166 if (!once++)
6167 WARN("Emboldening format 0x%x is not supported\n", glyph->format);
6168 return;
6172 static inline BYTE get_max_level( UINT format )
6174 switch( format )
6176 case GGO_GRAY2_BITMAP: return 4;
6177 case GGO_GRAY4_BITMAP: return 16;
6178 case GGO_GRAY8_BITMAP: return 64;
6180 return 255;
6183 extern const unsigned short vertical_orientation_table[];
6185 static BOOL check_unicode_tategaki(WCHAR uchar)
6187 unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
6189 /* We only reach this code if typographical substitution did not occur */
6190 /* Type: U or Type: Tu */
6191 return (orientation == 1 || orientation == 3);
6194 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6196 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
6197 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
6198 const MAT2* lpmat)
6200 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
6201 GLYPHMETRICS gm;
6202 FT_Face ft_face = incoming_font->ft_face;
6203 GdiFont *font = incoming_font;
6204 FT_Glyph_Metrics metrics;
6205 FT_UInt glyph_index;
6206 DWORD width, height, pitch, needed = 0;
6207 FT_Bitmap ft_bitmap;
6208 FT_Error err;
6209 INT left, right, top = 0, bottom = 0, adv;
6210 INT origin_x = 0, origin_y = 0;
6211 FT_Angle angle = 0;
6212 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
6213 double widthRatio = 1.0;
6214 FT_Matrix transMat = identityMat;
6215 FT_Matrix transMatUnrotated;
6216 FT_Matrix transMatTategaki;
6217 BOOL needsTransform = FALSE;
6218 BOOL tategaki = (font->name[0] == '@');
6219 BOOL vertical_metrics;
6220 UINT original_index;
6221 LONG avgAdvance = 0;
6222 FT_Fixed em_scale;
6224 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
6225 buflen, buf, lpmat);
6227 TRACE("font transform %f %f %f %f\n",
6228 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
6229 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
6231 if(format & GGO_GLYPH_INDEX) {
6232 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
6233 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6234 as glyph index. "Treasure Adventure Game" depends on this. */
6235 glyph_index = pFT_Get_Char_Index(font->ft_face, glyph);
6236 TRACE("translate glyph index %04x -> %04x\n", glyph, glyph_index);
6237 } else
6238 glyph_index = glyph;
6239 original_index = glyph_index;
6240 format &= ~GGO_GLYPH_INDEX;
6241 /* TODO: Window also turns off tategaki for glyphs passed in by index
6242 if their unicode code points fall outside of the range that is
6243 rotated. */
6244 } else {
6245 BOOL vert;
6246 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index, &vert);
6247 ft_face = font->ft_face;
6248 original_index = glyph_index;
6249 if (!vert && tategaki)
6250 tategaki = check_unicode_tategaki(glyph);
6253 if(format & GGO_UNHINTED) {
6254 load_flags |= FT_LOAD_NO_HINTING;
6255 format &= ~GGO_UNHINTED;
6258 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
6259 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
6260 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
6261 font->gmsize * sizeof(GM*));
6262 } else {
6263 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
6264 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
6266 *lpgm = FONT_GM(font,original_index)->gm;
6267 *abc = FONT_GM(font,original_index)->abc;
6268 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6269 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6270 lpgm->gmCellIncX, lpgm->gmCellIncY);
6271 return 1; /* FIXME */
6275 if (!font->gm[original_index / GM_BLOCK_SIZE])
6276 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
6278 /* Scaling factor */
6279 if (font->aveWidth)
6281 TEXTMETRICW tm;
6283 get_text_metrics(font, &tm);
6285 widthRatio = (double)font->aveWidth;
6286 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6288 else
6289 widthRatio = font->scale_y;
6291 /* Scaling transform */
6292 if (widthRatio != 1.0 || font->scale_y != 1.0)
6294 FT_Matrix scaleMat;
6295 scaleMat.xx = FT_FixedFromFloat(widthRatio);
6296 scaleMat.xy = 0;
6297 scaleMat.yx = 0;
6298 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
6300 pFT_Matrix_Multiply(&scaleMat, &transMat);
6301 needsTransform = TRUE;
6304 /* Slant transform */
6305 if (font->fake_italic) {
6306 FT_Matrix slantMat;
6308 slantMat.xx = (1 << 16);
6309 slantMat.xy = ((1 << 16) >> 2);
6310 slantMat.yx = 0;
6311 slantMat.yy = (1 << 16);
6312 pFT_Matrix_Multiply(&slantMat, &transMat);
6313 needsTransform = TRUE;
6316 /* Rotation transform */
6317 transMatUnrotated = transMat;
6318 transMatTategaki = transMat;
6319 if(font->orientation || tategaki) {
6320 FT_Matrix rotationMat;
6321 FT_Matrix taterotationMat;
6322 FT_Vector vecAngle;
6324 double orient = font->orientation / 10.0;
6325 double tate_orient = 0.f;
6327 if (tategaki)
6328 tate_orient = ((font->orientation+900)%3600)/10.0;
6329 else
6330 tate_orient = font->orientation/10.0;
6332 if (orient)
6334 angle = FT_FixedFromFloat(orient);
6335 pFT_Vector_Unit(&vecAngle, angle);
6336 rotationMat.xx = vecAngle.x;
6337 rotationMat.xy = -vecAngle.y;
6338 rotationMat.yx = -rotationMat.xy;
6339 rotationMat.yy = rotationMat.xx;
6341 pFT_Matrix_Multiply(&rotationMat, &transMat);
6344 if (tate_orient)
6346 angle = FT_FixedFromFloat(tate_orient);
6347 pFT_Vector_Unit(&vecAngle, angle);
6348 taterotationMat.xx = vecAngle.x;
6349 taterotationMat.xy = -vecAngle.y;
6350 taterotationMat.yx = -taterotationMat.xy;
6351 taterotationMat.yy = taterotationMat.xx;
6352 pFT_Matrix_Multiply(&taterotationMat, &transMatTategaki);
6355 needsTransform = TRUE;
6358 /* World transform */
6359 if (!is_identity_FMAT2(&font->font_desc.matrix))
6361 FT_Matrix worldMat;
6362 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6363 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6364 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6365 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6366 pFT_Matrix_Multiply(&worldMat, &transMat);
6367 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6368 pFT_Matrix_Multiply(&worldMat, &transMatTategaki);
6369 needsTransform = TRUE;
6372 /* Extra transformation specified by caller */
6373 if (!is_identity_MAT2(lpmat))
6375 FT_Matrix extraMat;
6376 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6377 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6378 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6379 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6380 pFT_Matrix_Multiply(&extraMat, &transMat);
6381 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6382 pFT_Matrix_Multiply(&extraMat, &transMatTategaki);
6383 needsTransform = TRUE;
6386 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
6387 /* there is a freetype bug where vertical metrics are only
6388 properly scaled and correct in 2.4.0 or greater */
6389 if ((vertical_metrics) && (FT_Version.major < 2 || (FT_Version.major == 2 && FT_Version.minor < 4)))
6390 vertical_metrics = FALSE;
6392 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6393 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
6395 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6397 if(err) {
6398 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6399 return GDI_ERROR;
6402 metrics = ft_face->glyph->metrics;
6403 if(font->fake_bold)
6404 synthesize_bold_glyph(ft_face->glyph, font->ppem, &metrics);
6406 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6407 * by the text metrics. The proper behavior is to clip the glyph metrics to
6408 * fit within the maximums specified in the text metrics. */
6409 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6410 get_bitmap_text_metrics(incoming_font)) {
6411 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6412 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6413 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6414 metrics.horiBearingY = top;
6415 metrics.height = top - bottom;
6417 /* TODO: Are we supposed to clip the width as well...? */
6418 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6421 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6423 if(FT_IS_SCALABLE(incoming_font->ft_face) && !font->fake_bold) {
6424 TEXTMETRICW tm;
6425 if (get_text_metrics(incoming_font, &tm) &&
6426 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6427 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6428 if (avgAdvance &&
6429 (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6430 TRACE("Fixed-pitch full-width character detected\n");
6431 else
6432 avgAdvance = 0; /* cancel this feature */
6436 if(!needsTransform) {
6437 left = (INT)(metrics.horiBearingX) & -64;
6438 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6439 if (!avgAdvance)
6440 adv = (INT)(metrics.horiAdvance + 63) >> 6;
6441 else
6442 adv = (INT)avgAdvance * 2;
6444 top = (metrics.horiBearingY + 63) & -64;
6445 bottom = (metrics.horiBearingY - metrics.height) & -64;
6446 gm.gmCellIncX = adv;
6447 gm.gmCellIncY = 0;
6448 origin_x = left;
6449 origin_y = top;
6450 abc->abcA = origin_x >> 6;
6451 abc->abcB = metrics.width >> 6;
6452 } else {
6453 INT xc, yc;
6454 FT_Vector vec;
6455 FT_Pos lsb;
6457 left = right = 0;
6459 for(xc = 0; xc < 2; xc++) {
6460 for(yc = 0; yc < 2; yc++) {
6461 vec.x = metrics.horiBearingX + xc * metrics.width;
6462 vec.y = metrics.horiBearingY - yc * metrics.height;
6463 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6464 pFT_Vector_Transform(&vec, &transMatTategaki);
6465 if(xc == 0 && yc == 0) {
6466 left = right = vec.x;
6467 top = bottom = vec.y;
6468 } else {
6469 if(vec.x < left) left = vec.x;
6470 else if(vec.x > right) right = vec.x;
6471 if(vec.y < bottom) bottom = vec.y;
6472 else if(vec.y > top) top = vec.y;
6476 left = left & -64;
6477 right = (right + 63) & -64;
6478 bottom = bottom & -64;
6479 top = (top + 63) & -64;
6481 if (tategaki && (font->potm || get_outline_text_metrics(font)))
6483 if (vertical_metrics)
6484 lsb = metrics.horiBearingY + metrics.vertBearingY;
6485 else
6486 lsb = metrics.vertAdvance + (font->potm->otmDescent << 6);
6487 vec.x = lsb;
6488 vec.y = font->potm->otmDescent << 6;
6489 TRACE ("Vec %ld,%ld\n", vec.x>>6, vec.y>>6);
6490 pFT_Vector_Transform(&vec, &transMat);
6491 origin_x = (vec.x + left) & -64;
6492 origin_y = (vec.y + top + 63) & -64;
6494 else
6496 origin_x = left;
6497 origin_y = top;
6498 lsb = metrics.horiBearingX;
6501 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6502 if (vertical_metrics)
6503 vec.x = metrics.vertAdvance;
6504 else
6505 vec.x = metrics.horiAdvance;
6506 vec.y = 0;
6507 pFT_Vector_Transform(&vec, &transMat);
6508 gm.gmCellIncY = -((vec.y+63) >> 6);
6509 if (!avgAdvance || vec.y)
6510 gm.gmCellIncX = (vec.x+63) >> 6;
6511 else {
6512 vec.x = incoming_font->ntmAvgWidth;
6513 vec.y = 0;
6514 pFT_Vector_Transform(&vec, &transMat);
6515 gm.gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6518 if (vertical_metrics)
6519 vec.x = metrics.vertAdvance;
6520 else
6521 vec.x = metrics.horiAdvance;
6522 vec.y = 0;
6523 pFT_Vector_Transform(&vec, &transMatUnrotated);
6524 if (!avgAdvance || vec.y)
6525 adv = (vec.x+63) >> 6;
6526 else {
6527 vec.x = incoming_font->ntmAvgWidth;
6528 vec.y = 0;
6529 pFT_Vector_Transform(&vec, &transMatUnrotated);
6530 adv = pFT_MulFix(vec.x, em_scale) * 2;
6533 vec.x = lsb;
6534 vec.y = 0;
6535 pFT_Vector_Transform(&vec, &transMatUnrotated);
6536 abc->abcA = vec.x >> 6;
6538 vec.x = metrics.width;
6539 vec.y = 0;
6540 pFT_Vector_Transform(&vec, &transMatUnrotated);
6541 if (vec.x >= 0)
6542 abc->abcB = vec.x >> 6;
6543 else
6544 abc->abcB = -vec.x >> 6;
6547 width = (right - left) >> 6;
6548 height = (top - bottom) >> 6;
6549 gm.gmBlackBoxX = width ? width : 1;
6550 gm.gmBlackBoxY = height ? height : 1;
6551 gm.gmptGlyphOrigin.x = origin_x >> 6;
6552 gm.gmptGlyphOrigin.y = origin_y >> 6;
6553 if (!abc->abcB) abc->abcB = 1;
6554 abc->abcC = adv - abc->abcA - abc->abcB;
6556 TRACE("%u,%u,%s,%d,%d\n", gm.gmBlackBoxX, gm.gmBlackBoxY,
6557 wine_dbgstr_point(&gm.gmptGlyphOrigin),
6558 gm.gmCellIncX, gm.gmCellIncY);
6560 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6561 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6563 FONT_GM(font,original_index)->gm = gm;
6564 FONT_GM(font,original_index)->abc = *abc;
6565 FONT_GM(font,original_index)->init = TRUE;
6568 if(format == GGO_METRICS)
6570 *lpgm = gm;
6571 return 1; /* FIXME */
6574 if(ft_face->glyph->format != ft_glyph_format_outline &&
6575 (format == GGO_NATIVE || format == GGO_BEZIER))
6577 TRACE("loaded a bitmap\n");
6578 return GDI_ERROR;
6581 switch(format) {
6582 case GGO_BITMAP:
6583 pitch = ((width + 31) >> 5) << 2;
6584 needed = pitch * height;
6586 if(!buf || !buflen) break;
6587 if (!needed) return GDI_ERROR; /* empty glyph */
6589 switch(ft_face->glyph->format) {
6590 case ft_glyph_format_bitmap:
6592 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6593 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
6594 INT h = min( height, ft_face->glyph->bitmap.rows );
6595 while(h--) {
6596 memcpy(dst, src, w);
6597 src += ft_face->glyph->bitmap.pitch;
6598 dst += pitch;
6600 break;
6603 case ft_glyph_format_outline:
6604 ft_bitmap.width = width;
6605 ft_bitmap.rows = height;
6606 ft_bitmap.pitch = pitch;
6607 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6608 ft_bitmap.buffer = buf;
6610 if(needsTransform)
6611 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6613 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6615 /* Note: FreeType will only set 'black' bits for us. */
6616 memset(buf, 0, needed);
6617 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6618 break;
6620 default:
6621 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6622 return GDI_ERROR;
6624 break;
6626 case GGO_GRAY2_BITMAP:
6627 case GGO_GRAY4_BITMAP:
6628 case GGO_GRAY8_BITMAP:
6629 case WINE_GGO_GRAY16_BITMAP:
6631 unsigned int max_level, row, col;
6632 BYTE *start, *ptr;
6634 pitch = (width + 3) / 4 * 4;
6635 needed = pitch * height;
6637 if(!buf || !buflen) break;
6638 if (!needed) return GDI_ERROR; /* empty glyph */
6640 max_level = get_max_level( format );
6642 switch(ft_face->glyph->format) {
6643 case ft_glyph_format_bitmap:
6645 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6646 INT h = min( height, ft_face->glyph->bitmap.rows );
6647 INT x;
6648 memset( buf, 0, needed );
6649 while(h--) {
6650 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6651 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6652 src += ft_face->glyph->bitmap.pitch;
6653 dst += pitch;
6655 break;
6657 case ft_glyph_format_outline:
6659 ft_bitmap.width = width;
6660 ft_bitmap.rows = height;
6661 ft_bitmap.pitch = pitch;
6662 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6663 ft_bitmap.buffer = buf;
6665 if(needsTransform)
6666 pFT_Outline_Transform(&ft_face->glyph->outline, &transMatTategaki);
6668 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6670 memset(ft_bitmap.buffer, 0, buflen);
6672 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6674 if (max_level != 255)
6676 for (row = 0, start = buf; row < height; row++)
6678 for (col = 0, ptr = start; col < width; col++, ptr++)
6679 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6680 start += pitch;
6683 break;
6686 default:
6687 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6688 return GDI_ERROR;
6690 break;
6693 case WINE_GGO_HRGB_BITMAP:
6694 case WINE_GGO_HBGR_BITMAP:
6695 case WINE_GGO_VRGB_BITMAP:
6696 case WINE_GGO_VBGR_BITMAP:
6697 #ifdef FT_LCD_FILTER_H
6699 switch (ft_face->glyph->format)
6701 case FT_GLYPH_FORMAT_BITMAP:
6703 BYTE *src, *dst;
6704 INT src_pitch, x;
6706 pitch = width * 4;
6707 needed = pitch * height;
6709 if (!buf || !buflen) break;
6710 if (!needed) return GDI_ERROR; /* empty glyph */
6712 memset(buf, 0, buflen);
6713 dst = buf;
6714 src = ft_face->glyph->bitmap.buffer;
6715 src_pitch = ft_face->glyph->bitmap.pitch;
6717 height = min( height, ft_face->glyph->bitmap.rows );
6718 while ( height-- )
6720 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6722 if ( src[x / 8] & masks[x % 8] )
6723 ((unsigned int *)dst)[x] = ~0u;
6725 src += src_pitch;
6726 dst += pitch;
6729 break;
6732 case FT_GLYPH_FORMAT_OUTLINE:
6734 unsigned int *dst;
6735 BYTE *src;
6736 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6737 INT x_shift, y_shift;
6738 BOOL rgb;
6739 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6740 FT_Render_Mode render_mode =
6741 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6742 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6744 if (!width || !height)
6746 if (!buf || !buflen) break;
6747 return GDI_ERROR;
6750 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6752 if ( render_mode == FT_RENDER_MODE_LCD)
6754 gm.gmBlackBoxX += 2;
6755 gm.gmptGlyphOrigin.x -= 1;
6756 left -= (1 << 6);
6758 else
6760 gm.gmBlackBoxY += 2;
6761 gm.gmptGlyphOrigin.y += 1;
6762 top += (1 << 6);
6766 width = gm.gmBlackBoxX;
6767 height = gm.gmBlackBoxY;
6768 pitch = width * 4;
6769 needed = pitch * height;
6771 if (!buf || !buflen) break;
6773 memset(buf, 0, buflen);
6774 dst = buf;
6775 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6777 if ( needsTransform )
6778 pFT_Outline_Transform (&ft_face->glyph->outline, &transMatTategaki);
6780 if ( pFT_Library_SetLcdFilter )
6781 pFT_Library_SetLcdFilter( library, lcdfilter );
6782 pFT_Render_Glyph (ft_face->glyph, render_mode);
6784 src = ft_face->glyph->bitmap.buffer;
6785 src_pitch = ft_face->glyph->bitmap.pitch;
6786 src_width = ft_face->glyph->bitmap.width;
6787 src_height = ft_face->glyph->bitmap.rows;
6789 if ( render_mode == FT_RENDER_MODE_LCD)
6791 rgb_interval = 1;
6792 hmul = 3;
6793 vmul = 1;
6795 else
6797 rgb_interval = src_pitch;
6798 hmul = 1;
6799 vmul = 3;
6802 x_shift = ft_face->glyph->bitmap_left - (left >> 6);
6803 if ( x_shift < 0 )
6805 src += hmul * -x_shift;
6806 src_width -= hmul * -x_shift;
6808 else if ( x_shift > 0 )
6810 dst += x_shift;
6811 width -= x_shift;
6814 y_shift = (top >> 6) - ft_face->glyph->bitmap_top;
6815 if ( y_shift < 0 )
6817 src += src_pitch * vmul * -y_shift;
6818 src_height -= vmul * -y_shift;
6820 else if ( y_shift > 0 )
6822 dst += y_shift * ( pitch / sizeof(*dst) );
6823 height -= y_shift;
6826 width = min( width, src_width / hmul );
6827 height = min( height, src_height / vmul );
6829 while ( height-- )
6831 for ( x = 0; x < width; x++ )
6833 if ( rgb )
6835 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6836 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6837 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6838 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6840 else
6842 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6843 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6844 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6845 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6848 src += src_pitch * vmul;
6849 dst += pitch / sizeof(*dst);
6852 break;
6855 default:
6856 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6857 return GDI_ERROR;
6860 break;
6862 #else
6863 return GDI_ERROR;
6864 #endif
6866 case GGO_NATIVE:
6868 int contour, point = 0, first_pt;
6869 FT_Outline *outline = &ft_face->glyph->outline;
6870 TTPOLYGONHEADER *pph;
6871 TTPOLYCURVE *ppc;
6872 DWORD pph_start, cpfx, type;
6874 if(buflen == 0) buf = NULL;
6876 if (needsTransform && buf) {
6877 pFT_Outline_Transform(outline, &transMatTategaki);
6880 for(contour = 0; contour < outline->n_contours; contour++) {
6881 /* Ignore contours containing one point */
6882 if(point == outline->contours[contour]) {
6883 point++;
6884 continue;
6887 pph_start = needed;
6888 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6889 first_pt = point;
6890 if(buf) {
6891 pph->dwType = TT_POLYGON_TYPE;
6892 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6894 needed += sizeof(*pph);
6895 point++;
6896 while(point <= outline->contours[contour]) {
6897 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6898 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6899 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6900 cpfx = 0;
6901 do {
6902 if(buf)
6903 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6904 cpfx++;
6905 point++;
6906 } while(point <= outline->contours[contour] &&
6907 (outline->tags[point] & FT_Curve_Tag_On) ==
6908 (outline->tags[point-1] & FT_Curve_Tag_On));
6909 /* At the end of a contour Windows adds the start point, but
6910 only for Beziers */
6911 if(point > outline->contours[contour] &&
6912 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6913 if(buf)
6914 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6915 cpfx++;
6916 } else if(point <= outline->contours[contour] &&
6917 outline->tags[point] & FT_Curve_Tag_On) {
6918 /* add closing pt for bezier */
6919 if(buf)
6920 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6921 cpfx++;
6922 point++;
6924 if(buf) {
6925 ppc->wType = type;
6926 ppc->cpfx = cpfx;
6928 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6930 if(buf)
6931 pph->cb = needed - pph_start;
6933 break;
6935 case GGO_BEZIER:
6937 /* Convert the quadratic Beziers to cubic Beziers.
6938 The parametric eqn for a cubic Bezier is, from PLRM:
6939 r(t) = at^3 + bt^2 + ct + r0
6940 with the control points:
6941 r1 = r0 + c/3
6942 r2 = r1 + (c + b)/3
6943 r3 = r0 + c + b + a
6945 A quadratic Bezier has the form:
6946 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6948 So equating powers of t leads to:
6949 r1 = 2/3 p1 + 1/3 p0
6950 r2 = 2/3 p1 + 1/3 p2
6951 and of course r0 = p0, r3 = p2
6954 int contour, point = 0, first_pt;
6955 FT_Outline *outline = &ft_face->glyph->outline;
6956 TTPOLYGONHEADER *pph;
6957 TTPOLYCURVE *ppc;
6958 DWORD pph_start, cpfx, type;
6959 FT_Vector cubic_control[4];
6960 if(buflen == 0) buf = NULL;
6962 if (needsTransform && buf) {
6963 pFT_Outline_Transform(outline, &transMat);
6966 for(contour = 0; contour < outline->n_contours; contour++) {
6967 pph_start = needed;
6968 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6969 first_pt = point;
6970 if(buf) {
6971 pph->dwType = TT_POLYGON_TYPE;
6972 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6974 needed += sizeof(*pph);
6975 point++;
6976 while(point <= outline->contours[contour]) {
6977 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6978 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6979 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6980 cpfx = 0;
6981 do {
6982 if(type == TT_PRIM_LINE) {
6983 if(buf)
6984 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6985 cpfx++;
6986 point++;
6987 } else {
6988 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6989 so cpfx = 3n */
6991 /* FIXME: Possible optimization in endpoint calculation
6992 if there are two consecutive curves */
6993 cubic_control[0] = outline->points[point-1];
6994 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6995 cubic_control[0].x += outline->points[point].x + 1;
6996 cubic_control[0].y += outline->points[point].y + 1;
6997 cubic_control[0].x >>= 1;
6998 cubic_control[0].y >>= 1;
7000 if(point+1 > outline->contours[contour])
7001 cubic_control[3] = outline->points[first_pt];
7002 else {
7003 cubic_control[3] = outline->points[point+1];
7004 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
7005 cubic_control[3].x += outline->points[point].x + 1;
7006 cubic_control[3].y += outline->points[point].y + 1;
7007 cubic_control[3].x >>= 1;
7008 cubic_control[3].y >>= 1;
7011 /* r1 = 1/3 p0 + 2/3 p1
7012 r2 = 1/3 p2 + 2/3 p1 */
7013 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
7014 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
7015 cubic_control[2] = cubic_control[1];
7016 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
7017 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
7018 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
7019 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
7020 if(buf) {
7021 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
7022 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
7023 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
7025 cpfx += 3;
7026 point++;
7028 } while(point <= outline->contours[contour] &&
7029 (outline->tags[point] & FT_Curve_Tag_On) ==
7030 (outline->tags[point-1] & FT_Curve_Tag_On));
7031 /* At the end of a contour Windows adds the start point,
7032 but only for Beziers and we've already done that.
7034 if(point <= outline->contours[contour] &&
7035 outline->tags[point] & FT_Curve_Tag_On) {
7036 /* This is the closing pt of a bezier, but we've already
7037 added it, so just inc point and carry on */
7038 point++;
7040 if(buf) {
7041 ppc->wType = type;
7042 ppc->cpfx = cpfx;
7044 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
7046 if(buf)
7047 pph->cb = needed - pph_start;
7049 break;
7052 default:
7053 FIXME("Unsupported format %d\n", format);
7054 return GDI_ERROR;
7056 *lpgm = gm;
7057 return needed;
7060 static BOOL get_bitmap_text_metrics(GdiFont *font)
7062 FT_Face ft_face = font->ft_face;
7063 FT_WinFNT_HeaderRec winfnt_header;
7064 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
7065 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
7066 font->potm->otmSize = size;
7068 #define TM font->potm->otmTextMetrics
7069 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
7071 TM.tmHeight = winfnt_header.pixel_height;
7072 TM.tmAscent = winfnt_header.ascent;
7073 TM.tmDescent = TM.tmHeight - TM.tmAscent;
7074 TM.tmInternalLeading = winfnt_header.internal_leading;
7075 TM.tmExternalLeading = winfnt_header.external_leading;
7076 TM.tmAveCharWidth = winfnt_header.avg_width;
7077 TM.tmMaxCharWidth = winfnt_header.max_width;
7078 TM.tmWeight = winfnt_header.weight;
7079 TM.tmOverhang = 0;
7080 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
7081 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
7082 TM.tmFirstChar = winfnt_header.first_char;
7083 TM.tmLastChar = winfnt_header.last_char;
7084 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
7085 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
7086 TM.tmItalic = winfnt_header.italic;
7087 TM.tmUnderlined = font->underline;
7088 TM.tmStruckOut = font->strikeout;
7089 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
7090 TM.tmCharSet = winfnt_header.charset;
7092 else
7094 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
7095 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
7096 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7097 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
7098 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
7099 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
7100 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
7101 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
7102 TM.tmOverhang = 0;
7103 TM.tmDigitizedAspectX = 96; /* FIXME */
7104 TM.tmDigitizedAspectY = 96; /* FIXME */
7105 TM.tmFirstChar = 1;
7106 TM.tmLastChar = 255;
7107 TM.tmDefaultChar = 32;
7108 TM.tmBreakChar = 32;
7109 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
7110 TM.tmUnderlined = font->underline;
7111 TM.tmStruckOut = font->strikeout;
7112 /* NB inverted meaning of TMPF_FIXED_PITCH */
7113 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
7114 TM.tmCharSet = font->charset;
7116 #undef TM
7118 return TRUE;
7122 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
7124 double scale_x, scale_y;
7126 if (font->aveWidth)
7128 scale_x = (double)font->aveWidth;
7129 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7131 else
7132 scale_x = font->scale_y;
7134 scale_x *= fabs(font->font_desc.matrix.eM11);
7135 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7137 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7138 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7140 SCALE_Y(ptm->tmHeight);
7141 SCALE_Y(ptm->tmAscent);
7142 SCALE_Y(ptm->tmDescent);
7143 SCALE_Y(ptm->tmInternalLeading);
7144 SCALE_Y(ptm->tmExternalLeading);
7145 SCALE_Y(ptm->tmOverhang);
7147 SCALE_X(ptm->tmAveCharWidth);
7148 SCALE_X(ptm->tmMaxCharWidth);
7150 #undef SCALE_X
7151 #undef SCALE_Y
7154 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
7156 double scale_x, scale_y;
7158 if (font->aveWidth)
7160 scale_x = (double)font->aveWidth;
7161 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
7163 else
7164 scale_x = font->scale_y;
7166 scale_x *= fabs(font->font_desc.matrix.eM11);
7167 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
7169 scale_font_metrics(font, &potm->otmTextMetrics);
7171 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7172 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7174 SCALE_Y(potm->otmAscent);
7175 SCALE_Y(potm->otmDescent);
7176 SCALE_Y(potm->otmLineGap);
7177 SCALE_Y(potm->otmsCapEmHeight);
7178 SCALE_Y(potm->otmsXHeight);
7179 SCALE_Y(potm->otmrcFontBox.top);
7180 SCALE_Y(potm->otmrcFontBox.bottom);
7181 SCALE_X(potm->otmrcFontBox.left);
7182 SCALE_X(potm->otmrcFontBox.right);
7183 SCALE_Y(potm->otmMacAscent);
7184 SCALE_Y(potm->otmMacDescent);
7185 SCALE_Y(potm->otmMacLineGap);
7186 SCALE_X(potm->otmptSubscriptSize.x);
7187 SCALE_Y(potm->otmptSubscriptSize.y);
7188 SCALE_X(potm->otmptSubscriptOffset.x);
7189 SCALE_Y(potm->otmptSubscriptOffset.y);
7190 SCALE_X(potm->otmptSuperscriptSize.x);
7191 SCALE_Y(potm->otmptSuperscriptSize.y);
7192 SCALE_X(potm->otmptSuperscriptOffset.x);
7193 SCALE_Y(potm->otmptSuperscriptOffset.y);
7194 SCALE_Y(potm->otmsStrikeoutSize);
7195 SCALE_Y(potm->otmsStrikeoutPosition);
7196 SCALE_Y(potm->otmsUnderscoreSize);
7197 SCALE_Y(potm->otmsUnderscorePosition);
7199 #undef SCALE_X
7200 #undef SCALE_Y
7203 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
7205 if(!font->potm)
7207 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
7209 /* Make sure that the font has sane width/height ratio */
7210 if (font->aveWidth)
7212 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
7214 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
7215 font->aveWidth = 0;
7219 *ptm = font->potm->otmTextMetrics;
7220 scale_font_metrics(font, ptm);
7221 return TRUE;
7224 static BOOL face_has_symbol_charmap(FT_Face ft_face)
7226 int i;
7228 for(i = 0; i < ft_face->num_charmaps; i++)
7230 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
7231 return TRUE;
7233 return FALSE;
7236 static BOOL get_outline_text_metrics(GdiFont *font)
7238 BOOL ret = FALSE;
7239 FT_Face ft_face = font->ft_face;
7240 UINT needed, lenfam, lensty, lenface, lenfull;
7241 TT_OS2 *pOS2;
7242 TT_HoriHeader *pHori;
7243 TT_Postscript *pPost;
7244 FT_Fixed em_scale;
7245 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
7246 char *cp;
7247 INT ascent, descent;
7249 TRACE("font=%p\n", font);
7251 if(!FT_IS_SCALABLE(ft_face))
7252 return FALSE;
7254 needed = sizeof(*font->potm);
7256 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
7257 family_nameW = strdupW(font->name);
7259 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
7260 if (!style_nameW)
7262 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
7263 style_nameW = towstr( CP_ACP, ft_face->style_name );
7265 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
7267 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
7268 if (!face_nameW)
7270 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
7271 face_nameW = strdupW(font->name);
7273 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
7274 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
7276 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
7277 if (!full_nameW)
7279 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
7280 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
7281 full_nameW = strdupW(fake_nameW);
7283 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
7285 /* These names should be read from the TT name table */
7287 /* length of otmpFamilyName */
7288 needed += lenfam;
7290 /* length of otmpFaceName */
7291 needed += lenface;
7293 /* length of otmpStyleName */
7294 needed += lensty;
7296 /* length of otmpFullName */
7297 needed += lenfull;
7300 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
7302 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
7303 if(!pOS2) {
7304 FIXME("Can't find OS/2 table - not TT font?\n");
7305 goto end;
7308 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
7309 if(!pHori) {
7310 FIXME("Can't find HHEA table - not TT font?\n");
7311 goto end;
7314 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
7316 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",
7317 pOS2->usWinAscent, pOS2->usWinDescent,
7318 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
7319 pOS2->xAvgCharWidth,
7320 ft_face->ascender, ft_face->descender, ft_face->height,
7321 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
7322 ft_face->bbox.yMax, ft_face->bbox.yMin);
7324 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
7325 font->potm->otmSize = needed;
7327 #define TM font->potm->otmTextMetrics
7329 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
7330 ascent = pHori->Ascender;
7331 descent = -pHori->Descender;
7332 } else {
7333 ascent = pOS2->usWinAscent;
7334 descent = pOS2->usWinDescent;
7337 font->ntmCellHeight = ascent + descent;
7338 font->ntmAvgWidth = pOS2->xAvgCharWidth;
7340 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7341 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7343 if(font->yMax) {
7344 TM.tmAscent = font->yMax;
7345 TM.tmDescent = -font->yMin;
7346 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
7347 } else {
7348 TM.tmAscent = SCALE_Y(ascent);
7349 TM.tmDescent = SCALE_Y(descent);
7350 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
7353 TM.tmHeight = TM.tmAscent + TM.tmDescent;
7355 /* MSDN says:
7356 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7358 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
7359 ((ascent + descent) -
7360 (pHori->Ascender - pHori->Descender))));
7362 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
7363 if (TM.tmAveCharWidth == 0) {
7364 TM.tmAveCharWidth = 1;
7366 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
7367 TM.tmWeight = FW_REGULAR;
7368 if (font->fake_bold) {
7369 TM.tmAveCharWidth++;
7370 TM.tmMaxCharWidth++;
7371 TM.tmWeight = FW_BOLD;
7373 else
7375 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
7377 if (pOS2->usWeightClass > FW_MEDIUM)
7378 TM.tmWeight = pOS2->usWeightClass;
7380 else if (pOS2->usWeightClass <= FW_MEDIUM)
7381 TM.tmWeight = pOS2->usWeightClass;
7383 TM.tmOverhang = 0;
7384 TM.tmDigitizedAspectX = 96; /* FIXME */
7385 TM.tmDigitizedAspectY = 96; /* FIXME */
7386 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7387 * symbol range to 0 - f0ff
7390 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
7392 TM.tmFirstChar = 0;
7393 switch(GetACP())
7395 case 1257: /* Baltic */
7396 TM.tmLastChar = 0xf8fd;
7397 break;
7398 default:
7399 TM.tmLastChar = 0xf0ff;
7401 TM.tmBreakChar = 0x20;
7402 TM.tmDefaultChar = 0x1f;
7404 else
7406 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
7407 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
7409 if(pOS2->usFirstCharIndex <= 1)
7410 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
7411 else if (pOS2->usFirstCharIndex > 0xff)
7412 TM.tmBreakChar = 0x20;
7413 else
7414 TM.tmBreakChar = pOS2->usFirstCharIndex;
7415 TM.tmDefaultChar = TM.tmBreakChar - 1;
7417 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
7418 TM.tmUnderlined = font->underline;
7419 TM.tmStruckOut = font->strikeout;
7421 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7422 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7423 (pOS2->version == 0xFFFFU ||
7424 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7425 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7426 else
7427 TM.tmPitchAndFamily = 0;
7429 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7431 case PAN_FAMILY_SCRIPT:
7432 TM.tmPitchAndFamily |= FF_SCRIPT;
7433 break;
7435 case PAN_FAMILY_DECORATIVE:
7436 TM.tmPitchAndFamily |= FF_DECORATIVE;
7437 break;
7439 case PAN_ANY:
7440 case PAN_NO_FIT:
7441 case PAN_FAMILY_TEXT_DISPLAY:
7442 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7443 /* which is clearly not what the panose spec says. */
7444 default:
7445 if(TM.tmPitchAndFamily == 0 || /* fixed */
7446 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7447 TM.tmPitchAndFamily = FF_MODERN;
7448 else
7450 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7452 case PAN_ANY:
7453 case PAN_NO_FIT:
7454 default:
7455 TM.tmPitchAndFamily |= FF_DONTCARE;
7456 break;
7458 case PAN_SERIF_COVE:
7459 case PAN_SERIF_OBTUSE_COVE:
7460 case PAN_SERIF_SQUARE_COVE:
7461 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7462 case PAN_SERIF_SQUARE:
7463 case PAN_SERIF_THIN:
7464 case PAN_SERIF_BONE:
7465 case PAN_SERIF_EXAGGERATED:
7466 case PAN_SERIF_TRIANGLE:
7467 TM.tmPitchAndFamily |= FF_ROMAN;
7468 break;
7470 case PAN_SERIF_NORMAL_SANS:
7471 case PAN_SERIF_OBTUSE_SANS:
7472 case PAN_SERIF_PERP_SANS:
7473 case PAN_SERIF_FLARED:
7474 case PAN_SERIF_ROUNDED:
7475 TM.tmPitchAndFamily |= FF_SWISS;
7476 break;
7479 break;
7482 if(FT_IS_SCALABLE(ft_face))
7483 TM.tmPitchAndFamily |= TMPF_VECTOR;
7485 if(FT_IS_SFNT(ft_face))
7487 if (font->ntmFlags & NTM_PS_OPENTYPE)
7488 TM.tmPitchAndFamily |= TMPF_DEVICE;
7489 else
7490 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7493 TM.tmCharSet = font->charset;
7495 font->potm->otmFiller = 0;
7496 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7497 font->potm->otmfsSelection = pOS2->fsSelection;
7498 font->potm->otmfsType = pOS2->fsType;
7499 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7500 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7501 font->potm->otmItalicAngle = 0; /* POST table */
7502 font->potm->otmEMSquare = ft_face->units_per_EM;
7503 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7504 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7505 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7506 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7507 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7508 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7509 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7510 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7511 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7512 font->potm->otmMacAscent = TM.tmAscent;
7513 font->potm->otmMacDescent = -TM.tmDescent;
7514 font->potm->otmMacLineGap = font->potm->otmLineGap;
7515 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7516 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7517 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7518 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7519 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7520 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7521 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7522 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7523 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7524 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7525 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7526 if(!pPost) {
7527 font->potm->otmsUnderscoreSize = 0;
7528 font->potm->otmsUnderscorePosition = 0;
7529 } else {
7530 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7531 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7533 #undef SCALE_X
7534 #undef SCALE_Y
7535 #undef TM
7537 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7538 cp = (char*)font->potm + sizeof(*font->potm);
7539 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7540 strcpyW((WCHAR*)cp, family_nameW);
7541 cp += lenfam;
7542 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7543 strcpyW((WCHAR*)cp, style_nameW);
7544 cp += lensty;
7545 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7546 strcpyW((WCHAR*)cp, face_nameW);
7547 cp += lenface;
7548 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7549 strcpyW((WCHAR*)cp, full_nameW);
7550 ret = TRUE;
7552 end:
7553 HeapFree(GetProcessHeap(), 0, style_nameW);
7554 HeapFree(GetProcessHeap(), 0, family_nameW);
7555 HeapFree(GetProcessHeap(), 0, face_nameW);
7556 HeapFree(GetProcessHeap(), 0, full_nameW);
7557 return ret;
7560 /*************************************************************
7561 * freetype_GetGlyphOutline
7563 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7564 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7566 struct freetype_physdev *physdev = get_freetype_dev( dev );
7567 DWORD ret;
7568 ABC abc;
7570 if (!physdev->font)
7572 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7573 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7576 GDI_CheckNotLock();
7577 EnterCriticalSection( &freetype_cs );
7578 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7579 LeaveCriticalSection( &freetype_cs );
7580 return ret;
7583 /*************************************************************
7584 * freetype_GetTextMetrics
7586 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7588 struct freetype_physdev *physdev = get_freetype_dev( dev );
7589 BOOL ret;
7591 if (!physdev->font)
7593 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7594 return dev->funcs->pGetTextMetrics( dev, metrics );
7597 GDI_CheckNotLock();
7598 EnterCriticalSection( &freetype_cs );
7599 ret = get_text_metrics( physdev->font, metrics );
7600 LeaveCriticalSection( &freetype_cs );
7601 return ret;
7604 /*************************************************************
7605 * freetype_GetOutlineTextMetrics
7607 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7609 struct freetype_physdev *physdev = get_freetype_dev( dev );
7610 UINT ret = 0;
7612 if (!physdev->font)
7614 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7615 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7618 TRACE("font=%p\n", physdev->font);
7620 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7622 GDI_CheckNotLock();
7623 EnterCriticalSection( &freetype_cs );
7625 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7627 if(cbSize >= physdev->font->potm->otmSize)
7629 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7630 scale_outline_font_metrics(physdev->font, potm);
7632 ret = physdev->font->potm->otmSize;
7634 LeaveCriticalSection( &freetype_cs );
7635 return ret;
7638 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7640 child->font = alloc_font();
7641 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7642 if(!child->font->ft_face)
7644 free_font(child->font);
7645 child->font = NULL;
7646 return FALSE;
7649 child->font->font_desc = font->font_desc;
7650 child->font->ntmFlags = child->face->ntmFlags;
7651 child->font->orientation = font->orientation;
7652 child->font->scale_y = font->scale_y;
7653 child->font->name = strdupW(child->face->family->FamilyName);
7654 child->font->base_font = font;
7655 TRACE("created child font %p for base %p\n", child->font, font);
7656 return TRUE;
7659 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph, BOOL* vert)
7661 FT_UInt g,o;
7662 CHILD_FONT *child_font;
7664 if(font->base_font)
7665 font = font->base_font;
7667 *linked_font = font;
7669 if((*glyph = get_glyph_index(font, c)))
7671 o = *glyph;
7672 *glyph = get_GSUB_vert_glyph(font, *glyph);
7673 *vert = (o != *glyph);
7674 return TRUE;
7677 if (c < 32) goto done; /* don't check linked fonts for control characters */
7679 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7681 if(!child_font->font)
7682 if(!load_child_font(font, child_font))
7683 continue;
7685 if(!child_font->font->ft_face)
7686 continue;
7687 g = get_glyph_index(child_font->font, c);
7688 o = g;
7689 g = get_GSUB_vert_glyph(child_font->font, g);
7690 if(g)
7692 *glyph = g;
7693 *linked_font = child_font->font;
7694 *vert = (o != g);
7695 return TRUE;
7699 done:
7700 *vert = FALSE;
7701 return FALSE;
7704 /*************************************************************
7705 * freetype_GetCharWidth
7707 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7709 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7710 UINT c;
7711 GLYPHMETRICS gm;
7712 ABC abc;
7713 struct freetype_physdev *physdev = get_freetype_dev( dev );
7715 if (!physdev->font)
7717 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7718 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7721 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7723 GDI_CheckNotLock();
7724 EnterCriticalSection( &freetype_cs );
7725 for(c = firstChar; c <= lastChar; c++) {
7726 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7727 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7729 LeaveCriticalSection( &freetype_cs );
7730 return TRUE;
7733 /*************************************************************
7734 * freetype_GetCharABCWidths
7736 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7738 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7739 UINT c;
7740 GLYPHMETRICS gm;
7741 struct freetype_physdev *physdev = get_freetype_dev( dev );
7743 if (!physdev->font)
7745 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7746 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7749 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7751 GDI_CheckNotLock();
7752 EnterCriticalSection( &freetype_cs );
7754 for(c = firstChar; c <= lastChar; c++, buffer++)
7755 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7757 LeaveCriticalSection( &freetype_cs );
7758 return TRUE;
7761 /*************************************************************
7762 * freetype_GetCharABCWidthsI
7764 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7766 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7767 UINT c;
7768 GLYPHMETRICS gm;
7769 struct freetype_physdev *physdev = get_freetype_dev( dev );
7771 if (!physdev->font)
7773 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7774 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7777 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7778 return FALSE;
7780 GDI_CheckNotLock();
7781 EnterCriticalSection( &freetype_cs );
7783 for(c = 0; c < count; c++, buffer++)
7784 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7785 &gm, buffer, 0, NULL, &identity );
7787 LeaveCriticalSection( &freetype_cs );
7788 return TRUE;
7791 /*************************************************************
7792 * freetype_GetTextExtentExPoint
7794 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7796 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7797 INT idx, pos;
7798 ABC abc;
7799 GLYPHMETRICS gm;
7800 struct freetype_physdev *physdev = get_freetype_dev( dev );
7802 if (!physdev->font)
7804 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7805 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7808 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7810 GDI_CheckNotLock();
7811 EnterCriticalSection( &freetype_cs );
7813 for (idx = pos = 0; idx < count; idx++)
7815 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7816 pos += abc.abcA + abc.abcB + abc.abcC;
7817 dxs[idx] = pos;
7820 LeaveCriticalSection( &freetype_cs );
7821 return TRUE;
7824 /*************************************************************
7825 * freetype_GetTextExtentExPointI
7827 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7829 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7830 INT idx, pos;
7831 ABC abc;
7832 GLYPHMETRICS gm;
7833 struct freetype_physdev *physdev = get_freetype_dev( dev );
7835 if (!physdev->font)
7837 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7838 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7841 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7843 GDI_CheckNotLock();
7844 EnterCriticalSection( &freetype_cs );
7846 for (idx = pos = 0; idx < count; idx++)
7848 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7849 &gm, &abc, 0, NULL, &identity );
7850 pos += abc.abcA + abc.abcB + abc.abcC;
7851 dxs[idx] = pos;
7854 LeaveCriticalSection( &freetype_cs );
7855 return TRUE;
7858 /*************************************************************
7859 * freetype_GetFontData
7861 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7863 struct freetype_physdev *physdev = get_freetype_dev( dev );
7865 if (!physdev->font)
7867 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7868 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7871 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7872 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7873 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7875 return get_font_data( physdev->font, table, offset, buf, cbData );
7878 /*************************************************************
7879 * freetype_GetTextFace
7881 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7883 INT n;
7884 struct freetype_physdev *physdev = get_freetype_dev( dev );
7886 if (!physdev->font)
7888 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7889 return dev->funcs->pGetTextFace( dev, count, str );
7892 n = strlenW(physdev->font->name) + 1;
7893 if (str)
7895 lstrcpynW(str, physdev->font->name, count);
7896 n = min(count, n);
7898 return n;
7901 /*************************************************************
7902 * freetype_GetTextCharsetInfo
7904 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7906 struct freetype_physdev *physdev = get_freetype_dev( dev );
7908 if (!physdev->font)
7910 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7911 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7913 if (fs) *fs = physdev->font->fs;
7914 return physdev->font->charset;
7917 /* Retrieve a list of supported Unicode ranges for a given font.
7918 * Can be called with NULL gs to calculate the buffer size. Returns
7919 * the number of ranges found.
7921 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7923 DWORD num_ranges = 0;
7925 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7927 FT_UInt glyph_code;
7928 FT_ULong char_code, char_code_prev;
7930 glyph_code = 0;
7931 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7933 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7934 face->num_glyphs, glyph_code, char_code);
7936 if (!glyph_code) return 0;
7938 if (gs)
7940 gs->ranges[0].wcLow = (USHORT)char_code;
7941 gs->ranges[0].cGlyphs = 0;
7942 gs->cGlyphsSupported = 0;
7945 num_ranges = 1;
7946 while (glyph_code)
7948 if (char_code < char_code_prev)
7950 ERR("expected increasing char code from FT_Get_Next_Char\n");
7951 return 0;
7953 if (char_code - char_code_prev > 1)
7955 num_ranges++;
7956 if (gs)
7958 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7959 gs->ranges[num_ranges - 1].cGlyphs = 1;
7960 gs->cGlyphsSupported++;
7963 else if (gs)
7965 gs->ranges[num_ranges - 1].cGlyphs++;
7966 gs->cGlyphsSupported++;
7968 char_code_prev = char_code;
7969 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7972 else
7973 FIXME("encoding %u not supported\n", face->charmap->encoding);
7975 return num_ranges;
7978 /*************************************************************
7979 * freetype_GetFontUnicodeRanges
7981 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7983 struct freetype_physdev *physdev = get_freetype_dev( dev );
7984 DWORD size, num_ranges;
7986 if (!physdev->font)
7988 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7989 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7992 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7993 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7994 if (glyphset)
7996 glyphset->cbThis = size;
7997 glyphset->cRanges = num_ranges;
7998 glyphset->flAccel = 0;
8000 return size;
8003 /*************************************************************
8004 * freetype_FontIsLinked
8006 static BOOL freetype_FontIsLinked( PHYSDEV dev )
8008 struct freetype_physdev *physdev = get_freetype_dev( dev );
8009 BOOL ret;
8011 if (!physdev->font)
8013 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
8014 return dev->funcs->pFontIsLinked( dev );
8017 GDI_CheckNotLock();
8018 EnterCriticalSection( &freetype_cs );
8019 ret = !list_empty(&physdev->font->child_fonts);
8020 LeaveCriticalSection( &freetype_cs );
8021 return ret;
8024 /*************************************************************************
8025 * GetRasterizerCaps (GDI32.@)
8027 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8029 lprs->nSize = sizeof(RASTERIZER_STATUS);
8030 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
8031 lprs->nLanguageID = 0;
8032 return TRUE;
8035 /*************************************************************
8036 * freetype_GdiRealizationInfo
8038 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
8040 struct freetype_physdev *physdev = get_freetype_dev( dev );
8041 realization_info_t *info = ptr;
8043 if (!physdev->font)
8045 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
8046 return dev->funcs->pGdiRealizationInfo( dev, ptr );
8049 FIXME("(%p, %p): stub!\n", physdev->font, info);
8051 info->flags = 1;
8052 if(FT_IS_SCALABLE(physdev->font->ft_face))
8053 info->flags |= 2;
8055 info->cache_num = physdev->font->cache_num;
8056 info->unknown2 = -1;
8057 return TRUE;
8060 /*************************************************************************
8061 * Kerning support for TrueType fonts
8063 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8065 struct TT_kern_table
8067 USHORT version;
8068 USHORT nTables;
8071 struct TT_kern_subtable
8073 USHORT version;
8074 USHORT length;
8075 union
8077 USHORT word;
8078 struct
8080 USHORT horizontal : 1;
8081 USHORT minimum : 1;
8082 USHORT cross_stream: 1;
8083 USHORT override : 1;
8084 USHORT reserved1 : 4;
8085 USHORT format : 8;
8086 } bits;
8087 } coverage;
8090 struct TT_format0_kern_subtable
8092 USHORT nPairs;
8093 USHORT searchRange;
8094 USHORT entrySelector;
8095 USHORT rangeShift;
8098 struct TT_kern_pair
8100 USHORT left;
8101 USHORT right;
8102 short value;
8105 static DWORD parse_format0_kern_subtable(GdiFont *font,
8106 const struct TT_format0_kern_subtable *tt_f0_ks,
8107 const USHORT *glyph_to_char,
8108 KERNINGPAIR *kern_pair, DWORD cPairs)
8110 USHORT i, nPairs;
8111 const struct TT_kern_pair *tt_kern_pair;
8113 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
8115 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
8117 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8118 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
8119 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
8121 if (!kern_pair || !cPairs)
8122 return nPairs;
8124 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
8126 nPairs = min(nPairs, cPairs);
8128 for (i = 0; i < nPairs; i++)
8130 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
8131 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
8132 /* this algorithm appears to better match what Windows does */
8133 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
8134 if (kern_pair->iKernAmount < 0)
8136 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
8137 kern_pair->iKernAmount -= font->ppem;
8139 else if (kern_pair->iKernAmount > 0)
8141 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
8142 kern_pair->iKernAmount += font->ppem;
8144 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
8146 TRACE("left %u right %u value %d\n",
8147 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
8149 kern_pair++;
8151 TRACE("copied %u entries\n", nPairs);
8152 return nPairs;
8155 /*************************************************************
8156 * freetype_GetKerningPairs
8158 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
8160 DWORD length;
8161 void *buf;
8162 const struct TT_kern_table *tt_kern_table;
8163 const struct TT_kern_subtable *tt_kern_subtable;
8164 USHORT i, nTables;
8165 USHORT *glyph_to_char;
8166 GdiFont *font;
8167 struct freetype_physdev *physdev = get_freetype_dev( dev );
8169 if (!(font = physdev->font))
8171 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
8172 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
8175 GDI_CheckNotLock();
8176 EnterCriticalSection( &freetype_cs );
8177 if (font->total_kern_pairs != (DWORD)-1)
8179 if (cPairs && kern_pair)
8181 cPairs = min(cPairs, font->total_kern_pairs);
8182 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8184 else cPairs = font->total_kern_pairs;
8186 LeaveCriticalSection( &freetype_cs );
8187 return cPairs;
8190 font->total_kern_pairs = 0;
8192 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
8194 if (length == GDI_ERROR)
8196 TRACE("no kerning data in the font\n");
8197 LeaveCriticalSection( &freetype_cs );
8198 return 0;
8201 buf = HeapAlloc(GetProcessHeap(), 0, length);
8202 if (!buf)
8204 WARN("Out of memory\n");
8205 LeaveCriticalSection( &freetype_cs );
8206 return 0;
8209 get_font_data(font, MS_KERN_TAG, 0, buf, length);
8211 /* build a glyph index to char code map */
8212 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
8213 if (!glyph_to_char)
8215 WARN("Out of memory allocating a glyph index to char code map\n");
8216 HeapFree(GetProcessHeap(), 0, buf);
8217 LeaveCriticalSection( &freetype_cs );
8218 return 0;
8221 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
8223 FT_UInt glyph_code;
8224 FT_ULong char_code;
8226 glyph_code = 0;
8227 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
8229 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8230 font->ft_face->num_glyphs, glyph_code, char_code);
8232 while (glyph_code)
8234 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8236 /* FIXME: This doesn't match what Windows does: it does some fancy
8237 * things with duplicate glyph index to char code mappings, while
8238 * we just avoid overriding existing entries.
8240 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
8241 glyph_to_char[glyph_code] = (USHORT)char_code;
8243 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
8246 else
8248 ULONG n;
8250 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
8251 for (n = 0; n <= 65535; n++)
8252 glyph_to_char[n] = (USHORT)n;
8255 tt_kern_table = buf;
8256 nTables = GET_BE_WORD(tt_kern_table->nTables);
8257 TRACE("version %u, nTables %u\n",
8258 GET_BE_WORD(tt_kern_table->version), nTables);
8260 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
8262 for (i = 0; i < nTables; i++)
8264 struct TT_kern_subtable tt_kern_subtable_copy;
8266 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
8267 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
8268 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
8270 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8271 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
8272 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
8274 /* According to the TrueType specification this is the only format
8275 * that will be properly interpreted by Windows and OS/2
8277 if (tt_kern_subtable_copy.coverage.bits.format == 0)
8279 DWORD new_chunk, old_total = font->total_kern_pairs;
8281 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8282 glyph_to_char, NULL, 0);
8283 font->total_kern_pairs += new_chunk;
8285 if (!font->kern_pairs)
8286 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
8287 font->total_kern_pairs * sizeof(*font->kern_pairs));
8288 else
8289 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
8290 font->total_kern_pairs * sizeof(*font->kern_pairs));
8292 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
8293 glyph_to_char, font->kern_pairs + old_total, new_chunk);
8295 else
8296 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
8298 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
8301 HeapFree(GetProcessHeap(), 0, glyph_to_char);
8302 HeapFree(GetProcessHeap(), 0, buf);
8304 if (cPairs && kern_pair)
8306 cPairs = min(cPairs, font->total_kern_pairs);
8307 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
8309 else cPairs = font->total_kern_pairs;
8311 LeaveCriticalSection( &freetype_cs );
8312 return cPairs;
8315 static const struct gdi_dc_funcs freetype_funcs =
8317 NULL, /* pAbortDoc */
8318 NULL, /* pAbortPath */
8319 NULL, /* pAlphaBlend */
8320 NULL, /* pAngleArc */
8321 NULL, /* pArc */
8322 NULL, /* pArcTo */
8323 NULL, /* pBeginPath */
8324 NULL, /* pBlendImage */
8325 NULL, /* pChord */
8326 NULL, /* pCloseFigure */
8327 NULL, /* pCreateCompatibleDC */
8328 freetype_CreateDC, /* pCreateDC */
8329 freetype_DeleteDC, /* pDeleteDC */
8330 NULL, /* pDeleteObject */
8331 NULL, /* pDeviceCapabilities */
8332 NULL, /* pEllipse */
8333 NULL, /* pEndDoc */
8334 NULL, /* pEndPage */
8335 NULL, /* pEndPath */
8336 freetype_EnumFonts, /* pEnumFonts */
8337 NULL, /* pEnumICMProfiles */
8338 NULL, /* pExcludeClipRect */
8339 NULL, /* pExtDeviceMode */
8340 NULL, /* pExtEscape */
8341 NULL, /* pExtFloodFill */
8342 NULL, /* pExtSelectClipRgn */
8343 NULL, /* pExtTextOut */
8344 NULL, /* pFillPath */
8345 NULL, /* pFillRgn */
8346 NULL, /* pFlattenPath */
8347 freetype_FontIsLinked, /* pFontIsLinked */
8348 NULL, /* pFrameRgn */
8349 NULL, /* pGdiComment */
8350 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
8351 NULL, /* pGetBoundsRect */
8352 freetype_GetCharABCWidths, /* pGetCharABCWidths */
8353 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
8354 freetype_GetCharWidth, /* pGetCharWidth */
8355 NULL, /* pGetDeviceCaps */
8356 NULL, /* pGetDeviceGammaRamp */
8357 freetype_GetFontData, /* pGetFontData */
8358 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
8359 freetype_GetGlyphIndices, /* pGetGlyphIndices */
8360 freetype_GetGlyphOutline, /* pGetGlyphOutline */
8361 NULL, /* pGetICMProfile */
8362 NULL, /* pGetImage */
8363 freetype_GetKerningPairs, /* pGetKerningPairs */
8364 NULL, /* pGetNearestColor */
8365 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
8366 NULL, /* pGetPixel */
8367 NULL, /* pGetSystemPaletteEntries */
8368 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
8369 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
8370 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
8371 freetype_GetTextFace, /* pGetTextFace */
8372 freetype_GetTextMetrics, /* pGetTextMetrics */
8373 NULL, /* pGradientFill */
8374 NULL, /* pIntersectClipRect */
8375 NULL, /* pInvertRgn */
8376 NULL, /* pLineTo */
8377 NULL, /* pModifyWorldTransform */
8378 NULL, /* pMoveTo */
8379 NULL, /* pOffsetClipRgn */
8380 NULL, /* pOffsetViewportOrg */
8381 NULL, /* pOffsetWindowOrg */
8382 NULL, /* pPaintRgn */
8383 NULL, /* pPatBlt */
8384 NULL, /* pPie */
8385 NULL, /* pPolyBezier */
8386 NULL, /* pPolyBezierTo */
8387 NULL, /* pPolyDraw */
8388 NULL, /* pPolyPolygon */
8389 NULL, /* pPolyPolyline */
8390 NULL, /* pPolygon */
8391 NULL, /* pPolyline */
8392 NULL, /* pPolylineTo */
8393 NULL, /* pPutImage */
8394 NULL, /* pRealizeDefaultPalette */
8395 NULL, /* pRealizePalette */
8396 NULL, /* pRectangle */
8397 NULL, /* pResetDC */
8398 NULL, /* pRestoreDC */
8399 NULL, /* pRoundRect */
8400 NULL, /* pSaveDC */
8401 NULL, /* pScaleViewportExt */
8402 NULL, /* pScaleWindowExt */
8403 NULL, /* pSelectBitmap */
8404 NULL, /* pSelectBrush */
8405 NULL, /* pSelectClipPath */
8406 freetype_SelectFont, /* pSelectFont */
8407 NULL, /* pSelectPalette */
8408 NULL, /* pSelectPen */
8409 NULL, /* pSetArcDirection */
8410 NULL, /* pSetBkColor */
8411 NULL, /* pSetBkMode */
8412 NULL, /* pSetDCBrushColor */
8413 NULL, /* pSetDCPenColor */
8414 NULL, /* pSetDIBColorTable */
8415 NULL, /* pSetDIBitsToDevice */
8416 NULL, /* pSetDeviceClipping */
8417 NULL, /* pSetDeviceGammaRamp */
8418 NULL, /* pSetLayout */
8419 NULL, /* pSetMapMode */
8420 NULL, /* pSetMapperFlags */
8421 NULL, /* pSetPixel */
8422 NULL, /* pSetPolyFillMode */
8423 NULL, /* pSetROP2 */
8424 NULL, /* pSetRelAbs */
8425 NULL, /* pSetStretchBltMode */
8426 NULL, /* pSetTextAlign */
8427 NULL, /* pSetTextCharacterExtra */
8428 NULL, /* pSetTextColor */
8429 NULL, /* pSetTextJustification */
8430 NULL, /* pSetViewportExt */
8431 NULL, /* pSetViewportOrg */
8432 NULL, /* pSetWindowExt */
8433 NULL, /* pSetWindowOrg */
8434 NULL, /* pSetWorldTransform */
8435 NULL, /* pStartDoc */
8436 NULL, /* pStartPage */
8437 NULL, /* pStretchBlt */
8438 NULL, /* pStretchDIBits */
8439 NULL, /* pStrokeAndFillPath */
8440 NULL, /* pStrokePath */
8441 NULL, /* pUnrealizePalette */
8442 NULL, /* pWidenPath */
8443 NULL, /* wine_get_wgl_driver */
8444 GDI_PRIORITY_FONT_DRV /* priority */
8447 #else /* HAVE_FREETYPE */
8449 /*************************************************************************/
8451 BOOL WineEngInit(void)
8453 return FALSE;
8456 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8458 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8459 return 1;
8462 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8464 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8465 return TRUE;
8468 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8470 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8471 return NULL;
8474 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8475 LPCWSTR font_file, LPCWSTR font_path )
8477 FIXME("stub\n");
8478 return FALSE;
8481 /*************************************************************************
8482 * GetRasterizerCaps (GDI32.@)
8484 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8486 lprs->nSize = sizeof(RASTERIZER_STATUS);
8487 lprs->wFlags = 0;
8488 lprs->nLanguageID = 0;
8489 return TRUE;
8492 #endif /* HAVE_FREETYPE */