gdi32: Ignore the lfHeight value when it exceeds the limit.
[wine/wine-gecko.git] / dlls / gdi32 / freetype.c
blob141238bd88db6084b68a234fad0578c920098067
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 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 #include "resource.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FREETYPE
98 #ifdef HAVE_FT2BUILD_H
99 #include <ft2build.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
103 #endif
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
106 #endif
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
112 #endif
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
115 #endif
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
118 #endif
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
121 #endif
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
124 #endif
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
127 #endif
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
130 #endif
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
173 #else
174 MAKE_FUNCPTR(FT_MulFix);
175 #endif
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigSubstitute);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetInteger);
205 MAKE_FUNCPTR(FcPatternGetString);
206 #endif
208 #undef MAKE_FUNCPTR
210 #ifndef FT_MAKE_TAG
211 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
212 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
213 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
214 #endif
216 #ifndef ft_encoding_none
217 #define FT_ENCODING_NONE ft_encoding_none
218 #endif
219 #ifndef ft_encoding_ms_symbol
220 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #endif
222 #ifndef ft_encoding_unicode
223 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #endif
225 #ifndef ft_encoding_apple_roman
226 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
227 #endif
229 #ifdef WORDS_BIGENDIAN
230 #define GET_BE_WORD(x) (x)
231 #else
232 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
233 #endif
235 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
236 typedef struct {
237 FT_Short height;
238 FT_Short width;
239 FT_Pos size;
240 FT_Pos x_ppem;
241 FT_Pos y_ppem;
242 FT_Short internal_leading;
243 } Bitmap_Size;
245 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
246 So to let this compile on older versions of FreeType we'll define the
247 new structure here. */
248 typedef struct {
249 FT_Short height, width;
250 FT_Pos size, x_ppem, y_ppem;
251 } My_FT_Bitmap_Size;
253 struct enum_data
255 ENUMLOGFONTEXW elf;
256 NEWTEXTMETRICEXW ntm;
257 DWORD type;
260 typedef struct tagFace {
261 struct list entry;
262 unsigned int refcount;
263 WCHAR *StyleName;
264 WCHAR *FullName;
265 WCHAR *file;
266 dev_t dev;
267 ino_t ino;
268 void *font_data_ptr;
269 DWORD font_data_size;
270 FT_Long face_index;
271 FONTSIGNATURE fs;
272 DWORD ntmFlags;
273 FT_Fixed font_version;
274 BOOL scalable;
275 Bitmap_Size size; /* set if face is a bitmap */
276 DWORD flags; /* ADDFONT flags */
277 struct tagFamily *family;
278 /* Cached data for Enum */
279 struct enum_data *cached_enum_data;
280 } Face;
282 #define ADDFONT_EXTERNAL_FONT 0x01
283 #define ADDFONT_ALLOW_BITMAP 0x02
284 #define ADDFONT_ADD_TO_CACHE 0x04
285 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
286 #define ADDFONT_VERTICAL_FONT 0x10
287 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
289 typedef struct tagFamily {
290 struct list entry;
291 unsigned int refcount;
292 WCHAR *FamilyName;
293 WCHAR *EnglishName;
294 struct list faces;
295 struct list *replacement;
296 } Family;
298 typedef struct {
299 GLYPHMETRICS gm;
300 ABC abc; /* metrics of the unrotated char */
301 BOOL init;
302 } GM;
304 typedef struct {
305 FLOAT eM11, eM12;
306 FLOAT eM21, eM22;
307 } FMAT2;
309 typedef struct {
310 DWORD hash;
311 LOGFONTW lf;
312 FMAT2 matrix;
313 BOOL can_use_bitmap;
314 } FONT_DESC;
316 typedef struct tagGdiFont GdiFont;
318 typedef struct {
319 struct list entry;
320 Face *face;
321 GdiFont *font;
322 } CHILD_FONT;
324 struct tagGdiFont {
325 struct list entry;
326 struct list unused_entry;
327 unsigned int refcount;
328 GM **gm;
329 DWORD gmsize;
330 OUTLINETEXTMETRICW *potm;
331 DWORD total_kern_pairs;
332 KERNINGPAIR *kern_pairs;
333 struct list child_fonts;
335 /* the following members can be accessed without locking, they are never modified after creation */
336 FT_Face ft_face;
337 struct font_mapping *mapping;
338 LPWSTR name;
339 int charset;
340 int codepage;
341 BOOL fake_italic;
342 BOOL fake_bold;
343 BYTE underline;
344 BYTE strikeout;
345 INT orientation;
346 FONT_DESC font_desc;
347 LONG aveWidth, ppem;
348 double scale_y;
349 SHORT yMax;
350 SHORT yMin;
351 DWORD ntmFlags;
352 DWORD aa_flags;
353 UINT ntmCellHeight, ntmAvgWidth;
354 FONTSIGNATURE fs;
355 GdiFont *base_font;
356 VOID *GSUB_Table;
357 DWORD cache_num;
360 typedef struct {
361 struct list entry;
362 const WCHAR *font_name;
363 FONTSIGNATURE fs;
364 struct list links;
365 } SYSTEM_LINKS;
367 struct enum_charset_element {
368 DWORD mask;
369 DWORD charset;
370 WCHAR name[LF_FACESIZE];
373 struct enum_charset_list {
374 DWORD total;
375 struct enum_charset_element element[32];
378 #define GM_BLOCK_SIZE 128
379 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
381 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
382 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
383 static unsigned int unused_font_count;
384 #define UNUSED_CACHE_SIZE 10
385 static struct list system_links = LIST_INIT(system_links);
387 static struct list font_subst_list = LIST_INIT(font_subst_list);
389 static struct list font_list = LIST_INIT(font_list);
391 struct freetype_physdev
393 struct gdi_physdev dev;
394 GdiFont *font;
397 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
399 return (struct freetype_physdev *)dev;
402 static const struct gdi_dc_funcs freetype_funcs;
404 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
405 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
406 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
408 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
409 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
410 'W','i','n','d','o','w','s','\\',
411 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
412 'F','o','n','t','s','\0'};
414 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
415 'W','i','n','d','o','w','s',' ','N','T','\\',
416 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
417 'F','o','n','t','s','\0'};
419 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
420 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
421 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
422 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
424 static const WCHAR * const SystemFontValues[] = {
425 System_Value,
426 OEMFont_Value,
427 FixedSys_Value,
428 NULL
431 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
432 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
434 /* Interesting and well-known (frequently-assumed!) font names */
435 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
436 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 };
437 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
438 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
439 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
440 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
441 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
442 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
444 static const WCHAR arial[] = {'A','r','i','a','l',0};
445 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
446 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};
447 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};
448 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
449 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
450 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
451 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
452 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
453 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
455 static const WCHAR *default_serif_list[] =
457 times_new_roman,
458 liberation_serif,
459 bitstream_vera_serif,
460 NULL
463 static const WCHAR *default_fixed_list[] =
465 courier_new,
466 liberation_mono,
467 bitstream_vera_sans_mono,
468 NULL
471 static const WCHAR *default_sans_list[] =
473 arial,
474 liberation_sans,
475 bitstream_vera_sans,
476 NULL
479 typedef struct {
480 WCHAR *name;
481 INT charset;
482 } NameCs;
484 typedef struct tagFontSubst {
485 struct list entry;
486 NameCs from;
487 NameCs to;
488 } FontSubst;
490 /* Registry font cache key and value names */
491 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
492 'F','o','n','t','s',0};
493 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
494 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
495 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
496 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
497 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
498 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
499 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
500 static const WCHAR face_size_value[] = {'S','i','z','e',0};
501 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
502 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
503 static const WCHAR face_flags_value[] = {'F','l','a','g','s',0};
504 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
505 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
506 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
507 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
510 struct font_mapping
512 struct list entry;
513 int refcount;
514 dev_t dev;
515 ino_t ino;
516 void *data;
517 size_t size;
520 static struct list mappings_list = LIST_INIT( mappings_list );
522 static UINT default_aa_flags;
523 static HKEY hkey_font_cache;
525 static CRITICAL_SECTION freetype_cs;
526 static CRITICAL_SECTION_DEBUG critsect_debug =
528 0, 0, &freetype_cs,
529 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
530 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
532 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
534 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
536 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
537 static BOOL use_default_fallback = FALSE;
539 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
540 static BOOL get_outline_text_metrics(GdiFont *font);
541 static BOOL get_bitmap_text_metrics(GdiFont *font);
542 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
543 static void remove_face_from_cache( Face *face );
545 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
546 'W','i','n','d','o','w','s',' ','N','T','\\',
547 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
548 'S','y','s','t','e','m','L','i','n','k',0};
550 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
551 'F','o','n','t','L','i','n','k','\\',
552 'S','y','s','t','e','m','L','i','n','k',0};
554 /****************************************
555 * Notes on .fon files
557 * The fonts System, FixedSys and Terminal are special. There are typically multiple
558 * versions installed for different resolutions and codepages. Windows stores which one to use
559 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
560 * Key Meaning
561 * FIXEDFON.FON FixedSys
562 * FONTS.FON System
563 * OEMFONT.FON Terminal
564 * LogPixels Current dpi set by the display control panel applet
565 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
566 * also has a LogPixels value that appears to mirror this)
568 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
569 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
570 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
571 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
572 * so that makes sense.
574 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
575 * to be mapped into the registry on Windows 2000 at least).
576 * I have
577 * woafont=app850.fon
578 * ega80woa.fon=ega80850.fon
579 * ega40woa.fon=ega40850.fon
580 * cga80woa.fon=cga80850.fon
581 * cga40woa.fon=cga40850.fon
584 /* These are all structures needed for the GSUB table */
586 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
587 #define TATEGAKI_LOWER_BOUND 0x02F1
589 typedef struct {
590 DWORD version;
591 WORD ScriptList;
592 WORD FeatureList;
593 WORD LookupList;
594 } GSUB_Header;
596 typedef struct {
597 CHAR ScriptTag[4];
598 WORD Script;
599 } GSUB_ScriptRecord;
601 typedef struct {
602 WORD ScriptCount;
603 GSUB_ScriptRecord ScriptRecord[1];
604 } GSUB_ScriptList;
606 typedef struct {
607 CHAR LangSysTag[4];
608 WORD LangSys;
609 } GSUB_LangSysRecord;
611 typedef struct {
612 WORD DefaultLangSys;
613 WORD LangSysCount;
614 GSUB_LangSysRecord LangSysRecord[1];
615 } GSUB_Script;
617 typedef struct {
618 WORD LookupOrder; /* Reserved */
619 WORD ReqFeatureIndex;
620 WORD FeatureCount;
621 WORD FeatureIndex[1];
622 } GSUB_LangSys;
624 typedef struct {
625 CHAR FeatureTag[4];
626 WORD Feature;
627 } GSUB_FeatureRecord;
629 typedef struct {
630 WORD FeatureCount;
631 GSUB_FeatureRecord FeatureRecord[1];
632 } GSUB_FeatureList;
634 typedef struct {
635 WORD FeatureParams; /* Reserved */
636 WORD LookupCount;
637 WORD LookupListIndex[1];
638 } GSUB_Feature;
640 typedef struct {
641 WORD LookupCount;
642 WORD Lookup[1];
643 } GSUB_LookupList;
645 typedef struct {
646 WORD LookupType;
647 WORD LookupFlag;
648 WORD SubTableCount;
649 WORD SubTable[1];
650 } GSUB_LookupTable;
652 typedef struct {
653 WORD CoverageFormat;
654 WORD GlyphCount;
655 WORD GlyphArray[1];
656 } GSUB_CoverageFormat1;
658 typedef struct {
659 WORD Start;
660 WORD End;
661 WORD StartCoverageIndex;
662 } GSUB_RangeRecord;
664 typedef struct {
665 WORD CoverageFormat;
666 WORD RangeCount;
667 GSUB_RangeRecord RangeRecord[1];
668 } GSUB_CoverageFormat2;
670 typedef struct {
671 WORD SubstFormat; /* = 1 */
672 WORD Coverage;
673 WORD DeltaGlyphID;
674 } GSUB_SingleSubstFormat1;
676 typedef struct {
677 WORD SubstFormat; /* = 2 */
678 WORD Coverage;
679 WORD GlyphCount;
680 WORD Substitute[1];
681 }GSUB_SingleSubstFormat2;
683 #ifdef HAVE_CARBON_CARBON_H
684 static char *find_cache_dir(void)
686 FSRef ref;
687 OSErr err;
688 static char cached_path[MAX_PATH];
689 static const char *wine = "/Wine", *fonts = "/Fonts";
691 if(*cached_path) return cached_path;
693 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
694 if(err != noErr)
696 WARN("can't create cached data folder\n");
697 return NULL;
699 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
700 if(err != noErr)
702 WARN("can't create cached data path\n");
703 *cached_path = '\0';
704 return NULL;
706 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
708 ERR("Could not create full path\n");
709 *cached_path = '\0';
710 return NULL;
712 strcat(cached_path, wine);
714 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
716 WARN("Couldn't mkdir %s\n", cached_path);
717 *cached_path = '\0';
718 return NULL;
720 strcat(cached_path, fonts);
721 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
723 WARN("Couldn't mkdir %s\n", cached_path);
724 *cached_path = '\0';
725 return NULL;
727 return cached_path;
730 /******************************************************************
731 * expand_mac_font
733 * Extracts individual TrueType font files from a Mac suitcase font
734 * and saves them into the user's caches directory (see
735 * find_cache_dir()).
736 * Returns a NULL terminated array of filenames.
738 * We do this because they are apps that try to read ttf files
739 * themselves and they don't like Mac suitcase files.
741 static char **expand_mac_font(const char *path)
743 FSRef ref;
744 SInt16 res_ref;
745 OSStatus s;
746 unsigned int idx;
747 const char *out_dir;
748 const char *filename;
749 int output_len;
750 struct {
751 char **array;
752 unsigned int size, max_size;
753 } ret;
755 TRACE("path %s\n", path);
757 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
758 if(s != noErr)
760 WARN("failed to get ref\n");
761 return NULL;
764 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
765 if(s != noErr)
767 TRACE("no data fork, so trying resource fork\n");
768 res_ref = FSOpenResFile(&ref, fsRdPerm);
769 if(res_ref == -1)
771 TRACE("unable to open resource fork\n");
772 return NULL;
776 ret.size = 0;
777 ret.max_size = 10;
778 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
779 if(!ret.array)
781 CloseResFile(res_ref);
782 return NULL;
785 out_dir = find_cache_dir();
787 filename = strrchr(path, '/');
788 if(!filename) filename = path;
789 else filename++;
791 /* output filename has the form out_dir/filename_%04x.ttf */
792 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
794 UseResFile(res_ref);
795 idx = 1;
796 while(1)
798 FamRec *fam_rec;
799 unsigned short *num_faces_ptr, num_faces, face;
800 AsscEntry *assoc;
801 Handle fond;
802 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
804 fond = Get1IndResource(fond_res, idx);
805 if(!fond) break;
806 TRACE("got fond resource %d\n", idx);
807 HLock(fond);
809 fam_rec = *(FamRec**)fond;
810 num_faces_ptr = (unsigned short *)(fam_rec + 1);
811 num_faces = GET_BE_WORD(*num_faces_ptr);
812 num_faces++;
813 assoc = (AsscEntry*)(num_faces_ptr + 1);
814 TRACE("num faces %04x\n", num_faces);
815 for(face = 0; face < num_faces; face++, assoc++)
817 Handle sfnt;
818 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
819 unsigned short size, font_id;
820 char *output;
822 size = GET_BE_WORD(assoc->fontSize);
823 font_id = GET_BE_WORD(assoc->fontID);
824 if(size != 0)
826 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
827 continue;
830 TRACE("trying to load sfnt id %04x\n", font_id);
831 sfnt = GetResource(sfnt_res, font_id);
832 if(!sfnt)
834 TRACE("can't get sfnt resource %04x\n", font_id);
835 continue;
838 output = HeapAlloc(GetProcessHeap(), 0, output_len);
839 if(output)
841 int fd;
843 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
845 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
846 if(fd != -1 || errno == EEXIST)
848 if(fd != -1)
850 unsigned char *sfnt_data;
852 HLock(sfnt);
853 sfnt_data = *(unsigned char**)sfnt;
854 write(fd, sfnt_data, GetHandleSize(sfnt));
855 HUnlock(sfnt);
856 close(fd);
858 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
860 ret.max_size *= 2;
861 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
863 ret.array[ret.size++] = output;
865 else
867 WARN("unable to create %s\n", output);
868 HeapFree(GetProcessHeap(), 0, output);
871 ReleaseResource(sfnt);
873 HUnlock(fond);
874 ReleaseResource(fond);
875 idx++;
877 CloseResFile(res_ref);
879 return ret.array;
882 #endif /* HAVE_CARBON_CARBON_H */
884 static inline BOOL is_win9x(void)
886 return GetVersion() & 0x80000000;
889 This function builds an FT_Fixed from a double. It fails if the absolute
890 value of the float number is greater than 32768.
892 static inline FT_Fixed FT_FixedFromFloat(double f)
894 return f * 0x10000;
898 This function builds an FT_Fixed from a FIXED. It simply put f.value
899 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
901 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
903 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
906 static BOOL is_hinting_enabled(void)
908 static int enabled = -1;
910 if (enabled == -1)
912 /* Use the >= 2.2.0 function if available */
913 if (pFT_Get_TrueType_Engine_Type)
915 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
916 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
918 #ifdef FT_DRIVER_HAS_HINTER
919 else
921 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
922 FT_Module mod = pFT_Get_Module(library, "truetype");
923 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
925 #endif
926 else enabled = FALSE;
927 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
929 return enabled;
932 static BOOL is_subpixel_rendering_enabled( void )
934 #ifdef HAVE_FREETYPE_FTLCDFIL_H
935 static int enabled = -1;
936 if (enabled == -1)
938 enabled = (pFT_Library_SetLcdFilter &&
939 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
940 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
942 return enabled;
943 #else
944 return FALSE;
945 #endif
949 static const struct list *get_face_list_from_family(const Family *family)
951 if (!list_empty(&family->faces))
952 return &family->faces;
953 else
954 return family->replacement;
957 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
959 Family *family;
960 Face *face;
961 const WCHAR *file;
963 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
965 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
967 const struct list *face_list;
968 if(face_name && strcmpiW(face_name, family->FamilyName))
969 continue;
970 face_list = get_face_list_from_family(family);
971 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
973 if (!face->file)
974 continue;
975 file = strrchrW(face->file, '/');
976 if(!file)
977 file = face->file;
978 else
979 file++;
980 if(strcmpiW(file, file_name)) continue;
981 face->refcount++;
982 return face;
985 return NULL;
988 static Family *find_family_from_name(const WCHAR *name)
990 Family *family;
992 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
994 if(!strcmpiW(family->FamilyName, name))
995 return family;
998 return NULL;
1001 static Family *find_family_from_any_name(const WCHAR *name)
1003 Family *family;
1005 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1007 if(!strcmpiW(family->FamilyName, name))
1008 return family;
1009 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1010 return family;
1013 return NULL;
1016 static void DumpSubstList(void)
1018 FontSubst *psub;
1020 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1022 if(psub->from.charset != -1 || psub->to.charset != -1)
1023 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1024 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1025 else
1026 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1027 debugstr_w(psub->to.name));
1029 return;
1032 static LPWSTR strdupW(LPCWSTR p)
1034 LPWSTR ret;
1035 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1036 ret = HeapAlloc(GetProcessHeap(), 0, len);
1037 memcpy(ret, p, len);
1038 return ret;
1041 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1042 INT from_charset)
1044 FontSubst *element;
1046 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1048 if(!strcmpiW(element->from.name, from_name) &&
1049 (element->from.charset == from_charset ||
1050 element->from.charset == -1))
1051 return element;
1054 return NULL;
1057 #define ADD_FONT_SUBST_FORCE 1
1059 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1061 FontSubst *from_exist, *to_exist;
1063 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1065 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1067 list_remove(&from_exist->entry);
1068 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1069 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1070 HeapFree(GetProcessHeap(), 0, from_exist);
1071 from_exist = NULL;
1074 if(!from_exist)
1076 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1078 if(to_exist)
1080 HeapFree(GetProcessHeap(), 0, subst->to.name);
1081 subst->to.name = strdupW(to_exist->to.name);
1084 list_add_tail(subst_list, &subst->entry);
1086 return TRUE;
1089 HeapFree(GetProcessHeap(), 0, subst->from.name);
1090 HeapFree(GetProcessHeap(), 0, subst->to.name);
1091 HeapFree(GetProcessHeap(), 0, subst);
1092 return FALSE;
1095 static WCHAR *towstr(UINT cp, const char *str)
1097 int len;
1098 WCHAR *wstr;
1100 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1101 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1102 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1103 return wstr;
1106 static char *strWtoA(UINT cp, const WCHAR *str)
1108 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1109 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1110 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1111 return ret;
1114 static void split_subst_info(NameCs *nc, LPSTR str)
1116 CHAR *p = strrchr(str, ',');
1118 nc->charset = -1;
1119 if(p && *(p+1)) {
1120 nc->charset = strtol(p+1, NULL, 10);
1121 *p = '\0';
1123 nc->name = towstr(CP_ACP, str);
1126 static void LoadSubstList(void)
1128 FontSubst *psub;
1129 HKEY hkey;
1130 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1131 LPSTR value;
1132 LPVOID data;
1134 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1135 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1136 &hkey) == ERROR_SUCCESS) {
1138 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1139 &valuelen, &datalen, NULL, NULL);
1141 valuelen++; /* returned value doesn't include room for '\0' */
1142 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1143 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1145 dlen = datalen;
1146 vlen = valuelen;
1147 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1148 &dlen) == ERROR_SUCCESS) {
1149 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1151 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1152 split_subst_info(&psub->from, value);
1153 split_subst_info(&psub->to, data);
1155 /* Win 2000 doesn't allow mapping between different charsets
1156 or mapping of DEFAULT_CHARSET */
1157 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1158 psub->to.charset == DEFAULT_CHARSET) {
1159 HeapFree(GetProcessHeap(), 0, psub->to.name);
1160 HeapFree(GetProcessHeap(), 0, psub->from.name);
1161 HeapFree(GetProcessHeap(), 0, psub);
1162 } else {
1163 add_font_subst(&font_subst_list, psub, 0);
1165 /* reset dlen and vlen */
1166 dlen = datalen;
1167 vlen = valuelen;
1169 HeapFree(GetProcessHeap(), 0, data);
1170 HeapFree(GetProcessHeap(), 0, value);
1171 RegCloseKey(hkey);
1176 /*****************************************************************
1177 * get_name_table_entry
1179 * Supply the platform, encoding, language and name ids in req
1180 * and if the name exists the function will fill in the string
1181 * and string_len members. The string is owned by FreeType so
1182 * don't free it. Returns TRUE if the name is found else FALSE.
1184 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1186 FT_SfntName name;
1187 FT_UInt num_names, name_index;
1189 if(FT_IS_SFNT(ft_face))
1191 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1193 for(name_index = 0; name_index < num_names; name_index++)
1195 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1197 if((name.platform_id == req->platform_id) &&
1198 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1199 (name.language_id == req->language_id) &&
1200 (name.name_id == req->name_id))
1202 req->string = name.string;
1203 req->string_len = name.string_len;
1204 return TRUE;
1209 req->string = NULL;
1210 req->string_len = 0;
1211 return FALSE;
1214 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1216 WCHAR *ret = NULL;
1217 FT_SfntName name;
1219 name.platform_id = TT_PLATFORM_MICROSOFT;
1220 name.language_id = language_id;
1221 name.name_id = name_id;
1223 if(get_name_table_entry(ft_face, &name))
1225 FT_UInt i;
1227 /* String is not nul terminated and string_len is a byte length. */
1228 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1229 for(i = 0; i < name.string_len / 2; i++)
1231 WORD *tmp = (WORD *)&name.string[i * 2];
1232 ret[i] = GET_BE_WORD(*tmp);
1234 ret[i] = 0;
1235 TRACE("Got localised name %s\n", debugstr_w(ret));
1238 return ret;
1241 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1243 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1244 if (f1->scalable) return TRUE;
1245 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1246 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1249 static void release_family( Family *family )
1251 if (--family->refcount) return;
1252 assert( list_empty( &family->faces ));
1253 list_remove( &family->entry );
1254 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1255 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1256 HeapFree( GetProcessHeap(), 0, family );
1259 static void release_face( Face *face )
1261 if (--face->refcount) return;
1262 if (face->family)
1264 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1265 list_remove( &face->entry );
1266 release_family( face->family );
1268 HeapFree( GetProcessHeap(), 0, face->file );
1269 HeapFree( GetProcessHeap(), 0, face->StyleName );
1270 HeapFree( GetProcessHeap(), 0, face->FullName );
1271 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1272 HeapFree( GetProcessHeap(), 0, face );
1275 static inline int style_order(const Face *face)
1277 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1279 case NTM_REGULAR:
1280 return 0;
1281 case NTM_BOLD:
1282 return 1;
1283 case NTM_ITALIC:
1284 return 2;
1285 case NTM_BOLD | NTM_ITALIC:
1286 return 3;
1287 default:
1288 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1289 debugstr_w(face->family->FamilyName),
1290 debugstr_w(face->StyleName),
1291 face->ntmFlags);
1292 return 9999;
1296 static BOOL insert_face_in_family_list( Face *face, Family *family )
1298 Face *cursor;
1300 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1302 if (faces_equal( face, cursor ))
1304 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1305 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1306 cursor->font_version, face->font_version);
1308 if (face->file && face->dev == cursor->dev && face->ino == cursor->ino)
1310 cursor->refcount++;
1311 TRACE("Font %s already in list, refcount now %d\n",
1312 debugstr_w(face->file), cursor->refcount);
1313 return FALSE;
1315 if (face->font_version <= cursor->font_version)
1317 TRACE("Original font %s is newer so skipping %s\n",
1318 debugstr_w(cursor->file), debugstr_w(face->file));
1319 return FALSE;
1321 else
1323 TRACE("Replacing original %s with %s\n",
1324 debugstr_w(cursor->file), debugstr_w(face->file));
1325 list_add_before( &cursor->entry, &face->entry );
1326 face->family = family;
1327 family->refcount++;
1328 face->refcount++;
1329 release_face( cursor );
1330 return TRUE;
1333 else
1334 TRACE("Adding new %s\n", debugstr_w(face->file));
1336 if (style_order( face ) < style_order( cursor )) break;
1339 list_add_before( &cursor->entry, &face->entry );
1340 face->family = family;
1341 family->refcount++;
1342 face->refcount++;
1343 return TRUE;
1346 /****************************************************************
1347 * NB This function stores the ptrs to the strings to save copying.
1348 * Don't free them after calling.
1350 static Family *create_family( WCHAR *name, WCHAR *english_name )
1352 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1353 family->refcount = 1;
1354 family->FamilyName = name;
1355 family->EnglishName = english_name;
1356 list_init( &family->faces );
1357 family->replacement = &family->faces;
1358 list_add_tail( &font_list, &family->entry );
1360 return family;
1363 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1365 DWORD type, size = sizeof(DWORD);
1367 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1368 type != REG_DWORD || size != sizeof(DWORD))
1370 *data = 0;
1371 return ERROR_BAD_CONFIGURATION;
1373 return ERROR_SUCCESS;
1376 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1378 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1381 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1383 DWORD needed, strike_index = 0;
1384 HKEY hkey_strike;
1386 /* If we have a File Name key then this is a real font, not just the parent
1387 key of a bunch of non-scalable strikes */
1388 needed = buffer_size;
1389 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1391 Face *face;
1392 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1393 face->cached_enum_data = NULL;
1394 face->family = NULL;
1396 face->refcount = 1;
1397 face->file = strdupW( buffer );
1398 face->StyleName = strdupW(face_name);
1400 needed = buffer_size;
1401 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1402 face->FullName = strdupW( buffer );
1403 else
1404 face->FullName = NULL;
1406 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1407 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1408 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1409 reg_load_dword(hkey_face, face_flags_value, (DWORD*)&face->flags);
1411 needed = sizeof(face->fs);
1412 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1414 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1416 face->scalable = TRUE;
1417 memset(&face->size, 0, sizeof(face->size));
1419 else
1421 face->scalable = FALSE;
1422 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1423 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1424 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1425 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1426 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1428 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1429 face->size.height, face->size.width, face->size.size >> 6,
1430 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1433 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1434 face->fs.fsCsb[0], face->fs.fsCsb[1],
1435 face->fs.fsUsb[0], face->fs.fsUsb[1],
1436 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1438 if (insert_face_in_family_list(face, family))
1439 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1441 release_face( face );
1444 /* load bitmap strikes */
1446 needed = buffer_size;
1447 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1449 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1451 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1452 RegCloseKey(hkey_strike);
1454 needed = buffer_size;
1458 static void load_font_list_from_cache(HKEY hkey_font_cache)
1460 DWORD size, family_index = 0;
1461 Family *family;
1462 HKEY hkey_family;
1463 WCHAR buffer[4096];
1465 size = sizeof(buffer);
1466 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1468 WCHAR *english_family = NULL;
1469 WCHAR *family_name = strdupW( buffer );
1470 DWORD face_index = 0;
1472 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1473 TRACE("opened family key %s\n", debugstr_w(family_name));
1474 size = sizeof(buffer);
1475 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1476 english_family = strdupW( buffer );
1478 family = create_family(family_name, english_family);
1480 if(english_family)
1482 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1483 subst->from.name = strdupW(english_family);
1484 subst->from.charset = -1;
1485 subst->to.name = strdupW(family_name);
1486 subst->to.charset = -1;
1487 add_font_subst(&font_subst_list, subst, 0);
1490 size = sizeof(buffer);
1491 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1493 WCHAR *face_name = strdupW( buffer );
1494 HKEY hkey_face;
1496 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1498 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1499 RegCloseKey(hkey_face);
1501 HeapFree( GetProcessHeap(), 0, face_name );
1502 size = sizeof(buffer);
1504 RegCloseKey(hkey_family);
1505 release_family( family );
1506 size = sizeof(buffer);
1510 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1512 LONG ret;
1513 HKEY hkey_wine_fonts;
1515 /* We don't want to create the fonts key as volatile, so open this first */
1516 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1517 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1518 if(ret != ERROR_SUCCESS)
1520 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1521 return ret;
1524 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1525 KEY_ALL_ACCESS, NULL, hkey, disposition);
1526 RegCloseKey(hkey_wine_fonts);
1527 return ret;
1530 static void add_face_to_cache(Face *face)
1532 HKEY hkey_family, hkey_face;
1533 WCHAR *face_key_name;
1535 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1536 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1537 if(face->family->EnglishName)
1538 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1539 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1541 if(face->scalable)
1542 face_key_name = face->StyleName;
1543 else
1545 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1546 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1547 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1549 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1550 &hkey_face, NULL);
1551 if(!face->scalable)
1552 HeapFree(GetProcessHeap(), 0, face_key_name);
1554 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1555 (strlenW(face->file) + 1) * sizeof(WCHAR));
1556 if (face->FullName)
1557 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1558 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1560 reg_save_dword(hkey_face, face_index_value, face->face_index);
1561 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1562 reg_save_dword(hkey_face, face_version_value, face->font_version);
1563 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1565 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1567 if(!face->scalable)
1569 reg_save_dword(hkey_face, face_height_value, face->size.height);
1570 reg_save_dword(hkey_face, face_width_value, face->size.width);
1571 reg_save_dword(hkey_face, face_size_value, face->size.size);
1572 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1573 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1574 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1576 RegCloseKey(hkey_face);
1577 RegCloseKey(hkey_family);
1580 static void remove_face_from_cache( Face *face )
1582 HKEY hkey_family;
1584 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1586 if (face->scalable)
1588 RegDeleteKeyW( hkey_family, face->StyleName );
1590 else
1592 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1593 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1594 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1595 RegDeleteKeyW( hkey_family, face_key_name );
1596 HeapFree(GetProcessHeap(), 0, face_key_name);
1598 RegCloseKey(hkey_family);
1601 static WCHAR *prepend_at(WCHAR *family)
1603 WCHAR *str;
1605 if (!family)
1606 return NULL;
1608 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1609 str[0] = '@';
1610 strcpyW(str + 1, family);
1611 HeapFree(GetProcessHeap(), 0, family);
1612 return str;
1615 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1617 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1618 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1620 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1621 if (!*name)
1623 *name = *english;
1624 *english = NULL;
1626 else if (!strcmpiW( *name, *english ))
1628 HeapFree( GetProcessHeap(), 0, *english );
1629 *english = NULL;
1632 if (vertical)
1634 *name = prepend_at( *name );
1635 *english = prepend_at( *english );
1639 static Family *get_family( FT_Face ft_face, BOOL vertical )
1641 Family *family;
1642 WCHAR *name, *english_name;
1644 get_family_names( ft_face, &name, &english_name, vertical );
1646 family = find_family_from_name( name );
1648 if (!family)
1650 family = create_family( name, english_name );
1651 if (english_name)
1653 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1654 subst->from.name = strdupW( english_name );
1655 subst->from.charset = -1;
1656 subst->to.name = strdupW( name );
1657 subst->to.charset = -1;
1658 add_font_subst( &font_subst_list, subst, 0 );
1661 else
1663 HeapFree( GetProcessHeap(), 0, name );
1664 HeapFree( GetProcessHeap(), 0, english_name );
1665 family->refcount++;
1668 return family;
1671 static inline FT_Fixed get_font_version( FT_Face ft_face )
1673 FT_Fixed version = 0;
1674 TT_Header *header;
1676 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1677 if (header) version = header->Font_Revision;
1679 return version;
1682 static inline DWORD get_ntm_flags( FT_Face ft_face )
1684 DWORD flags = 0;
1685 FT_ULong table_size = 0;
1687 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1688 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1689 if (flags == 0) flags = NTM_REGULAR;
1691 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1692 flags |= NTM_PS_OPENTYPE;
1694 return flags;
1697 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1699 int internal_leading = 0;
1700 FT_WinFNT_HeaderRec winfnt_header;
1702 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1703 internal_leading = winfnt_header.internal_leading;
1705 return internal_leading;
1708 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1710 TT_OS2 *os2;
1711 FT_UInt dummy;
1712 CHARSETINFO csi;
1713 FT_WinFNT_HeaderRec winfnt_header;
1714 int i;
1716 memset( fs, 0, sizeof(*fs) );
1718 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1719 if (os2)
1721 fs->fsUsb[0] = os2->ulUnicodeRange1;
1722 fs->fsUsb[1] = os2->ulUnicodeRange2;
1723 fs->fsUsb[2] = os2->ulUnicodeRange3;
1724 fs->fsUsb[3] = os2->ulUnicodeRange4;
1726 if (os2->version == 0)
1728 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1729 fs->fsCsb[0] = FS_LATIN1;
1730 else
1731 fs->fsCsb[0] = FS_SYMBOL;
1733 else
1735 fs->fsCsb[0] = os2->ulCodePageRange1;
1736 fs->fsCsb[1] = os2->ulCodePageRange2;
1739 else
1741 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1743 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1744 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1745 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1746 *fs = csi.fs;
1750 if (fs->fsCsb[0] == 0)
1752 /* let's see if we can find any interesting cmaps */
1753 for (i = 0; i < ft_face->num_charmaps; i++)
1755 switch (ft_face->charmaps[i]->encoding)
1757 case FT_ENCODING_UNICODE:
1758 case FT_ENCODING_APPLE_ROMAN:
1759 fs->fsCsb[0] |= FS_LATIN1;
1760 break;
1761 case FT_ENCODING_MS_SYMBOL:
1762 fs->fsCsb[0] |= FS_SYMBOL;
1763 break;
1764 default:
1765 break;
1771 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1772 DWORD flags )
1774 struct stat st;
1775 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1776 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1778 face->refcount = 1;
1779 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1780 if (!face->StyleName)
1781 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1782 if (!face->StyleName)
1784 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1787 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1788 if (!face->FullName)
1789 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1790 if (flags & ADDFONT_VERTICAL_FONT)
1791 face->FullName = prepend_at( face->FullName );
1793 face->dev = 0;
1794 face->ino = 0;
1795 if (file)
1797 face->file = towstr( CP_UNIXCP, file );
1798 face->font_data_ptr = NULL;
1799 face->font_data_size = 0;
1800 if (!stat( file, &st ))
1802 face->dev = st.st_dev;
1803 face->ino = st.st_ino;
1806 else
1808 face->file = NULL;
1809 face->font_data_ptr = font_data_ptr;
1810 face->font_data_size = font_data_size;
1813 face->face_index = face_index;
1814 get_fontsig( ft_face, &face->fs );
1815 face->ntmFlags = get_ntm_flags( ft_face );
1816 face->font_version = get_font_version( ft_face );
1818 if (FT_IS_SCALABLE( ft_face ))
1820 memset( &face->size, 0, sizeof(face->size) );
1821 face->scalable = TRUE;
1823 else
1825 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1826 size->height, size->width, size->size >> 6,
1827 size->x_ppem >> 6, size->y_ppem >> 6);
1828 face->size.height = size->height;
1829 face->size.width = size->width;
1830 face->size.size = size->size;
1831 face->size.x_ppem = size->x_ppem;
1832 face->size.y_ppem = size->y_ppem;
1833 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1834 face->scalable = FALSE;
1837 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1838 face->flags = flags;
1839 face->family = NULL;
1840 face->cached_enum_data = NULL;
1842 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1843 face->fs.fsCsb[0], face->fs.fsCsb[1],
1844 face->fs.fsUsb[0], face->fs.fsUsb[1],
1845 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1847 return face;
1850 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1851 FT_Long face_index, DWORD flags )
1853 Face *face;
1854 Family *family;
1856 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
1857 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
1858 if (insert_face_in_family_list( face, family ))
1860 if (flags & ADDFONT_ADD_TO_CACHE)
1861 add_face_to_cache( face );
1863 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1864 debugstr_w(face->StyleName));
1866 release_face( face );
1867 release_family( family );
1870 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1871 FT_Long face_index, BOOL allow_bitmap )
1873 FT_Error err;
1874 TT_OS2 *pOS2;
1875 FT_Face ft_face;
1877 if (file)
1879 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1880 err = pFT_New_Face(library, file, face_index, &ft_face);
1882 else
1884 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1885 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1888 if (err != 0)
1890 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1891 return NULL;
1894 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1895 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1897 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1898 goto fail;
1901 if (!FT_IS_SFNT( ft_face ))
1903 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1905 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1906 goto fail;
1909 else
1911 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1912 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1913 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1915 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1916 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1917 goto fail;
1920 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1921 we don't want to load these. */
1922 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1924 FT_ULong len = 0;
1926 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1928 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1929 goto fail;
1934 if (!ft_face->family_name || !ft_face->style_name)
1936 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1937 goto fail;
1940 return ft_face;
1941 fail:
1942 pFT_Done_Face( ft_face );
1943 return NULL;
1946 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1948 FT_Face ft_face;
1949 FT_Long face_index = 0, num_faces;
1950 INT ret = 0;
1952 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1953 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1955 #ifdef HAVE_CARBON_CARBON_H
1956 if(file)
1958 char **mac_list = expand_mac_font(file);
1959 if(mac_list)
1961 BOOL had_one = FALSE;
1962 char **cursor;
1963 for(cursor = mac_list; *cursor; cursor++)
1965 had_one = TRUE;
1966 AddFontToList(*cursor, NULL, 0, flags);
1967 HeapFree(GetProcessHeap(), 0, *cursor);
1969 HeapFree(GetProcessHeap(), 0, mac_list);
1970 if(had_one)
1971 return 1;
1974 #endif /* HAVE_CARBON_CARBON_H */
1976 do {
1977 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
1978 if (!ft_face) return 0;
1980 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1982 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1983 pFT_Done_Face(ft_face);
1984 return 0;
1987 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
1988 ++ret;
1990 if (FT_HAS_VERTICAL(ft_face))
1992 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
1993 flags | ADDFONT_VERTICAL_FONT);
1994 ++ret;
1997 num_faces = ft_face->num_faces;
1998 pFT_Done_Face(ft_face);
1999 } while(num_faces > ++face_index);
2000 return ret;
2003 static int remove_font_resource( const char *file, DWORD flags )
2005 Family *family, *family_next;
2006 Face *face, *face_next;
2007 struct stat st;
2008 int count = 0;
2010 if (stat( file, &st ) == -1) return 0;
2011 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2013 family->refcount++;
2014 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2016 if (!face->file) continue;
2017 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2018 if (st.st_dev == face->dev && st.st_ino == face->ino)
2020 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2021 release_face( face );
2022 count++;
2025 release_family( family );
2027 return count;
2030 static void DumpFontList(void)
2032 Family *family;
2033 Face *face;
2035 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2036 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2037 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2038 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2039 if(!face->scalable)
2040 TRACE(" %d", face->size.height);
2041 TRACE("\n");
2044 return;
2047 /***********************************************************
2048 * The replacement list is a way to map an entire font
2049 * family onto another family. For example adding
2051 * [HKCU\Software\Wine\Fonts\Replacements]
2052 * "Wingdings"="Winedings"
2054 * would enumerate the Winedings font both as Winedings and
2055 * Wingdings. However if a real Wingdings font is present the
2056 * replacement does not take place.
2059 static void LoadReplaceList(void)
2061 HKEY hkey;
2062 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2063 LPWSTR value;
2064 LPVOID data;
2066 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2067 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2069 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2070 &valuelen, &datalen, NULL, NULL);
2072 valuelen++; /* returned value doesn't include room for '\0' */
2073 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2074 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2076 dlen = datalen;
2077 vlen = valuelen;
2078 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2079 &dlen) == ERROR_SUCCESS) {
2080 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2081 /* "NewName"="Oldname" */
2082 if(!find_family_from_any_name(value))
2084 Family * const family = find_family_from_any_name(data);
2085 if (family != NULL)
2087 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2088 if (new_family != NULL)
2090 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2091 new_family->FamilyName = strdupW(value);
2092 new_family->EnglishName = NULL;
2093 list_init(&new_family->faces);
2094 new_family->replacement = &family->faces;
2095 list_add_tail(&font_list, &new_family->entry);
2098 else
2100 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2103 else
2105 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2107 /* reset dlen and vlen */
2108 dlen = datalen;
2109 vlen = valuelen;
2111 HeapFree(GetProcessHeap(), 0, data);
2112 HeapFree(GetProcessHeap(), 0, value);
2113 RegCloseKey(hkey);
2117 static const WCHAR *font_links_list[] =
2119 Lucida_Sans_Unicode,
2120 Microsoft_Sans_Serif,
2121 Tahoma
2124 static const struct font_links_defaults_list
2126 /* Keyed off substitution for "MS Shell Dlg" */
2127 const WCHAR *shelldlg;
2128 /* Maximum of four substitutes, plus terminating NULL pointer */
2129 const WCHAR *substitutes[5];
2130 } font_links_defaults_list[] =
2132 /* Non East-Asian */
2133 { Tahoma, /* FIXME unverified ordering */
2134 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2136 /* Below lists are courtesy of
2137 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2139 /* Japanese */
2140 { MS_UI_Gothic,
2141 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2143 /* Chinese Simplified */
2144 { SimSun,
2145 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2147 /* Korean */
2148 { Gulim,
2149 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2151 /* Chinese Traditional */
2152 { PMingLiU,
2153 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2158 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2160 SYSTEM_LINKS *font_link;
2162 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2164 if(!strcmpiW(font_link->font_name, name))
2165 return font_link;
2168 return NULL;
2171 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2173 const WCHAR *value;
2174 int i;
2175 FontSubst *psub;
2176 Family *family;
2177 Face *face;
2178 const WCHAR *file;
2180 if (values)
2182 SYSTEM_LINKS *font_link;
2184 psub = get_font_subst(&font_subst_list, name, -1);
2185 /* Don't store fonts that are only substitutes for other fonts */
2186 if(psub)
2188 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2189 return;
2192 font_link = find_font_link(name);
2193 if (font_link == NULL)
2195 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2196 font_link->font_name = strdupW(name);
2197 list_init(&font_link->links);
2198 list_add_tail(&system_links, &font_link->entry);
2201 memset(&font_link->fs, 0, sizeof font_link->fs);
2202 for (i = 0; values[i] != NULL; i++)
2204 const struct list *face_list;
2205 CHILD_FONT *child_font;
2207 value = values[i];
2208 if (!strcmpiW(name,value))
2209 continue;
2210 psub = get_font_subst(&font_subst_list, value, -1);
2211 if(psub)
2212 value = psub->to.name;
2213 family = find_family_from_name(value);
2214 if (!family)
2215 continue;
2216 file = NULL;
2217 /* Use first extant filename for this Family */
2218 face_list = get_face_list_from_family(family);
2219 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2221 if (!face->file)
2222 continue;
2223 file = strrchrW(face->file, '/');
2224 if (!file)
2225 file = face->file;
2226 else
2227 file++;
2228 break;
2230 if (!file)
2231 continue;
2232 face = find_face_from_filename(file, value);
2233 if(!face)
2235 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2236 continue;
2239 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2240 child_font->face = face;
2241 child_font->font = NULL;
2242 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2243 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2244 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2245 child_font->face->face_index);
2246 list_add_tail(&font_link->links, &child_font->entry);
2248 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2254 /*************************************************************
2255 * init_system_links
2257 static BOOL init_system_links(void)
2259 HKEY hkey;
2260 BOOL ret = FALSE;
2261 DWORD type, max_val, max_data, val_len, data_len, index;
2262 WCHAR *value, *data;
2263 WCHAR *entry, *next;
2264 SYSTEM_LINKS *font_link, *system_font_link;
2265 CHILD_FONT *child_font;
2266 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2267 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2268 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2269 Face *face;
2270 FontSubst *psub;
2271 UINT i, j;
2273 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2275 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2276 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2277 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2278 val_len = max_val + 1;
2279 data_len = max_data;
2280 index = 0;
2281 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2283 psub = get_font_subst(&font_subst_list, value, -1);
2284 /* Don't store fonts that are only substitutes for other fonts */
2285 if(psub)
2287 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2288 goto next;
2290 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2291 font_link->font_name = strdupW(value);
2292 memset(&font_link->fs, 0, sizeof font_link->fs);
2293 list_init(&font_link->links);
2294 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2296 WCHAR *face_name;
2297 CHILD_FONT *child_font;
2299 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2301 next = entry + strlenW(entry) + 1;
2303 face_name = strchrW(entry, ',');
2304 if(face_name)
2306 *face_name++ = 0;
2307 while(isspaceW(*face_name))
2308 face_name++;
2310 psub = get_font_subst(&font_subst_list, face_name, -1);
2311 if(psub)
2312 face_name = psub->to.name;
2314 face = find_face_from_filename(entry, face_name);
2315 if(!face)
2317 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2318 continue;
2321 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2322 child_font->face = face;
2323 child_font->font = NULL;
2324 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2325 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2326 TRACE("Adding file %s index %ld\n",
2327 debugstr_w(child_font->face->file), child_font->face->face_index);
2328 list_add_tail(&font_link->links, &child_font->entry);
2330 list_add_tail(&system_links, &font_link->entry);
2331 next:
2332 val_len = max_val + 1;
2333 data_len = max_data;
2336 HeapFree(GetProcessHeap(), 0, value);
2337 HeapFree(GetProcessHeap(), 0, data);
2338 RegCloseKey(hkey);
2342 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2343 if (!psub) {
2344 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2345 goto skip_internal;
2348 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2350 const FontSubst *psub2;
2351 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2353 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2355 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2356 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2358 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2359 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2361 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2363 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2367 skip_internal:
2369 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2370 that Tahoma has */
2372 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2373 system_font_link->font_name = strdupW(System);
2374 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2375 list_init(&system_font_link->links);
2377 face = find_face_from_filename(tahoma_ttf, Tahoma);
2378 if(face)
2380 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2381 child_font->face = face;
2382 child_font->font = NULL;
2383 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2384 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2385 TRACE("Found Tahoma in %s index %ld\n",
2386 debugstr_w(child_font->face->file), child_font->face->face_index);
2387 list_add_tail(&system_font_link->links, &child_font->entry);
2389 font_link = find_font_link(Tahoma);
2390 if (font_link != NULL)
2392 CHILD_FONT *font_link_entry;
2393 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2395 CHILD_FONT *new_child;
2396 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2397 new_child->face = font_link_entry->face;
2398 new_child->font = NULL;
2399 new_child->face->refcount++;
2400 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2401 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2402 list_add_tail(&system_font_link->links, &new_child->entry);
2405 list_add_tail(&system_links, &system_font_link->entry);
2406 return ret;
2409 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2411 DIR *dir;
2412 struct dirent *dent;
2413 char path[MAX_PATH];
2415 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2417 dir = opendir(dirname);
2418 if(!dir) {
2419 WARN("Can't open directory %s\n", debugstr_a(dirname));
2420 return FALSE;
2422 while((dent = readdir(dir)) != NULL) {
2423 struct stat statbuf;
2425 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2426 continue;
2428 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2430 sprintf(path, "%s/%s", dirname, dent->d_name);
2432 if(stat(path, &statbuf) == -1)
2434 WARN("Can't stat %s\n", debugstr_a(path));
2435 continue;
2437 if(S_ISDIR(statbuf.st_mode))
2438 ReadFontDir(path, external_fonts);
2439 else
2441 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2442 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2443 AddFontToList(path, NULL, 0, addfont_flags);
2446 closedir(dir);
2447 return TRUE;
2450 #ifdef SONAME_LIBFONTCONFIG
2452 static BOOL fontconfig_enabled;
2454 static UINT parse_aa_pattern( FcPattern *pattern )
2456 FcBool antialias;
2457 int rgba;
2458 UINT aa_flags = 0;
2460 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2461 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2463 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2465 switch (rgba)
2467 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2468 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2469 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2470 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2471 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2474 return aa_flags;
2477 static void init_fontconfig(void)
2479 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2481 if (!fc_handle)
2483 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2484 return;
2487 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2488 LOAD_FUNCPTR(FcConfigSubstitute);
2489 LOAD_FUNCPTR(FcFontList);
2490 LOAD_FUNCPTR(FcFontSetDestroy);
2491 LOAD_FUNCPTR(FcInit);
2492 LOAD_FUNCPTR(FcObjectSetAdd);
2493 LOAD_FUNCPTR(FcObjectSetCreate);
2494 LOAD_FUNCPTR(FcObjectSetDestroy);
2495 LOAD_FUNCPTR(FcPatternCreate);
2496 LOAD_FUNCPTR(FcPatternDestroy);
2497 LOAD_FUNCPTR(FcPatternGetBool);
2498 LOAD_FUNCPTR(FcPatternGetInteger);
2499 LOAD_FUNCPTR(FcPatternGetString);
2500 #undef LOAD_FUNCPTR
2502 if (pFcInit())
2504 FcPattern *pattern = pFcPatternCreate();
2505 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2506 default_aa_flags = parse_aa_pattern( pattern );
2507 pFcPatternDestroy( pattern );
2508 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2509 fontconfig_enabled = TRUE;
2513 static void load_fontconfig_fonts(void)
2515 FcPattern *pat;
2516 FcObjectSet *os;
2517 FcFontSet *fontset;
2518 int i, len;
2519 char *file;
2520 const char *ext;
2522 if (!fontconfig_enabled) return;
2524 pat = pFcPatternCreate();
2525 os = pFcObjectSetCreate();
2526 pFcObjectSetAdd(os, FC_FILE);
2527 pFcObjectSetAdd(os, FC_SCALABLE);
2528 pFcObjectSetAdd(os, FC_ANTIALIAS);
2529 pFcObjectSetAdd(os, FC_RGBA);
2530 fontset = pFcFontList(NULL, pat, os);
2531 if(!fontset) return;
2532 for(i = 0; i < fontset->nfont; i++) {
2533 FcBool scalable;
2534 DWORD aa_flags;
2536 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2537 continue;
2539 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2541 /* We're just interested in OT/TT fonts for now, so this hack just
2542 picks up the scalable fonts without extensions .pf[ab] to save time
2543 loading every other font */
2545 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2547 TRACE("not scalable\n");
2548 continue;
2551 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2552 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2554 len = strlen( file );
2555 if(len < 4) continue;
2556 ext = &file[ len - 3 ];
2557 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2558 AddFontToList(file, NULL, 0,
2559 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2561 pFcFontSetDestroy(fontset);
2562 pFcObjectSetDestroy(os);
2563 pFcPatternDestroy(pat);
2566 #elif defined(HAVE_CARBON_CARBON_H)
2568 static void load_mac_font_callback(const void *value, void *context)
2570 CFStringRef pathStr = value;
2571 CFIndex len;
2572 char* path;
2574 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2575 path = HeapAlloc(GetProcessHeap(), 0, len);
2576 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2578 TRACE("font file %s\n", path);
2579 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2581 HeapFree(GetProcessHeap(), 0, path);
2584 static void load_mac_fonts(void)
2586 CFStringRef removeDupesKey;
2587 CFBooleanRef removeDupesValue;
2588 CFDictionaryRef options;
2589 CTFontCollectionRef col;
2590 CFArrayRef descs;
2591 CFMutableSetRef paths;
2592 CFIndex i;
2594 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2595 removeDupesValue = kCFBooleanTrue;
2596 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2597 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2598 col = CTFontCollectionCreateFromAvailableFonts(options);
2599 if (options) CFRelease(options);
2600 if (!col)
2602 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2603 return;
2606 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2607 CFRelease(col);
2608 if (!descs)
2610 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2611 return;
2614 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2615 if (!paths)
2617 WARN("CFSetCreateMutable failed\n");
2618 CFRelease(descs);
2619 return;
2622 for (i = 0; i < CFArrayGetCount(descs); i++)
2624 CTFontDescriptorRef desc;
2625 CTFontRef font;
2626 ATSFontRef atsFont;
2627 OSStatus status;
2628 FSRef fsref;
2629 CFURLRef url;
2630 CFStringRef ext;
2631 CFStringRef path;
2633 desc = CFArrayGetValueAtIndex(descs, i);
2635 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2636 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2637 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2638 if (!font) continue;
2640 atsFont = CTFontGetPlatformFont(font, NULL);
2641 if (!atsFont)
2643 CFRelease(font);
2644 continue;
2647 status = ATSFontGetFileReference(atsFont, &fsref);
2648 CFRelease(font);
2649 if (status != noErr) continue;
2651 url = CFURLCreateFromFSRef(NULL, &fsref);
2652 if (!url) continue;
2654 ext = CFURLCopyPathExtension(url);
2655 if (ext)
2657 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2658 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2659 CFRelease(ext);
2660 if (skip)
2662 CFRelease(url);
2663 continue;
2667 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2668 CFRelease(url);
2669 if (!path) continue;
2671 CFSetAddValue(paths, path);
2672 CFRelease(path);
2675 CFRelease(descs);
2677 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2678 CFRelease(paths);
2681 #endif
2683 static char *get_data_dir_path( LPCWSTR file )
2685 char *unix_name = NULL;
2686 const char *data_dir = wine_get_data_dir();
2688 if (!data_dir) data_dir = wine_get_build_dir();
2690 if (data_dir)
2692 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2694 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2695 strcpy(unix_name, data_dir);
2696 strcat(unix_name, "/fonts/");
2698 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2700 return unix_name;
2703 static BOOL load_font_from_data_dir(LPCWSTR file)
2705 BOOL ret = FALSE;
2706 char *unix_name = get_data_dir_path( file );
2708 if (unix_name)
2710 EnterCriticalSection( &freetype_cs );
2711 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2712 LeaveCriticalSection( &freetype_cs );
2713 HeapFree(GetProcessHeap(), 0, unix_name);
2715 return ret;
2718 static char *get_winfonts_dir_path(LPCWSTR file)
2720 static const WCHAR slashW[] = {'\\','\0'};
2721 WCHAR windowsdir[MAX_PATH];
2723 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2724 strcatW(windowsdir, fontsW);
2725 strcatW(windowsdir, slashW);
2726 strcatW(windowsdir, file);
2727 return wine_get_unix_file_name( windowsdir );
2730 static void load_system_fonts(void)
2732 HKEY hkey;
2733 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2734 const WCHAR * const *value;
2735 DWORD dlen, type;
2736 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2737 char *unixname;
2739 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2740 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2741 strcatW(windowsdir, fontsW);
2742 for(value = SystemFontValues; *value; value++) {
2743 dlen = sizeof(data);
2744 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2745 type == REG_SZ) {
2746 BOOL added = FALSE;
2748 sprintfW(pathW, fmtW, windowsdir, data);
2749 if((unixname = wine_get_unix_file_name(pathW))) {
2750 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2751 HeapFree(GetProcessHeap(), 0, unixname);
2753 if (!added)
2754 load_font_from_data_dir(data);
2757 RegCloseKey(hkey);
2761 /*************************************************************
2763 * This adds registry entries for any externally loaded fonts
2764 * (fonts from fontconfig or FontDirs). It also deletes entries
2765 * of no longer existing fonts.
2768 static void update_reg_entries(void)
2770 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2771 LPWSTR valueW;
2772 DWORD len;
2773 Family *family;
2774 Face *face;
2775 WCHAR *file, *path;
2776 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2778 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2779 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2780 ERR("Can't create Windows font reg key\n");
2781 goto end;
2784 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2785 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2786 ERR("Can't create Windows font reg key\n");
2787 goto end;
2790 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2791 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2792 ERR("Can't create external font reg key\n");
2793 goto end;
2796 /* enumerate the fonts and add external ones to the two keys */
2798 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2799 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2800 char *buffer;
2801 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
2803 if(face->FullName)
2805 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2806 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2807 strcpyW(valueW, face->FullName);
2809 else
2811 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2812 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2813 strcpyW(valueW, family->FamilyName);
2816 buffer = strWtoA( CP_UNIXCP, face->file );
2817 path = wine_get_dos_file_name( buffer );
2818 HeapFree( GetProcessHeap(), 0, buffer );
2820 if (path)
2821 file = path;
2822 else if ((file = strrchrW(face->file, '/')))
2823 file++;
2824 else
2825 file = face->file;
2827 len = strlenW(file) + 1;
2828 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2829 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2830 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2832 HeapFree(GetProcessHeap(), 0, path);
2833 HeapFree(GetProcessHeap(), 0, valueW);
2836 end:
2837 if(external_key) RegCloseKey(external_key);
2838 if(win9x_key) RegCloseKey(win9x_key);
2839 if(winnt_key) RegCloseKey(winnt_key);
2840 return;
2843 static void delete_external_font_keys(void)
2845 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2846 DWORD dlen, vlen, datalen, valuelen, i, type;
2847 LPWSTR valueW;
2848 LPVOID data;
2850 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2851 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2852 ERR("Can't create Windows font reg key\n");
2853 goto end;
2856 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2857 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2858 ERR("Can't create Windows font reg key\n");
2859 goto end;
2862 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2863 ERR("Can't create external font reg key\n");
2864 goto end;
2867 /* Delete all external fonts added last time */
2869 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2870 &valuelen, &datalen, NULL, NULL);
2871 valuelen++; /* returned value doesn't include room for '\0' */
2872 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2873 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2875 dlen = datalen * sizeof(WCHAR);
2876 vlen = valuelen;
2877 i = 0;
2878 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2879 &dlen) == ERROR_SUCCESS) {
2881 RegDeleteValueW(winnt_key, valueW);
2882 RegDeleteValueW(win9x_key, valueW);
2883 /* reset dlen and vlen */
2884 dlen = datalen;
2885 vlen = valuelen;
2887 HeapFree(GetProcessHeap(), 0, data);
2888 HeapFree(GetProcessHeap(), 0, valueW);
2890 /* Delete the old external fonts key */
2891 RegCloseKey(external_key);
2892 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2894 end:
2895 if(win9x_key) RegCloseKey(win9x_key);
2896 if(winnt_key) RegCloseKey(winnt_key);
2899 /*************************************************************
2900 * WineEngAddFontResourceEx
2903 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2905 INT ret = 0;
2907 GDI_CheckNotLock();
2909 if (ft_handle) /* do it only if we have freetype up and running */
2911 char *unixname;
2913 EnterCriticalSection( &freetype_cs );
2915 if((unixname = wine_get_unix_file_name(file)))
2917 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
2919 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2920 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2921 HeapFree(GetProcessHeap(), 0, unixname);
2923 if (!ret && !strchrW(file, '\\')) {
2924 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2925 if ((unixname = get_winfonts_dir_path( file )))
2927 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2928 HeapFree(GetProcessHeap(), 0, unixname);
2930 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
2931 if (!ret && (unixname = get_data_dir_path( file )))
2933 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2934 HeapFree(GetProcessHeap(), 0, unixname);
2938 LeaveCriticalSection( &freetype_cs );
2940 return ret;
2943 /*************************************************************
2944 * WineEngAddFontMemResourceEx
2947 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2949 GDI_CheckNotLock();
2951 if (ft_handle) /* do it only if we have freetype up and running */
2953 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2955 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2956 memcpy(pFontCopy, pbFont, cbFont);
2958 EnterCriticalSection( &freetype_cs );
2959 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2960 LeaveCriticalSection( &freetype_cs );
2962 if (*pcFonts == 0)
2964 TRACE("AddFontToList failed\n");
2965 HeapFree(GetProcessHeap(), 0, pFontCopy);
2966 return 0;
2968 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2969 * For now return something unique but quite random
2971 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2972 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2975 *pcFonts = 0;
2976 return 0;
2979 /*************************************************************
2980 * WineEngRemoveFontResourceEx
2983 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2985 INT ret = 0;
2987 GDI_CheckNotLock();
2989 if (ft_handle) /* do it only if we have freetype up and running */
2991 char *unixname;
2993 EnterCriticalSection( &freetype_cs );
2995 if ((unixname = wine_get_unix_file_name(file)))
2997 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
2999 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
3000 ret = remove_font_resource( unixname, addfont_flags );
3001 HeapFree(GetProcessHeap(), 0, unixname);
3003 if (!ret && !strchrW(file, '\\'))
3005 if ((unixname = get_winfonts_dir_path( file )))
3007 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3008 HeapFree(GetProcessHeap(), 0, unixname);
3010 if (!ret && (unixname = get_data_dir_path( file )))
3012 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3013 HeapFree(GetProcessHeap(), 0, unixname);
3017 LeaveCriticalSection( &freetype_cs );
3019 return ret;
3022 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3024 WCHAR *fullname;
3025 char *unix_name;
3026 int file_len;
3028 if (!font_file) return NULL;
3030 file_len = strlenW( font_file );
3032 if (font_path && font_path[0])
3034 int path_len = strlenW( font_path );
3035 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3036 if (!fullname) return NULL;
3037 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3038 fullname[path_len] = '\\';
3039 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3041 else
3043 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3044 if (!len) return NULL;
3045 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3046 if (!fullname) return NULL;
3047 GetFullPathNameW( font_file, len, fullname, NULL );
3050 unix_name = wine_get_unix_file_name( fullname );
3051 HeapFree( GetProcessHeap(), 0, fullname );
3052 return unix_name;
3055 #include <pshpack1.h>
3056 struct fontdir
3058 WORD num_of_resources;
3059 WORD res_id;
3060 WORD dfVersion;
3061 DWORD dfSize;
3062 CHAR dfCopyright[60];
3063 WORD dfType;
3064 WORD dfPoints;
3065 WORD dfVertRes;
3066 WORD dfHorizRes;
3067 WORD dfAscent;
3068 WORD dfInternalLeading;
3069 WORD dfExternalLeading;
3070 BYTE dfItalic;
3071 BYTE dfUnderline;
3072 BYTE dfStrikeOut;
3073 WORD dfWeight;
3074 BYTE dfCharSet;
3075 WORD dfPixWidth;
3076 WORD dfPixHeight;
3077 BYTE dfPitchAndFamily;
3078 WORD dfAvgWidth;
3079 WORD dfMaxWidth;
3080 BYTE dfFirstChar;
3081 BYTE dfLastChar;
3082 BYTE dfDefaultChar;
3083 BYTE dfBreakChar;
3084 WORD dfWidthBytes;
3085 DWORD dfDevice;
3086 DWORD dfFace;
3087 DWORD dfReserved;
3088 CHAR szFaceName[LF_FACESIZE];
3091 #include <poppack.h>
3093 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3094 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3096 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3098 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3099 Face *face;
3100 WCHAR *name, *english_name;
3101 ENUMLOGFONTEXW elf;
3102 NEWTEXTMETRICEXW ntm;
3103 DWORD type;
3105 if (!ft_face) return FALSE;
3106 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3107 get_family_names( ft_face, &name, &english_name, FALSE );
3108 pFT_Done_Face( ft_face );
3110 GetEnumStructs( face, name, &elf, &ntm, &type );
3111 release_face( face );
3112 HeapFree( GetProcessHeap(), 0, name );
3113 HeapFree( GetProcessHeap(), 0, english_name );
3115 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3117 memset( fd, 0, sizeof(*fd) );
3119 fd->num_of_resources = 1;
3120 fd->res_id = 0;
3121 fd->dfVersion = 0x200;
3122 fd->dfSize = sizeof(*fd);
3123 strcpy( fd->dfCopyright, "Wine fontdir" );
3124 fd->dfType = 0x4003; /* 0x0080 set if private */
3125 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3126 fd->dfVertRes = 72;
3127 fd->dfHorizRes = 72;
3128 fd->dfAscent = ntm.ntmTm.tmAscent;
3129 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3130 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3131 fd->dfItalic = ntm.ntmTm.tmItalic;
3132 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3133 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3134 fd->dfWeight = ntm.ntmTm.tmWeight;
3135 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3136 fd->dfPixWidth = 0;
3137 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3138 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3139 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3140 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3141 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3142 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3143 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3144 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3145 fd->dfWidthBytes = 0;
3146 fd->dfDevice = 0;
3147 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3148 fd->dfReserved = 0;
3149 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3151 return TRUE;
3154 #define NE_FFLAGS_LIBMODULE 0x8000
3155 #define NE_OSFLAGS_WINDOWS 0x02
3157 static const char dos_string[0x40] = "This is a TrueType resource file";
3158 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3160 #include <pshpack2.h>
3162 struct ne_typeinfo
3164 WORD type_id;
3165 WORD count;
3166 DWORD res;
3169 struct ne_nameinfo
3171 WORD off;
3172 WORD len;
3173 WORD flags;
3174 WORD id;
3175 DWORD res;
3178 struct rsrc_tab
3180 WORD align;
3181 struct ne_typeinfo fontdir_type;
3182 struct ne_nameinfo fontdir_name;
3183 struct ne_typeinfo scalable_type;
3184 struct ne_nameinfo scalable_name;
3185 WORD end_of_rsrc;
3186 BYTE fontdir_res_name[8];
3189 #include <poppack.h>
3191 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3193 BOOL ret = FALSE;
3194 HANDLE file;
3195 DWORD size, written;
3196 BYTE *ptr, *start;
3197 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3198 char *font_fileA, *last_part, *ext;
3199 IMAGE_DOS_HEADER dos;
3200 IMAGE_OS2_HEADER ne =
3202 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3203 0, 0, 0, 0, 0, 0,
3204 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3205 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3207 struct rsrc_tab rsrc_tab =
3210 { 0x8007, 1, 0 },
3211 { 0, 0, 0x0c50, 0x2c, 0 },
3212 { 0x80cc, 1, 0 },
3213 { 0, 0, 0x0c50, 0x8001, 0 },
3215 { 7,'F','O','N','T','D','I','R'}
3218 memset( &dos, 0, sizeof(dos) );
3219 dos.e_magic = IMAGE_DOS_SIGNATURE;
3220 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3222 /* import name is last part\0, resident name is last part without extension
3223 non-resident name is "FONTRES:" + lfFaceName */
3225 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3226 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3227 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3229 last_part = strrchr( font_fileA, '\\' );
3230 if (last_part) last_part++;
3231 else last_part = font_fileA;
3232 import_name_len = strlen( last_part ) + 1;
3234 ext = strchr( last_part, '.' );
3235 if (ext) res_name_len = ext - last_part;
3236 else res_name_len = import_name_len - 1;
3238 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3240 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3241 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3242 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3243 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3244 ne.ne_cbenttab = 2;
3245 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3247 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3248 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3249 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3250 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3252 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3253 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3255 if (!ptr)
3257 HeapFree( GetProcessHeap(), 0, font_fileA );
3258 return FALSE;
3261 memcpy( ptr, &dos, sizeof(dos) );
3262 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3263 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3265 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3266 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3268 ptr = start + dos.e_lfanew + ne.ne_restab;
3269 *ptr++ = res_name_len;
3270 memcpy( ptr, last_part, res_name_len );
3272 ptr = start + dos.e_lfanew + ne.ne_imptab;
3273 *ptr++ = import_name_len;
3274 memcpy( ptr, last_part, import_name_len );
3276 ptr = start + ne.ne_nrestab;
3277 *ptr++ = non_res_name_len;
3278 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3279 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3281 ptr = start + (rsrc_tab.scalable_name.off << 4);
3282 memcpy( ptr, font_fileA, font_file_len );
3284 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3285 memcpy( ptr, fontdir, fontdir->dfSize );
3287 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3288 if (file != INVALID_HANDLE_VALUE)
3290 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3291 ret = TRUE;
3292 CloseHandle( file );
3295 HeapFree( GetProcessHeap(), 0, start );
3296 HeapFree( GetProcessHeap(), 0, font_fileA );
3298 return ret;
3301 /*************************************************************
3302 * WineEngCreateScalableFontResource
3305 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3306 LPCWSTR font_file, LPCWSTR font_path )
3308 char *unix_name = get_ttf_file_name( font_file, font_path );
3309 struct fontdir fontdir;
3310 BOOL ret = FALSE;
3312 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3313 SetLastError( ERROR_INVALID_PARAMETER );
3314 else
3316 if (hidden) fontdir.dfType |= 0x80;
3317 ret = create_fot( resource, font_file, &fontdir );
3320 HeapFree( GetProcessHeap(), 0, unix_name );
3321 return ret;
3324 static const struct nls_update_font_list
3326 UINT ansi_cp, oem_cp;
3327 const char *oem, *fixed, *system;
3328 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3329 /* these are for font substitutes */
3330 const char *shelldlg, *tmsrmn;
3331 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3332 *helv_0, *tmsrmn_0;
3333 const struct subst
3335 const char *from, *to;
3336 } arial_0, courier_new_0, times_new_roman_0;
3337 } nls_update_font_list[] =
3339 /* Latin 1 (United States) */
3340 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3341 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3342 "Tahoma","Times New Roman",
3343 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3344 { 0 }, { 0 }, { 0 }
3346 /* Latin 1 (Multilingual) */
3347 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3348 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3349 "Tahoma","Times New Roman", /* FIXME unverified */
3350 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3351 { 0 }, { 0 }, { 0 }
3353 /* Eastern Europe */
3354 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3355 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3356 "Tahoma","Times New Roman", /* FIXME unverified */
3357 "Fixedsys,238", "System,238",
3358 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3359 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3360 { "Arial CE,0", "Arial,238" },
3361 { "Courier New CE,0", "Courier New,238" },
3362 { "Times New Roman CE,0", "Times New Roman,238" }
3364 /* Cyrillic */
3365 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3366 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3367 "Tahoma","Times New Roman", /* FIXME unverified */
3368 "Fixedsys,204", "System,204",
3369 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3370 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3371 { "Arial Cyr,0", "Arial,204" },
3372 { "Courier New Cyr,0", "Courier New,204" },
3373 { "Times New Roman Cyr,0", "Times New Roman,204" }
3375 /* Greek */
3376 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3377 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3378 "Tahoma","Times New Roman", /* FIXME unverified */
3379 "Fixedsys,161", "System,161",
3380 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3381 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3382 { "Arial Greek,0", "Arial,161" },
3383 { "Courier New Greek,0", "Courier New,161" },
3384 { "Times New Roman Greek,0", "Times New Roman,161" }
3386 /* Turkish */
3387 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3388 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3389 "Tahoma","Times New Roman", /* FIXME unverified */
3390 "Fixedsys,162", "System,162",
3391 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3392 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3393 { "Arial Tur,0", "Arial,162" },
3394 { "Courier New Tur,0", "Courier New,162" },
3395 { "Times New Roman Tur,0", "Times New Roman,162" }
3397 /* Hebrew */
3398 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3399 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3400 "Tahoma","Times New Roman", /* FIXME unverified */
3401 "Fixedsys,177", "System,177",
3402 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3403 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3404 { 0 }, { 0 }, { 0 }
3406 /* Arabic */
3407 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3408 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3409 "Tahoma","Times New Roman", /* FIXME unverified */
3410 "Fixedsys,178", "System,178",
3411 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3412 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3413 { 0 }, { 0 }, { 0 }
3415 /* Baltic */
3416 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3417 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3418 "Tahoma","Times New Roman", /* FIXME unverified */
3419 "Fixedsys,186", "System,186",
3420 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3421 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3422 { "Arial Baltic,0", "Arial,186" },
3423 { "Courier New Baltic,0", "Courier New,186" },
3424 { "Times New Roman Baltic,0", "Times New Roman,186" }
3426 /* Vietnamese */
3427 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3428 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3429 "Tahoma","Times New Roman", /* FIXME unverified */
3430 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3431 { 0 }, { 0 }, { 0 }
3433 /* Thai */
3434 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3435 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3436 "Tahoma","Times New Roman", /* FIXME unverified */
3437 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3438 { 0 }, { 0 }, { 0 }
3440 /* Japanese */
3441 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3442 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3443 "MS UI Gothic","MS Serif",
3444 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3445 { 0 }, { 0 }, { 0 }
3447 /* Chinese Simplified */
3448 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3449 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3450 "SimSun", "NSimSun",
3451 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3452 { 0 }, { 0 }, { 0 }
3454 /* Korean */
3455 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3456 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3457 "Gulim", "Batang",
3458 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3459 { 0 }, { 0 }, { 0 }
3461 /* Chinese Traditional */
3462 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3463 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3464 "PMingLiU", "MingLiU",
3465 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3466 { 0 }, { 0 }, { 0 }
3470 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3472 return ( ansi_cp == 932 /* CP932 for Japanese */
3473 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3474 || ansi_cp == 949 /* CP949 for Korean */
3475 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3478 static inline HKEY create_fonts_NT_registry_key(void)
3480 HKEY hkey = 0;
3482 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3483 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3484 return hkey;
3487 static inline HKEY create_fonts_9x_registry_key(void)
3489 HKEY hkey = 0;
3491 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3492 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3493 return hkey;
3496 static inline HKEY create_config_fonts_registry_key(void)
3498 HKEY hkey = 0;
3500 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3501 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3502 return hkey;
3505 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3507 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3509 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3510 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3511 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3512 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3515 static void set_value_key(HKEY hkey, const char *name, const char *value)
3517 if (value)
3518 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3519 else if (name)
3520 RegDeleteValueA(hkey, name);
3523 static void update_font_association_info(UINT current_ansi_codepage)
3525 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3526 static const char *assoc_charset_subkey = "Associated Charset";
3528 if (is_dbcs_ansi_cp(current_ansi_codepage))
3530 HKEY hkey;
3531 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3533 HKEY hsubkey;
3534 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3536 switch (current_ansi_codepage)
3538 case 932:
3539 set_value_key(hsubkey, "ANSI(00)", "NO");
3540 set_value_key(hsubkey, "OEM(FF)", "NO");
3541 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3542 break;
3543 case 936:
3544 case 949:
3545 case 950:
3546 set_value_key(hsubkey, "ANSI(00)", "YES");
3547 set_value_key(hsubkey, "OEM(FF)", "YES");
3548 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3549 break;
3551 RegCloseKey(hsubkey);
3554 /* TODO: Associated DefaultFonts */
3556 RegCloseKey(hkey);
3559 else
3560 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3563 static void update_font_info(void)
3565 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3566 char buf[40], cpbuf[40];
3567 DWORD len, type;
3568 HKEY hkey = 0;
3569 UINT i, ansi_cp = 0, oem_cp = 0;
3570 DWORD screen_dpi = 96, font_dpi = 0;
3571 BOOL done = FALSE;
3573 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3574 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3575 &hkey) == ERROR_SUCCESS)
3577 reg_load_dword(hkey, logpixels, &screen_dpi);
3578 RegCloseKey(hkey);
3581 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3582 return;
3584 reg_load_dword(hkey, logpixels, &font_dpi);
3586 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3587 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3588 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3589 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3590 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3592 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3593 if (is_dbcs_ansi_cp(ansi_cp))
3594 use_default_fallback = TRUE;
3596 buf[0] = 0;
3597 len = sizeof(buf);
3598 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3600 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3602 RegCloseKey(hkey);
3603 return;
3605 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3606 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3608 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3609 ansi_cp, oem_cp, screen_dpi);
3611 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3612 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3613 RegCloseKey(hkey);
3615 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3617 HKEY hkey;
3619 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3620 nls_update_font_list[i].oem_cp == oem_cp)
3622 hkey = create_config_fonts_registry_key();
3623 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3624 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3625 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3626 RegCloseKey(hkey);
3628 hkey = create_fonts_NT_registry_key();
3629 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3630 RegCloseKey(hkey);
3632 hkey = create_fonts_9x_registry_key();
3633 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3634 RegCloseKey(hkey);
3636 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3638 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3639 strlen(nls_update_font_list[i].shelldlg)+1);
3640 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3641 strlen(nls_update_font_list[i].tmsrmn)+1);
3643 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3644 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3645 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3646 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3647 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3648 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3649 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3650 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3652 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3653 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3654 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3656 RegCloseKey(hkey);
3658 done = TRUE;
3660 else
3662 /* Delete the FontSubstitutes from other locales */
3663 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3665 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3666 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3667 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3668 RegCloseKey(hkey);
3672 if (!done)
3673 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3675 /* update locale dependent font association info in registry.
3676 update only when codepages changed, not logpixels. */
3677 if (strcmp(buf, cpbuf) != 0)
3678 update_font_association_info(ansi_cp);
3681 static BOOL init_freetype(void)
3683 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3684 if(!ft_handle) {
3685 WINE_MESSAGE(
3686 "Wine cannot find the FreeType font library. To enable Wine to\n"
3687 "use TrueType fonts please install a version of FreeType greater than\n"
3688 "or equal to 2.0.5.\n"
3689 "http://www.freetype.org\n");
3690 return FALSE;
3693 #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;}
3695 LOAD_FUNCPTR(FT_Done_Face)
3696 LOAD_FUNCPTR(FT_Get_Char_Index)
3697 LOAD_FUNCPTR(FT_Get_First_Char)
3698 LOAD_FUNCPTR(FT_Get_Module)
3699 LOAD_FUNCPTR(FT_Get_Next_Char)
3700 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3701 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3702 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3703 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3704 LOAD_FUNCPTR(FT_Init_FreeType)
3705 LOAD_FUNCPTR(FT_Library_Version)
3706 LOAD_FUNCPTR(FT_Load_Glyph)
3707 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3708 LOAD_FUNCPTR(FT_Matrix_Multiply)
3709 #ifndef FT_MULFIX_INLINED
3710 LOAD_FUNCPTR(FT_MulFix)
3711 #endif
3712 LOAD_FUNCPTR(FT_New_Face)
3713 LOAD_FUNCPTR(FT_New_Memory_Face)
3714 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3715 LOAD_FUNCPTR(FT_Outline_Transform)
3716 LOAD_FUNCPTR(FT_Outline_Translate)
3717 LOAD_FUNCPTR(FT_Render_Glyph)
3718 LOAD_FUNCPTR(FT_Select_Charmap)
3719 LOAD_FUNCPTR(FT_Set_Charmap)
3720 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3721 LOAD_FUNCPTR(FT_Vector_Transform)
3722 LOAD_FUNCPTR(FT_Vector_Unit)
3723 #undef LOAD_FUNCPTR
3724 /* Don't warn if these ones are missing */
3725 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3726 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3727 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3728 #endif
3730 if(pFT_Init_FreeType(&library) != 0) {
3731 ERR("Can't init FreeType library\n");
3732 wine_dlclose(ft_handle, NULL, 0);
3733 ft_handle = NULL;
3734 return FALSE;
3736 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3738 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3739 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3740 ((FT_Version.minor << 8) & 0x00ff00) |
3741 ((FT_Version.patch ) & 0x0000ff);
3743 font_driver = &freetype_funcs;
3744 return TRUE;
3746 sym_not_found:
3747 WINE_MESSAGE(
3748 "Wine cannot find certain functions that it needs inside the FreeType\n"
3749 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3750 "FreeType to at least version 2.1.4.\n"
3751 "http://www.freetype.org\n");
3752 wine_dlclose(ft_handle, NULL, 0);
3753 ft_handle = NULL;
3754 return FALSE;
3757 static void init_font_list(void)
3759 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3760 static const WCHAR pathW[] = {'P','a','t','h',0};
3761 HKEY hkey;
3762 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3763 WCHAR windowsdir[MAX_PATH];
3764 char *unixname;
3765 const char *data_dir;
3767 delete_external_font_keys();
3769 /* load the system bitmap fonts */
3770 load_system_fonts();
3772 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3773 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3774 strcatW(windowsdir, fontsW);
3775 if((unixname = wine_get_unix_file_name(windowsdir)))
3777 ReadFontDir(unixname, FALSE);
3778 HeapFree(GetProcessHeap(), 0, unixname);
3781 /* load the system truetype fonts */
3782 data_dir = wine_get_data_dir();
3783 if (!data_dir) data_dir = wine_get_build_dir();
3784 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3786 strcpy(unixname, data_dir);
3787 strcat(unixname, "/fonts/");
3788 ReadFontDir(unixname, TRUE);
3789 HeapFree(GetProcessHeap(), 0, unixname);
3792 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3793 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3794 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3795 will skip these. */
3796 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3797 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3798 &hkey) == ERROR_SUCCESS)
3800 LPWSTR data, valueW;
3801 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3802 &valuelen, &datalen, NULL, NULL);
3804 valuelen++; /* returned value doesn't include room for '\0' */
3805 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3806 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3807 if (valueW && data)
3809 dlen = datalen * sizeof(WCHAR);
3810 vlen = valuelen;
3811 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3812 &dlen) == ERROR_SUCCESS)
3814 if(data[0] && (data[1] == ':'))
3816 if((unixname = wine_get_unix_file_name(data)))
3818 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3819 HeapFree(GetProcessHeap(), 0, unixname);
3822 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3824 WCHAR pathW[MAX_PATH];
3825 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3826 BOOL added = FALSE;
3828 sprintfW(pathW, fmtW, windowsdir, data);
3829 if((unixname = wine_get_unix_file_name(pathW)))
3831 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3832 HeapFree(GetProcessHeap(), 0, unixname);
3834 if (!added)
3835 load_font_from_data_dir(data);
3837 /* reset dlen and vlen */
3838 dlen = datalen;
3839 vlen = valuelen;
3842 HeapFree(GetProcessHeap(), 0, data);
3843 HeapFree(GetProcessHeap(), 0, valueW);
3844 RegCloseKey(hkey);
3847 #ifdef SONAME_LIBFONTCONFIG
3848 load_fontconfig_fonts();
3849 #elif defined(HAVE_CARBON_CARBON_H)
3850 load_mac_fonts();
3851 #endif
3853 /* then look in any directories that we've specified in the config file */
3854 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3855 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3857 DWORD len;
3858 LPWSTR valueW;
3859 LPSTR valueA, ptr;
3861 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3863 len += sizeof(WCHAR);
3864 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3865 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3867 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3868 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3869 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3870 TRACE( "got font path %s\n", debugstr_a(valueA) );
3871 ptr = valueA;
3872 while (ptr)
3874 const char* home;
3875 LPSTR next = strchr( ptr, ':' );
3876 if (next) *next++ = 0;
3877 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3878 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3880 strcpy( unixname, home );
3881 strcat( unixname, ptr + 1 );
3882 ReadFontDir( unixname, TRUE );
3883 HeapFree( GetProcessHeap(), 0, unixname );
3885 else
3886 ReadFontDir( ptr, TRUE );
3887 ptr = next;
3889 HeapFree( GetProcessHeap(), 0, valueA );
3891 HeapFree( GetProcessHeap(), 0, valueW );
3893 RegCloseKey(hkey);
3897 static BOOL move_to_front(const WCHAR *name)
3899 Family *family, *cursor2;
3900 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3902 if(!strcmpiW(family->FamilyName, name))
3904 list_remove(&family->entry);
3905 list_add_head(&font_list, &family->entry);
3906 return TRUE;
3909 return FALSE;
3912 static BOOL set_default(const WCHAR **name_list)
3914 while (*name_list)
3916 if (move_to_front(*name_list)) return TRUE;
3917 name_list++;
3920 return FALSE;
3923 static void reorder_font_list(void)
3925 set_default( default_serif_list );
3926 set_default( default_fixed_list );
3927 set_default( default_sans_list );
3930 /*************************************************************
3931 * WineEngInit
3933 * Initialize FreeType library and create a list of available faces
3935 BOOL WineEngInit(void)
3937 DWORD disposition;
3938 HANDLE font_mutex;
3940 /* update locale dependent font info in registry */
3941 update_font_info();
3943 if(!init_freetype()) return FALSE;
3945 #ifdef SONAME_LIBFONTCONFIG
3946 init_fontconfig();
3947 #endif
3949 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3951 ERR("Failed to create font mutex\n");
3952 return FALSE;
3954 WaitForSingleObject(font_mutex, INFINITE);
3956 create_font_cache_key(&hkey_font_cache, &disposition);
3958 if(disposition == REG_CREATED_NEW_KEY)
3959 init_font_list();
3960 else
3961 load_font_list_from_cache(hkey_font_cache);
3963 reorder_font_list();
3965 DumpFontList();
3966 LoadSubstList();
3967 DumpSubstList();
3968 LoadReplaceList();
3970 if(disposition == REG_CREATED_NEW_KEY)
3971 update_reg_entries();
3973 init_system_links();
3975 ReleaseMutex(font_mutex);
3976 return TRUE;
3980 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3982 TT_OS2 *pOS2;
3983 TT_HoriHeader *pHori;
3985 LONG ppem;
3986 const LONG MAX_PPEM = (1 << 16) - 1;
3988 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3989 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3991 if(height == 0) height = 16;
3993 /* Calc. height of EM square:
3995 * For +ve lfHeight we have
3996 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3997 * Re-arranging gives:
3998 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4000 * For -ve lfHeight we have
4001 * |lfHeight| = ppem
4002 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4003 * with il = winAscent + winDescent - units_per_em]
4007 if(height > 0) {
4008 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
4009 ppem = MulDiv(ft_face->units_per_EM, height,
4010 pHori->Ascender - pHori->Descender);
4011 else
4012 ppem = MulDiv(ft_face->units_per_EM, height,
4013 pOS2->usWinAscent + pOS2->usWinDescent);
4014 if(ppem > MAX_PPEM) {
4015 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
4016 ppem = 1;
4019 else if(height >= -MAX_PPEM)
4020 ppem = -height;
4021 else {
4022 WARN("Ignoring too large height %d\n", height);
4023 ppem = 1;
4026 return ppem;
4029 static struct font_mapping *map_font_file( const char *name )
4031 struct font_mapping *mapping;
4032 struct stat st;
4033 int fd;
4035 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4036 if (fstat( fd, &st ) == -1) goto error;
4038 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4040 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4042 mapping->refcount++;
4043 close( fd );
4044 return mapping;
4047 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4048 goto error;
4050 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4051 close( fd );
4053 if (mapping->data == MAP_FAILED)
4055 HeapFree( GetProcessHeap(), 0, mapping );
4056 return NULL;
4058 mapping->refcount = 1;
4059 mapping->dev = st.st_dev;
4060 mapping->ino = st.st_ino;
4061 mapping->size = st.st_size;
4062 list_add_tail( &mappings_list, &mapping->entry );
4063 return mapping;
4065 error:
4066 close( fd );
4067 return NULL;
4070 static void unmap_font_file( struct font_mapping *mapping )
4072 if (!--mapping->refcount)
4074 list_remove( &mapping->entry );
4075 munmap( mapping->data, mapping->size );
4076 HeapFree( GetProcessHeap(), 0, mapping );
4080 static LONG load_VDMX(GdiFont*, LONG);
4082 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4084 FT_Error err;
4085 FT_Face ft_face;
4086 void *data_ptr;
4087 DWORD data_size;
4089 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4091 if (face->file)
4093 char *filename = strWtoA( CP_UNIXCP, face->file );
4094 font->mapping = map_font_file( filename );
4095 HeapFree( GetProcessHeap(), 0, filename );
4096 if (!font->mapping)
4098 WARN("failed to map %s\n", debugstr_w(face->file));
4099 return 0;
4101 data_ptr = font->mapping->data;
4102 data_size = font->mapping->size;
4104 else
4106 data_ptr = face->font_data_ptr;
4107 data_size = face->font_data_size;
4110 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4111 if(err) {
4112 ERR("FT_New_Face rets %d\n", err);
4113 return 0;
4116 /* set it here, as load_VDMX needs it */
4117 font->ft_face = ft_face;
4119 if(FT_IS_SCALABLE(ft_face)) {
4120 /* load the VDMX table if we have one */
4121 font->ppem = load_VDMX(font, height);
4122 if(font->ppem == 0)
4123 font->ppem = calc_ppem_for_height(ft_face, height);
4124 TRACE("height %d => ppem %d\n", height, font->ppem);
4126 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4127 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4128 } else {
4129 font->ppem = height;
4130 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4131 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4133 return ft_face;
4137 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4139 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4140 a single face with the requested charset. The idea is to check if
4141 the selected font supports the current ANSI codepage, if it does
4142 return the corresponding charset, else return the first charset */
4144 CHARSETINFO csi;
4145 int acp = GetACP(), i;
4146 DWORD fs0;
4148 *cp = acp;
4149 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4151 const SYSTEM_LINKS *font_link;
4153 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4154 return csi.ciCharset;
4156 font_link = find_font_link(family_name);
4157 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4158 return csi.ciCharset;
4161 for(i = 0; i < 32; i++) {
4162 fs0 = 1L << i;
4163 if(face->fs.fsCsb[0] & fs0) {
4164 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4165 *cp = csi.ciACP;
4166 return csi.ciCharset;
4168 else
4169 FIXME("TCI failing on %x\n", fs0);
4173 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4174 face->fs.fsCsb[0], debugstr_w(face->file));
4175 *cp = acp;
4176 return DEFAULT_CHARSET;
4179 static GdiFont *alloc_font(void)
4181 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4182 ret->refcount = 1;
4183 ret->gmsize = 1;
4184 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4185 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4186 ret->potm = NULL;
4187 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4188 ret->total_kern_pairs = (DWORD)-1;
4189 ret->kern_pairs = NULL;
4190 list_init(&ret->child_fonts);
4191 return ret;
4194 static void free_font(GdiFont *font)
4196 CHILD_FONT *child, *child_next;
4197 DWORD i;
4199 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4201 list_remove(&child->entry);
4202 if(child->font)
4203 free_font(child->font);
4204 release_face( child->face );
4205 HeapFree(GetProcessHeap(), 0, child);
4208 if (font->ft_face) pFT_Done_Face(font->ft_face);
4209 if (font->mapping) unmap_font_file( font->mapping );
4210 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4211 HeapFree(GetProcessHeap(), 0, font->potm);
4212 HeapFree(GetProcessHeap(), 0, font->name);
4213 for (i = 0; i < font->gmsize; i++)
4214 HeapFree(GetProcessHeap(),0,font->gm[i]);
4215 HeapFree(GetProcessHeap(), 0, font->gm);
4216 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4217 HeapFree(GetProcessHeap(), 0, font);
4221 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4223 FT_Face ft_face = font->ft_face;
4224 FT_ULong len;
4225 FT_Error err;
4227 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4229 if(!buf)
4230 len = 0;
4231 else
4232 len = cbData;
4234 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4236 /* make sure value of len is the value freetype says it needs */
4237 if (buf && len)
4239 FT_ULong needed = 0;
4240 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4241 if( !err && needed < len) len = needed;
4243 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4244 if (err)
4246 TRACE("Can't find table %c%c%c%c\n",
4247 /* bytes were reversed */
4248 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4249 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4250 return GDI_ERROR;
4252 return len;
4255 /*************************************************************
4256 * load_VDMX
4258 * load the vdmx entry for the specified height
4261 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4262 ( ( (FT_ULong)_x4 << 24 ) | \
4263 ( (FT_ULong)_x3 << 16 ) | \
4264 ( (FT_ULong)_x2 << 8 ) | \
4265 (FT_ULong)_x1 )
4267 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4269 typedef struct {
4270 BYTE bCharSet;
4271 BYTE xRatio;
4272 BYTE yStartRatio;
4273 BYTE yEndRatio;
4274 } Ratios;
4276 typedef struct {
4277 WORD recs;
4278 BYTE startsz;
4279 BYTE endsz;
4280 } VDMX_group;
4282 static LONG load_VDMX(GdiFont *font, LONG height)
4284 WORD hdr[3], tmp;
4285 VDMX_group group;
4286 BYTE devXRatio, devYRatio;
4287 USHORT numRecs, numRatios;
4288 DWORD result, offset = -1;
4289 LONG ppem = 0;
4290 int i;
4292 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4294 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4295 return ppem;
4297 /* FIXME: need the real device aspect ratio */
4298 devXRatio = 1;
4299 devYRatio = 1;
4301 numRecs = GET_BE_WORD(hdr[1]);
4302 numRatios = GET_BE_WORD(hdr[2]);
4304 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4305 for(i = 0; i < numRatios; i++) {
4306 Ratios ratio;
4308 offset = (3 * 2) + (i * sizeof(Ratios));
4309 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4310 offset = -1;
4312 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4314 if((ratio.xRatio == 0 &&
4315 ratio.yStartRatio == 0 &&
4316 ratio.yEndRatio == 0) ||
4317 (devXRatio == ratio.xRatio &&
4318 devYRatio >= ratio.yStartRatio &&
4319 devYRatio <= ratio.yEndRatio))
4321 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4322 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4323 offset = GET_BE_WORD(tmp);
4324 break;
4328 if(offset == -1) {
4329 FIXME("No suitable ratio found\n");
4330 return ppem;
4333 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4334 USHORT recs;
4335 BYTE startsz, endsz;
4336 WORD *vTable;
4338 recs = GET_BE_WORD(group.recs);
4339 startsz = group.startsz;
4340 endsz = group.endsz;
4342 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4344 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4345 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4346 if(result == GDI_ERROR) {
4347 FIXME("Failed to retrieve vTable\n");
4348 goto end;
4351 if(height > 0) {
4352 for(i = 0; i < recs; i++) {
4353 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4354 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4355 ppem = GET_BE_WORD(vTable[i * 3]);
4357 if(yMax + -yMin == height) {
4358 font->yMax = yMax;
4359 font->yMin = yMin;
4360 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4361 break;
4363 if(yMax + -yMin > height) {
4364 if(--i < 0) {
4365 ppem = 0;
4366 goto end; /* failed */
4368 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4369 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4370 ppem = GET_BE_WORD(vTable[i * 3]);
4371 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4372 break;
4375 if(!font->yMax) {
4376 ppem = 0;
4377 TRACE("ppem not found for height %d\n", height);
4380 end:
4381 HeapFree(GetProcessHeap(), 0, vTable);
4384 return ppem;
4387 static void dump_gdi_font_list(void)
4389 GdiFont *font;
4391 TRACE("---------- Font Cache ----------\n");
4392 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4393 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4394 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4397 static void grab_font( GdiFont *font )
4399 if (!font->refcount++)
4401 list_remove( &font->unused_entry );
4402 unused_font_count--;
4406 static void release_font( GdiFont *font )
4408 if (!font) return;
4409 if (!--font->refcount)
4411 TRACE( "font %p\n", font );
4413 /* add it to the unused list */
4414 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4415 if (unused_font_count > UNUSED_CACHE_SIZE)
4417 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4418 TRACE( "freeing %p\n", font );
4419 list_remove( &font->entry );
4420 list_remove( &font->unused_entry );
4421 free_font( font );
4423 else unused_font_count++;
4425 if (TRACE_ON(font)) dump_gdi_font_list();
4429 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4431 if(font->font_desc.hash != fd->hash) return TRUE;
4432 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4433 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4434 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4435 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4438 static void calc_hash(FONT_DESC *pfd)
4440 DWORD hash = 0, *ptr, two_chars;
4441 WORD *pwc;
4442 unsigned int i;
4444 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4445 hash ^= *ptr;
4446 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4447 hash ^= *ptr;
4448 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4449 two_chars = *ptr;
4450 pwc = (WCHAR *)&two_chars;
4451 if(!*pwc) break;
4452 *pwc = toupperW(*pwc);
4453 pwc++;
4454 *pwc = toupperW(*pwc);
4455 hash ^= two_chars;
4456 if(!*pwc) break;
4458 hash ^= !pfd->can_use_bitmap;
4459 pfd->hash = hash;
4460 return;
4463 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4465 GdiFont *ret;
4466 FONT_DESC fd;
4468 fd.lf = *plf;
4469 fd.matrix = *pmat;
4470 fd.can_use_bitmap = can_use_bitmap;
4471 calc_hash(&fd);
4473 /* try the in-use list */
4474 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4476 if(fontcmp(ret, &fd)) continue;
4477 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4478 list_remove( &ret->entry );
4479 list_add_head( &gdi_font_list, &ret->entry );
4480 grab_font( ret );
4481 return ret;
4483 return NULL;
4486 static void add_to_cache(GdiFont *font)
4488 static DWORD cache_num = 1;
4490 font->cache_num = cache_num++;
4491 list_add_head(&gdi_font_list, &font->entry);
4492 TRACE( "font %p\n", font );
4495 /*************************************************************
4496 * create_child_font_list
4498 static BOOL create_child_font_list(GdiFont *font)
4500 BOOL ret = FALSE;
4501 SYSTEM_LINKS *font_link;
4502 CHILD_FONT *font_link_entry, *new_child;
4503 FontSubst *psub;
4504 WCHAR* font_name;
4506 psub = get_font_subst(&font_subst_list, font->name, -1);
4507 font_name = psub ? psub->to.name : font->name;
4508 font_link = find_font_link(font_name);
4509 if (font_link != NULL)
4511 TRACE("found entry in system list\n");
4512 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4514 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4515 new_child->face = font_link_entry->face;
4516 new_child->font = NULL;
4517 new_child->face->refcount++;
4518 list_add_tail(&font->child_fonts, &new_child->entry);
4519 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4521 ret = TRUE;
4524 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4525 * Sans Serif. This is how asian windows get default fallbacks for fonts
4527 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4528 font->charset != OEM_CHARSET &&
4529 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4531 font_link = find_font_link(szDefaultFallbackLink);
4532 if (font_link != NULL)
4534 TRACE("found entry in default fallback list\n");
4535 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4537 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4538 new_child->face = font_link_entry->face;
4539 new_child->font = NULL;
4540 new_child->face->refcount++;
4541 list_add_tail(&font->child_fonts, &new_child->entry);
4542 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4544 ret = TRUE;
4548 return ret;
4551 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4553 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4555 if (pFT_Set_Charmap)
4557 FT_Int i;
4558 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4560 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4562 for (i = 0; i < ft_face->num_charmaps; i++)
4564 if (ft_face->charmaps[i]->encoding == encoding)
4566 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4567 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4569 switch (ft_face->charmaps[i]->platform_id)
4571 default:
4572 cmap_def = ft_face->charmaps[i];
4573 break;
4574 case 0: /* Apple Unicode */
4575 cmap0 = ft_face->charmaps[i];
4576 break;
4577 case 1: /* Macintosh */
4578 cmap1 = ft_face->charmaps[i];
4579 break;
4580 case 2: /* ISO */
4581 cmap2 = ft_face->charmaps[i];
4582 break;
4583 case 3: /* Microsoft */
4584 cmap3 = ft_face->charmaps[i];
4585 break;
4589 if (cmap3) /* prefer Microsoft cmap table */
4590 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4591 else if (cmap1)
4592 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4593 else if (cmap2)
4594 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4595 else if (cmap0)
4596 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4597 else if (cmap_def)
4598 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4600 return ft_err == FT_Err_Ok;
4603 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4607 /*************************************************************
4608 * freetype_CreateDC
4610 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4611 LPCWSTR output, const DEVMODEW *devmode )
4613 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4615 if (!physdev) return FALSE;
4616 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4617 return TRUE;
4621 /*************************************************************
4622 * freetype_DeleteDC
4624 static BOOL freetype_DeleteDC( PHYSDEV dev )
4626 struct freetype_physdev *physdev = get_freetype_dev( dev );
4627 release_font( physdev->font );
4628 HeapFree( GetProcessHeap(), 0, physdev );
4629 return TRUE;
4632 static FT_Encoding pick_charmap( FT_Face face, int charset )
4634 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4635 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4636 const FT_Encoding *encs = regular_order;
4638 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4640 while (*encs != 0)
4642 if (select_charmap( face, *encs )) break;
4643 encs++;
4645 return *encs;
4648 #define GASP_GRIDFIT 0x01
4649 #define GASP_DOGRAY 0x02
4650 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4652 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4654 DWORD size;
4655 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4656 WORD *alloced = NULL, *ptr = buf;
4657 WORD num_recs, version;
4658 BOOL ret = FALSE;
4660 *flags = 0;
4661 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4662 if (size == GDI_ERROR) return FALSE;
4663 if (size < 4 * sizeof(WORD)) return FALSE;
4664 if (size > sizeof(buf))
4666 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4667 if (!ptr) return FALSE;
4670 get_font_data( font, GASP_TAG, 0, ptr, size );
4672 version = GET_BE_WORD( *ptr++ );
4673 num_recs = GET_BE_WORD( *ptr++ );
4675 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4677 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4678 goto done;
4681 while (num_recs--)
4683 *flags = GET_BE_WORD( *(ptr + 1) );
4684 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4685 ptr += 2;
4687 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4688 ret = TRUE;
4690 done:
4691 HeapFree( GetProcessHeap(), 0, alloced );
4692 return ret;
4695 /*************************************************************
4696 * freetype_SelectFont
4698 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4700 struct freetype_physdev *physdev = get_freetype_dev( dev );
4701 GdiFont *ret;
4702 Face *face, *best, *best_bitmap;
4703 Family *family, *last_resort_family;
4704 const struct list *face_list;
4705 INT height, width = 0;
4706 unsigned int score = 0, new_score;
4707 signed int diff = 0, newdiff;
4708 BOOL bd, it, can_use_bitmap, want_vertical;
4709 LOGFONTW lf;
4710 CHARSETINFO csi;
4711 FMAT2 dcmat;
4712 FontSubst *psub = NULL;
4713 DC *dc = get_dc_ptr( dev->hdc );
4714 const SYSTEM_LINKS *font_link;
4716 if (!hfont) /* notification that the font has been changed by another driver */
4718 release_font( physdev->font );
4719 physdev->font = NULL;
4720 release_dc_ptr( dc );
4721 return 0;
4724 GetObjectW( hfont, sizeof(lf), &lf );
4725 lf.lfWidth = abs(lf.lfWidth);
4727 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4729 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4730 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4731 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4732 lf.lfEscapement);
4734 if(dc->GraphicsMode == GM_ADVANCED)
4736 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4737 /* Try to avoid not necessary glyph transformations */
4738 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4740 lf.lfHeight *= fabs(dcmat.eM11);
4741 lf.lfWidth *= fabs(dcmat.eM11);
4742 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4745 else
4747 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4748 font scaling abilities. */
4749 dcmat.eM11 = dcmat.eM22 = 1.0;
4750 dcmat.eM21 = dcmat.eM12 = 0;
4751 lf.lfOrientation = lf.lfEscapement;
4752 if (dc->vport2WorldValid)
4754 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4755 lf.lfOrientation = -lf.lfOrientation;
4756 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4757 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4761 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4762 dcmat.eM21, dcmat.eM22);
4764 GDI_CheckNotLock();
4765 EnterCriticalSection( &freetype_cs );
4767 /* check the cache first */
4768 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4769 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4770 goto done;
4773 TRACE("not in cache\n");
4774 ret = alloc_font();
4776 ret->font_desc.matrix = dcmat;
4777 ret->font_desc.lf = lf;
4778 ret->font_desc.can_use_bitmap = can_use_bitmap;
4779 calc_hash(&ret->font_desc);
4781 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4782 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4783 original value lfCharSet. Note this is a special case for
4784 Symbol and doesn't happen at least for "Wingdings*" */
4786 if(!strcmpiW(lf.lfFaceName, SymbolW))
4787 lf.lfCharSet = SYMBOL_CHARSET;
4789 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4790 switch(lf.lfCharSet) {
4791 case DEFAULT_CHARSET:
4792 csi.fs.fsCsb[0] = 0;
4793 break;
4794 default:
4795 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4796 csi.fs.fsCsb[0] = 0;
4797 break;
4801 family = NULL;
4802 if(lf.lfFaceName[0] != '\0') {
4803 CHILD_FONT *font_link_entry;
4804 LPWSTR FaceName = lf.lfFaceName;
4806 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4808 if(psub) {
4809 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4810 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4811 if (psub->to.charset != -1)
4812 lf.lfCharSet = psub->to.charset;
4815 /* We want a match on name and charset or just name if
4816 charset was DEFAULT_CHARSET. If the latter then
4817 we fixup the returned charset later in get_nearest_charset
4818 where we'll either use the charset of the current ansi codepage
4819 or if that's unavailable the first charset that the font supports.
4821 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4822 if (!strcmpiW(family->FamilyName, FaceName) ||
4823 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4825 font_link = find_font_link(family->FamilyName);
4826 face_list = get_face_list_from_family(family);
4827 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4828 if (!(face->scalable || can_use_bitmap))
4829 continue;
4830 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4831 goto found;
4832 if (font_link != NULL &&
4833 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4834 goto found;
4835 if (!csi.fs.fsCsb[0])
4836 goto found;
4841 /* Search by full face name. */
4842 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4843 face_list = get_face_list_from_family(family);
4844 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4845 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4846 (face->scalable || can_use_bitmap))
4848 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4849 goto found_face;
4850 font_link = find_font_link(family->FamilyName);
4851 if (font_link != NULL &&
4852 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4853 goto found_face;
4859 * Try check the SystemLink list first for a replacement font.
4860 * We may find good replacements there.
4862 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4864 if(!strcmpiW(font_link->font_name, FaceName) ||
4865 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4867 TRACE("found entry in system list\n");
4868 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4870 const SYSTEM_LINKS *links;
4872 face = font_link_entry->face;
4873 if (!(face->scalable || can_use_bitmap))
4874 continue;
4875 family = face->family;
4876 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4877 goto found;
4878 links = find_font_link(family->FamilyName);
4879 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4880 goto found;
4886 psub = NULL; /* substitution is no more relevant */
4888 /* If requested charset was DEFAULT_CHARSET then try using charset
4889 corresponding to the current ansi codepage */
4890 if (!csi.fs.fsCsb[0])
4892 INT acp = GetACP();
4893 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4894 FIXME("TCI failed on codepage %d\n", acp);
4895 csi.fs.fsCsb[0] = 0;
4896 } else
4897 lf.lfCharSet = csi.ciCharset;
4900 want_vertical = (lf.lfFaceName[0] == '@');
4902 /* Face families are in the top 4 bits of lfPitchAndFamily,
4903 so mask with 0xF0 before testing */
4905 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4906 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4907 strcpyW(lf.lfFaceName, defFixed);
4908 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4909 strcpyW(lf.lfFaceName, defSerif);
4910 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4911 strcpyW(lf.lfFaceName, defSans);
4912 else
4913 strcpyW(lf.lfFaceName, defSans);
4914 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4915 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4916 font_link = find_font_link(family->FamilyName);
4917 face_list = get_face_list_from_family(family);
4918 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4919 if (!(face->scalable || can_use_bitmap))
4920 continue;
4921 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4922 goto found;
4923 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4924 goto found;
4929 last_resort_family = NULL;
4930 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4931 font_link = find_font_link(family->FamilyName);
4932 face_list = get_face_list_from_family(family);
4933 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4934 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
4935 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4936 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4937 if(face->scalable)
4938 goto found;
4939 if(can_use_bitmap && !last_resort_family)
4940 last_resort_family = family;
4945 if(last_resort_family) {
4946 family = last_resort_family;
4947 csi.fs.fsCsb[0] = 0;
4948 goto found;
4951 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4952 face_list = get_face_list_from_family(family);
4953 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4954 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
4955 csi.fs.fsCsb[0] = 0;
4956 WARN("just using first face for now\n");
4957 goto found;
4959 if(can_use_bitmap && !last_resort_family)
4960 last_resort_family = family;
4963 if(!last_resort_family) {
4964 FIXME("can't find a single appropriate font - bailing\n");
4965 free_font(ret);
4966 ret = NULL;
4967 goto done;
4970 WARN("could only find a bitmap font - this will probably look awful!\n");
4971 family = last_resort_family;
4972 csi.fs.fsCsb[0] = 0;
4974 found:
4975 it = lf.lfItalic ? 1 : 0;
4976 bd = lf.lfWeight > 550 ? 1 : 0;
4978 height = lf.lfHeight;
4980 face = best = best_bitmap = NULL;
4981 font_link = find_font_link(family->FamilyName);
4982 face_list = get_face_list_from_family(family);
4983 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4985 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4986 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4987 !csi.fs.fsCsb[0])
4989 BOOL italic, bold;
4991 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4992 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4993 new_score = (italic ^ it) + (bold ^ bd);
4994 if(!best || new_score <= score)
4996 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4997 italic, bold, it, bd);
4998 score = new_score;
4999 best = face;
5000 if(best->scalable && score == 0) break;
5001 if(!best->scalable)
5003 if(height > 0)
5004 newdiff = height - (signed int)(best->size.height);
5005 else
5006 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
5007 if(!best_bitmap || new_score < score ||
5008 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5010 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5011 diff = newdiff;
5012 best_bitmap = best;
5013 if(score == 0 && diff == 0) break;
5019 if(best)
5020 face = best->scalable ? best : best_bitmap;
5021 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5022 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5024 found_face:
5025 height = lf.lfHeight;
5027 ret->fs = face->fs;
5029 if(csi.fs.fsCsb[0]) {
5030 ret->charset = lf.lfCharSet;
5031 ret->codepage = csi.ciACP;
5033 else
5034 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5036 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5037 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5039 ret->aveWidth = height ? lf.lfWidth : 0;
5041 if(!face->scalable) {
5042 /* Windows uses integer scaling factors for bitmap fonts */
5043 INT scale, scaled_height;
5044 GdiFont *cachedfont;
5046 /* FIXME: rotation of bitmap fonts is ignored */
5047 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5048 if (ret->aveWidth)
5049 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5050 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5051 dcmat.eM11 = dcmat.eM22 = 1.0;
5052 /* As we changed the matrix, we need to search the cache for the font again,
5053 * otherwise we might explode the cache. */
5054 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5055 TRACE("Found cached font after non-scalable matrix rescale!\n");
5056 free_font( ret );
5057 ret = cachedfont;
5058 goto done;
5060 calc_hash(&ret->font_desc);
5062 if (height != 0) height = diff;
5063 height += face->size.height;
5065 scale = (height + face->size.height - 1) / face->size.height;
5066 scaled_height = scale * face->size.height;
5067 /* Only jump to the next height if the difference <= 25% original height */
5068 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5069 /* The jump between unscaled and doubled is delayed by 1 */
5070 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5071 ret->scale_y = scale;
5073 width = face->size.x_ppem >> 6;
5074 height = face->size.y_ppem >> 6;
5076 else
5077 ret->scale_y = 1.0;
5078 TRACE("font scale y: %f\n", ret->scale_y);
5080 ret->ft_face = OpenFontFace(ret, face, width, height);
5082 if (!ret->ft_face)
5084 free_font( ret );
5085 ret = NULL;
5086 goto done;
5089 ret->ntmFlags = face->ntmFlags;
5091 pick_charmap( ret->ft_face, ret->charset );
5093 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5094 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5095 ret->underline = lf.lfUnderline ? 0xff : 0;
5096 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5097 create_child_font_list(ret);
5099 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5101 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5102 if (length != GDI_ERROR)
5104 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5105 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5106 TRACE("Loaded GSUB table of %i bytes\n",length);
5109 ret->aa_flags = HIWORD( face->flags );
5111 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5113 add_to_cache(ret);
5114 done:
5115 if (ret)
5117 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5119 switch (lf.lfQuality)
5121 case NONANTIALIASED_QUALITY:
5122 case ANTIALIASED_QUALITY:
5123 next->funcs->pSelectFont( dev, hfont, aa_flags );
5124 break;
5125 case CLEARTYPE_QUALITY:
5126 case CLEARTYPE_NATURAL_QUALITY:
5127 default:
5128 if (!*aa_flags) *aa_flags = ret->aa_flags;
5129 next->funcs->pSelectFont( dev, hfont, aa_flags );
5131 /* fixup the antialiasing flags for that font */
5132 switch (*aa_flags)
5134 case WINE_GGO_HRGB_BITMAP:
5135 case WINE_GGO_HBGR_BITMAP:
5136 case WINE_GGO_VRGB_BITMAP:
5137 case WINE_GGO_VBGR_BITMAP:
5138 if (is_subpixel_rendering_enabled()) break;
5139 *aa_flags = GGO_GRAY4_BITMAP;
5140 /* fall through */
5141 case GGO_GRAY2_BITMAP:
5142 case GGO_GRAY4_BITMAP:
5143 case GGO_GRAY8_BITMAP:
5144 case WINE_GGO_GRAY16_BITMAP:
5145 if (is_hinting_enabled())
5147 WORD gasp_flags;
5148 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5150 TRACE( "font %s %d aa disabled by GASP\n",
5151 debugstr_w(lf.lfFaceName), lf.lfHeight );
5152 *aa_flags = GGO_BITMAP;
5157 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5158 release_font( physdev->font );
5159 physdev->font = ret;
5161 LeaveCriticalSection( &freetype_cs );
5162 release_dc_ptr( dc );
5163 return ret ? hfont : 0;
5166 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5168 HRSRC rsrc;
5169 HGLOBAL hMem;
5170 WCHAR *p;
5171 int i;
5173 id += IDS_FIRST_SCRIPT;
5174 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5175 if (!rsrc) return 0;
5176 hMem = LoadResource( gdi32_module, rsrc );
5177 if (!hMem) return 0;
5179 p = LockResource( hMem );
5180 id &= 0x000f;
5181 while (id--) p += *p + 1;
5183 i = min(LF_FACESIZE - 1, *p);
5184 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5185 buffer[i] = 0;
5186 return i;
5190 /***************************************************
5191 * create_enum_charset_list
5193 * This function creates charset enumeration list because in DEFAULT_CHARSET
5194 * case, the ANSI codepage's charset takes precedence over other charsets.
5195 * This function works as a filter other than DEFAULT_CHARSET case.
5197 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5199 CHARSETINFO csi;
5200 DWORD n = 0;
5202 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5203 csi.fs.fsCsb[0] != 0) {
5204 list->element[n].mask = csi.fs.fsCsb[0];
5205 list->element[n].charset = csi.ciCharset;
5206 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5207 n++;
5209 else { /* charset is DEFAULT_CHARSET or invalid. */
5210 INT acp, i;
5211 DWORD mask = 0;
5213 /* Set the current codepage's charset as the first element. */
5214 acp = GetACP();
5215 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5216 csi.fs.fsCsb[0] != 0) {
5217 list->element[n].mask = csi.fs.fsCsb[0];
5218 list->element[n].charset = csi.ciCharset;
5219 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5220 mask |= csi.fs.fsCsb[0];
5221 n++;
5224 /* Fill out left elements. */
5225 for (i = 0; i < 32; i++) {
5226 FONTSIGNATURE fs;
5227 fs.fsCsb[0] = 1L << i;
5228 fs.fsCsb[1] = 0;
5229 if (fs.fsCsb[0] & mask)
5230 continue; /* skip, already added. */
5231 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5232 continue; /* skip, this is an invalid fsCsb bit. */
5234 list->element[n].mask = fs.fsCsb[0];
5235 list->element[n].charset = csi.ciCharset;
5236 load_script_name( i, list->element[n].name );
5237 mask |= fs.fsCsb[0];
5238 n++;
5241 /* add catch all mask for remaining bits */
5242 if (~mask)
5244 list->element[n].mask = ~mask;
5245 list->element[n].charset = DEFAULT_CHARSET;
5246 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5247 n++;
5250 list->total = n;
5252 return n;
5255 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5256 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5258 GdiFont *font;
5259 LONG width, height;
5261 if (face->cached_enum_data)
5263 TRACE("Cached\n");
5264 *pelf = face->cached_enum_data->elf;
5265 *pntm = face->cached_enum_data->ntm;
5266 *ptype = face->cached_enum_data->type;
5267 return;
5270 font = alloc_font();
5272 if(face->scalable) {
5273 height = 100;
5274 width = 0;
5275 } else {
5276 height = face->size.y_ppem >> 6;
5277 width = face->size.x_ppem >> 6;
5279 font->scale_y = 1.0;
5281 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5283 free_font(font);
5284 return;
5287 font->name = strdupW( family_name );
5288 font->ntmFlags = face->ntmFlags;
5290 if (get_outline_text_metrics(font))
5292 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5294 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5295 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5296 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5298 lstrcpynW(pelf->elfLogFont.lfFaceName,
5299 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5300 LF_FACESIZE);
5301 lstrcpynW(pelf->elfFullName,
5302 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5303 LF_FULLFACESIZE);
5304 lstrcpynW(pelf->elfStyle,
5305 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5306 LF_FACESIZE);
5308 else
5310 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5312 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5313 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5314 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5316 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5317 if (face->FullName)
5318 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5319 else
5320 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5321 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5324 pntm->ntmTm.ntmFlags = face->ntmFlags;
5325 pntm->ntmFontSig = face->fs;
5327 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5329 pelf->elfLogFont.lfEscapement = 0;
5330 pelf->elfLogFont.lfOrientation = 0;
5331 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5332 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5333 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5334 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5335 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5336 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5337 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5338 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5339 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5340 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5341 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5343 *ptype = 0;
5344 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5345 *ptype |= TRUETYPE_FONTTYPE;
5346 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5347 *ptype |= DEVICE_FONTTYPE;
5348 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5349 *ptype |= RASTER_FONTTYPE;
5351 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5352 if (face->cached_enum_data)
5354 face->cached_enum_data->elf = *pelf;
5355 face->cached_enum_data->ntm = *pntm;
5356 face->cached_enum_data->type = *ptype;
5359 free_font(font);
5362 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5364 Face *face;
5365 const struct list *face_list;
5367 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5369 face_list = get_face_list_from_family(family);
5370 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5371 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5373 return FALSE;
5376 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5378 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5380 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5383 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5384 FONTENUMPROCW proc, LPARAM lparam)
5386 ENUMLOGFONTEXW elf;
5387 NEWTEXTMETRICEXW ntm;
5388 DWORD type = 0;
5389 DWORD i;
5391 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5392 for(i = 0; i < list->total; i++) {
5393 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5394 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5395 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5396 i = list->total; /* break out of loop after enumeration */
5398 else
5400 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5401 /* use the DEFAULT_CHARSET case only if no other charset is present */
5402 if (list->element[i].charset == DEFAULT_CHARSET &&
5403 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5404 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5405 strcpyW(elf.elfScript, list->element[i].name);
5406 if (!elf.elfScript[0])
5407 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5409 /* Font Replacement */
5410 if (family != face->family)
5412 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5413 if (face->FullName)
5414 strcpyW(elf.elfFullName, face->FullName);
5415 else
5416 strcpyW(elf.elfFullName, family->FamilyName);
5418 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5419 debugstr_w(elf.elfLogFont.lfFaceName),
5420 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5421 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5422 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5423 ntm.ntmTm.ntmFlags);
5424 /* release section before callback (FIXME) */
5425 LeaveCriticalSection( &freetype_cs );
5426 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5427 EnterCriticalSection( &freetype_cs );
5429 return TRUE;
5432 /*************************************************************
5433 * freetype_EnumFonts
5435 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5437 Family *family;
5438 Face *face;
5439 const struct list *face_list;
5440 LOGFONTW lf;
5441 struct enum_charset_list enum_charsets;
5443 if (!plf)
5445 lf.lfCharSet = DEFAULT_CHARSET;
5446 lf.lfPitchAndFamily = 0;
5447 lf.lfFaceName[0] = 0;
5448 plf = &lf;
5451 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5453 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5455 GDI_CheckNotLock();
5456 EnterCriticalSection( &freetype_cs );
5457 if(plf->lfFaceName[0]) {
5458 FontSubst *psub;
5459 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5461 if(psub) {
5462 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5463 debugstr_w(psub->to.name));
5464 lf = *plf;
5465 strcpyW(lf.lfFaceName, psub->to.name);
5466 plf = &lf;
5469 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5470 if (!family_matches(family, plf)) continue;
5471 face_list = get_face_list_from_family(family);
5472 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5473 if (!face_matches(family->FamilyName, face, plf)) continue;
5474 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5477 } else {
5478 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5479 face_list = get_face_list_from_family(family);
5480 face = LIST_ENTRY(list_head(face_list), Face, entry);
5481 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5484 LeaveCriticalSection( &freetype_cs );
5485 return TRUE;
5488 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5490 pt->x.value = vec->x >> 6;
5491 pt->x.fract = (vec->x & 0x3f) << 10;
5492 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5493 pt->y.value = vec->y >> 6;
5494 pt->y.fract = (vec->y & 0x3f) << 10;
5495 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5496 return;
5499 /***************************************************
5500 * According to the MSDN documentation on WideCharToMultiByte,
5501 * certain codepages cannot set the default_used parameter.
5502 * This returns TRUE if the codepage can set that parameter, false else
5503 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5505 static BOOL codepage_sets_default_used(UINT codepage)
5507 switch (codepage)
5509 case CP_UTF7:
5510 case CP_UTF8:
5511 case CP_SYMBOL:
5512 return FALSE;
5513 default:
5514 return TRUE;
5519 * GSUB Table handling functions
5522 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5524 const GSUB_CoverageFormat1* cf1;
5526 cf1 = table;
5528 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5530 int count = GET_BE_WORD(cf1->GlyphCount);
5531 int i;
5532 TRACE("Coverage Format 1, %i glyphs\n",count);
5533 for (i = 0; i < count; i++)
5534 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5535 return i;
5536 return -1;
5538 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5540 const GSUB_CoverageFormat2* cf2;
5541 int i;
5542 int count;
5543 cf2 = (const GSUB_CoverageFormat2*)cf1;
5545 count = GET_BE_WORD(cf2->RangeCount);
5546 TRACE("Coverage Format 2, %i ranges\n",count);
5547 for (i = 0; i < count; i++)
5549 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5550 return -1;
5551 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5552 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5554 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5555 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5558 return -1;
5560 else
5561 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5563 return -1;
5566 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5568 const GSUB_ScriptList *script;
5569 const GSUB_Script *deflt = NULL;
5570 int i;
5571 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5573 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5574 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5576 const GSUB_Script *scr;
5577 int offset;
5579 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5580 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5582 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5583 return scr;
5584 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5585 deflt = scr;
5587 return deflt;
5590 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5592 int i;
5593 int offset;
5594 const GSUB_LangSys *Lang;
5596 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5598 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5600 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5601 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5603 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5604 return Lang;
5606 offset = GET_BE_WORD(script->DefaultLangSys);
5607 if (offset)
5609 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5610 return Lang;
5612 return NULL;
5615 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5617 int i;
5618 const GSUB_FeatureList *feature;
5619 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5621 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5622 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5624 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5625 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5627 const GSUB_Feature *feat;
5628 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5629 return feat;
5632 return NULL;
5635 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5637 int i;
5638 int offset;
5639 const GSUB_LookupList *lookup;
5640 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5642 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5643 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5645 const GSUB_LookupTable *look;
5646 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5647 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5648 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5649 if (GET_BE_WORD(look->LookupType) != 1)
5650 FIXME("We only handle SubType 1\n");
5651 else
5653 int j;
5655 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5657 const GSUB_SingleSubstFormat1 *ssf1;
5658 offset = GET_BE_WORD(look->SubTable[j]);
5659 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5660 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5662 int offset = GET_BE_WORD(ssf1->Coverage);
5663 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5664 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5666 TRACE(" Glyph 0x%x ->",glyph);
5667 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5668 TRACE(" 0x%x\n",glyph);
5671 else
5673 const GSUB_SingleSubstFormat2 *ssf2;
5674 INT index;
5675 INT offset;
5677 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5678 offset = GET_BE_WORD(ssf1->Coverage);
5679 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5680 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5681 TRACE(" Coverage index %i\n",index);
5682 if (index != -1)
5684 TRACE(" Glyph is 0x%x ->",glyph);
5685 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5686 TRACE("0x%x\n",glyph);
5692 return glyph;
5695 static const char* get_opentype_script(const GdiFont *font)
5698 * I am not sure if this is the correct way to generate our script tag
5701 switch (font->charset)
5703 case ANSI_CHARSET: return "latn";
5704 case BALTIC_CHARSET: return "latn"; /* ?? */
5705 case CHINESEBIG5_CHARSET: return "hani";
5706 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5707 case GB2312_CHARSET: return "hani";
5708 case GREEK_CHARSET: return "grek";
5709 case HANGUL_CHARSET: return "hang";
5710 case RUSSIAN_CHARSET: return "cyrl";
5711 case SHIFTJIS_CHARSET: return "kana";
5712 case TURKISH_CHARSET: return "latn"; /* ?? */
5713 case VIETNAMESE_CHARSET: return "latn";
5714 case JOHAB_CHARSET: return "latn"; /* ?? */
5715 case ARABIC_CHARSET: return "arab";
5716 case HEBREW_CHARSET: return "hebr";
5717 case THAI_CHARSET: return "thai";
5718 default: return "latn";
5722 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5724 const GSUB_Header *header;
5725 const GSUB_Script *script;
5726 const GSUB_LangSys *language;
5727 const GSUB_Feature *feature;
5729 if (!font->GSUB_Table)
5730 return glyph;
5732 header = font->GSUB_Table;
5734 script = GSUB_get_script_table(header, get_opentype_script(font));
5735 if (!script)
5737 TRACE("Script not found\n");
5738 return glyph;
5740 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5741 if (!language)
5743 TRACE("Language not found\n");
5744 return glyph;
5746 feature = GSUB_get_feature(header, language, "vrt2");
5747 if (!feature)
5748 feature = GSUB_get_feature(header, language, "vert");
5749 if (!feature)
5751 TRACE("vrt2/vert feature not found\n");
5752 return glyph;
5754 return GSUB_apply_feature(header, feature, glyph);
5757 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5759 FT_UInt glyphId;
5761 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5762 WCHAR wc = (WCHAR)glyph;
5763 BOOL default_used;
5764 BOOL *default_used_pointer;
5765 FT_UInt ret;
5766 char buf;
5767 default_used_pointer = NULL;
5768 default_used = FALSE;
5769 if (codepage_sets_default_used(font->codepage))
5770 default_used_pointer = &default_used;
5771 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5773 if (font->codepage == CP_SYMBOL && wc < 0x100)
5774 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5775 else
5776 ret = 0;
5778 else
5779 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5780 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5781 return ret;
5784 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5786 if (glyph < 0x100) glyph += 0xf000;
5787 /* there is a number of old pre-Unicode "broken" TTFs, which
5788 do have symbols at U+00XX instead of U+f0XX */
5789 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5790 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5792 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5794 return glyphId;
5797 /*************************************************************
5798 * freetype_GetGlyphIndices
5800 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5802 struct freetype_physdev *physdev = get_freetype_dev( dev );
5803 int i;
5804 WORD default_char;
5805 BOOL got_default = FALSE;
5807 if (!physdev->font)
5809 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5810 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5813 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5815 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5816 got_default = TRUE;
5819 GDI_CheckNotLock();
5820 EnterCriticalSection( &freetype_cs );
5822 for(i = 0; i < count; i++)
5824 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5825 if (pgi[i] == 0)
5827 if (!got_default)
5829 if (FT_IS_SFNT(physdev->font->ft_face))
5831 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5832 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5834 else
5836 TEXTMETRICW textm;
5837 get_text_metrics(physdev->font, &textm);
5838 default_char = textm.tmDefaultChar;
5840 got_default = TRUE;
5842 pgi[i] = default_char;
5845 LeaveCriticalSection( &freetype_cs );
5846 return count;
5849 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5851 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5852 return !memcmp(matrix, &identity, sizeof(FMAT2));
5855 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5857 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5858 return !memcmp(matrix, &identity, sizeof(MAT2));
5861 static inline BYTE get_max_level( UINT format )
5863 switch( format )
5865 case GGO_GRAY2_BITMAP: return 4;
5866 case GGO_GRAY4_BITMAP: return 16;
5867 case GGO_GRAY8_BITMAP: return 64;
5869 return 255;
5872 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5874 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5875 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5876 const MAT2* lpmat)
5878 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5879 FT_Face ft_face = incoming_font->ft_face;
5880 GdiFont *font = incoming_font;
5881 FT_Glyph_Metrics metrics;
5882 FT_UInt glyph_index;
5883 DWORD width, height, pitch, needed = 0;
5884 FT_Bitmap ft_bitmap;
5885 FT_Error err;
5886 INT left, right, top = 0, bottom = 0, adv;
5887 FT_Angle angle = 0;
5888 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5889 double widthRatio = 1.0;
5890 FT_Matrix transMat = identityMat;
5891 FT_Matrix transMatUnrotated;
5892 BOOL needsTransform = FALSE;
5893 BOOL tategaki = (font->GSUB_Table != NULL);
5894 UINT original_index;
5895 LONG avgAdvance = 0;
5896 FT_Fixed em_scale;
5898 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5899 buflen, buf, lpmat);
5901 TRACE("font transform %f %f %f %f\n",
5902 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5903 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5905 if(format & GGO_GLYPH_INDEX) {
5906 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5907 original_index = glyph;
5908 format &= ~GGO_GLYPH_INDEX;
5909 } else {
5910 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5911 ft_face = font->ft_face;
5912 original_index = glyph_index;
5915 if(format & GGO_UNHINTED) {
5916 load_flags |= FT_LOAD_NO_HINTING;
5917 format &= ~GGO_UNHINTED;
5920 /* tategaki never appears to happen to lower glyph index */
5921 if (glyph_index < TATEGAKI_LOWER_BOUND )
5922 tategaki = FALSE;
5924 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5925 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5926 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5927 font->gmsize * sizeof(GM*));
5928 } else {
5929 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5930 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5932 *lpgm = FONT_GM(font,original_index)->gm;
5933 *abc = FONT_GM(font,original_index)->abc;
5934 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5935 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5936 lpgm->gmCellIncX, lpgm->gmCellIncY);
5937 return 1; /* FIXME */
5941 if (!font->gm[original_index / GM_BLOCK_SIZE])
5942 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5944 /* Scaling factor */
5945 if (font->aveWidth)
5947 TEXTMETRICW tm;
5949 get_text_metrics(font, &tm);
5951 widthRatio = (double)font->aveWidth;
5952 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5954 else
5955 widthRatio = font->scale_y;
5957 /* Scaling transform */
5958 if (widthRatio != 1.0 || font->scale_y != 1.0)
5960 FT_Matrix scaleMat;
5961 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5962 scaleMat.xy = 0;
5963 scaleMat.yx = 0;
5964 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5966 pFT_Matrix_Multiply(&scaleMat, &transMat);
5967 needsTransform = TRUE;
5970 /* Slant transform */
5971 if (font->fake_italic) {
5972 FT_Matrix slantMat;
5974 slantMat.xx = (1 << 16);
5975 slantMat.xy = ((1 << 16) >> 2);
5976 slantMat.yx = 0;
5977 slantMat.yy = (1 << 16);
5978 pFT_Matrix_Multiply(&slantMat, &transMat);
5979 needsTransform = TRUE;
5982 /* Rotation transform */
5983 transMatUnrotated = transMat;
5984 if(font->orientation && !tategaki) {
5985 FT_Matrix rotationMat;
5986 FT_Vector vecAngle;
5987 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5988 pFT_Vector_Unit(&vecAngle, angle);
5989 rotationMat.xx = vecAngle.x;
5990 rotationMat.xy = -vecAngle.y;
5991 rotationMat.yx = -rotationMat.xy;
5992 rotationMat.yy = rotationMat.xx;
5994 pFT_Matrix_Multiply(&rotationMat, &transMat);
5995 needsTransform = TRUE;
5998 /* World transform */
5999 if (!is_identity_FMAT2(&font->font_desc.matrix))
6001 FT_Matrix worldMat;
6002 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6003 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6004 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6005 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6006 pFT_Matrix_Multiply(&worldMat, &transMat);
6007 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6008 needsTransform = TRUE;
6011 /* Extra transformation specified by caller */
6012 if (!is_identity_MAT2(lpmat))
6014 FT_Matrix extraMat;
6015 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6016 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6017 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6018 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6019 pFT_Matrix_Multiply(&extraMat, &transMat);
6020 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6021 needsTransform = TRUE;
6024 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6026 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6028 if(err) {
6029 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6030 return GDI_ERROR;
6033 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6034 * by the text metrics. The proper behavior is to clip the glyph metrics to
6035 * fit within the maximums specified in the text metrics. */
6036 metrics = ft_face->glyph->metrics;
6037 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6038 get_bitmap_text_metrics(incoming_font)) {
6039 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6040 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6041 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6042 metrics.horiBearingY = top;
6043 metrics.height = top - bottom;
6045 /* TODO: Are we supposed to clip the width as well...? */
6046 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6049 if(FT_IS_SCALABLE(incoming_font->ft_face)) {
6050 TEXTMETRICW tm;
6051 if (get_text_metrics(incoming_font, &tm) &&
6052 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6053 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6054 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6055 if (avgAdvance &&
6056 (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6057 TRACE("Fixed-pitch full-width character detected\n");
6058 else
6059 avgAdvance = 0; /* cancel this feature */
6063 if(!needsTransform) {
6064 left = (INT)(metrics.horiBearingX) & -64;
6065 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6066 if (!avgAdvance)
6067 adv = (INT)(metrics.horiAdvance + 63) >> 6;
6068 else
6069 adv = (INT)avgAdvance * 2;
6071 top = (metrics.horiBearingY + 63) & -64;
6072 bottom = (metrics.horiBearingY - metrics.height) & -64;
6073 lpgm->gmCellIncX = adv;
6074 lpgm->gmCellIncY = 0;
6075 } else {
6076 INT xc, yc;
6077 FT_Vector vec;
6079 left = right = 0;
6081 for(xc = 0; xc < 2; xc++) {
6082 for(yc = 0; yc < 2; yc++) {
6083 vec.x = metrics.horiBearingX + xc * metrics.width;
6084 vec.y = metrics.horiBearingY - yc * metrics.height;
6085 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6086 pFT_Vector_Transform(&vec, &transMat);
6087 if(xc == 0 && yc == 0) {
6088 left = right = vec.x;
6089 top = bottom = vec.y;
6090 } else {
6091 if(vec.x < left) left = vec.x;
6092 else if(vec.x > right) right = vec.x;
6093 if(vec.y < bottom) bottom = vec.y;
6094 else if(vec.y > top) top = vec.y;
6098 left = left & -64;
6099 right = (right + 63) & -64;
6100 bottom = bottom & -64;
6101 top = (top + 63) & -64;
6103 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6104 vec.x = metrics.horiAdvance;
6105 vec.y = 0;
6106 pFT_Vector_Transform(&vec, &transMat);
6107 lpgm->gmCellIncY = -((vec.y+63) >> 6);
6108 if (!avgAdvance || vec.y)
6109 lpgm->gmCellIncX = (vec.x+63) >> 6;
6110 else {
6111 vec.x = incoming_font->ntmAvgWidth;
6112 vec.y = 0;
6113 pFT_Vector_Transform(&vec, &transMat);
6114 lpgm->gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6117 vec.x = metrics.horiAdvance;
6118 vec.y = 0;
6119 pFT_Vector_Transform(&vec, &transMatUnrotated);
6120 if (!avgAdvance || vec.y)
6121 adv = (vec.x+63) >> 6;
6122 else {
6123 vec.x = incoming_font->ntmAvgWidth;
6124 vec.y = 0;
6125 pFT_Vector_Transform(&vec, &transMatUnrotated);
6126 adv = pFT_MulFix(vec.x, em_scale) * 2;
6130 lpgm->gmBlackBoxX = (right - left) >> 6;
6131 lpgm->gmBlackBoxY = (top - bottom) >> 6;
6132 lpgm->gmptGlyphOrigin.x = left >> 6;
6133 lpgm->gmptGlyphOrigin.y = top >> 6;
6134 abc->abcA = left >> 6;
6135 abc->abcB = (right - left) >> 6;
6136 abc->abcC = adv - abc->abcA - abc->abcB;
6138 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6139 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6140 lpgm->gmCellIncX, lpgm->gmCellIncY);
6142 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6143 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6145 FONT_GM(font,original_index)->gm = *lpgm;
6146 FONT_GM(font,original_index)->abc = *abc;
6147 FONT_GM(font,original_index)->init = TRUE;
6150 if(format == GGO_METRICS)
6152 return 1; /* FIXME */
6155 if(ft_face->glyph->format != ft_glyph_format_outline &&
6156 (format == GGO_NATIVE || format == GGO_BEZIER))
6158 TRACE("loaded a bitmap\n");
6159 return GDI_ERROR;
6162 switch(format) {
6163 case GGO_BITMAP:
6164 width = lpgm->gmBlackBoxX;
6165 height = lpgm->gmBlackBoxY;
6166 pitch = ((width + 31) >> 5) << 2;
6167 needed = pitch * height;
6169 if(!buf || !buflen) break;
6171 switch(ft_face->glyph->format) {
6172 case ft_glyph_format_bitmap:
6174 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6175 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
6176 INT h = min( height, ft_face->glyph->bitmap.rows );
6177 while(h--) {
6178 memcpy(dst, src, w);
6179 src += ft_face->glyph->bitmap.pitch;
6180 dst += pitch;
6182 break;
6185 case ft_glyph_format_outline:
6186 ft_bitmap.width = width;
6187 ft_bitmap.rows = height;
6188 ft_bitmap.pitch = pitch;
6189 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6190 ft_bitmap.buffer = buf;
6192 if(needsTransform)
6193 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6195 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6197 /* Note: FreeType will only set 'black' bits for us. */
6198 memset(buf, 0, needed);
6199 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6200 break;
6202 default:
6203 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6204 return GDI_ERROR;
6206 break;
6208 case GGO_GRAY2_BITMAP:
6209 case GGO_GRAY4_BITMAP:
6210 case GGO_GRAY8_BITMAP:
6211 case WINE_GGO_GRAY16_BITMAP:
6213 unsigned int max_level, row, col;
6214 BYTE *start, *ptr;
6216 width = lpgm->gmBlackBoxX;
6217 height = lpgm->gmBlackBoxY;
6218 pitch = (width + 3) / 4 * 4;
6219 needed = pitch * height;
6221 if(!buf || !buflen) break;
6223 max_level = get_max_level( format );
6225 switch(ft_face->glyph->format) {
6226 case ft_glyph_format_bitmap:
6228 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6229 INT h = min( height, ft_face->glyph->bitmap.rows );
6230 INT x;
6231 memset( buf, 0, needed );
6232 while(h--) {
6233 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6234 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6235 src += ft_face->glyph->bitmap.pitch;
6236 dst += pitch;
6238 return needed;
6240 case ft_glyph_format_outline:
6242 ft_bitmap.width = width;
6243 ft_bitmap.rows = height;
6244 ft_bitmap.pitch = pitch;
6245 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6246 ft_bitmap.buffer = buf;
6248 if(needsTransform)
6249 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6251 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6253 memset(ft_bitmap.buffer, 0, buflen);
6255 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6257 if (max_level != 255)
6259 for (row = 0, start = buf; row < height; row++)
6261 for (col = 0, ptr = start; col < width; col++, ptr++)
6262 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6263 start += pitch;
6266 return needed;
6269 default:
6270 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6271 return GDI_ERROR;
6273 break;
6276 case WINE_GGO_HRGB_BITMAP:
6277 case WINE_GGO_HBGR_BITMAP:
6278 case WINE_GGO_VRGB_BITMAP:
6279 case WINE_GGO_VBGR_BITMAP:
6280 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6282 switch (ft_face->glyph->format)
6284 case FT_GLYPH_FORMAT_BITMAP:
6286 BYTE *src, *dst;
6287 INT src_pitch, x;
6289 width = lpgm->gmBlackBoxX;
6290 height = lpgm->gmBlackBoxY;
6291 pitch = width * 4;
6292 needed = pitch * height;
6294 if (!buf || !buflen) break;
6296 memset(buf, 0, buflen);
6297 dst = buf;
6298 src = ft_face->glyph->bitmap.buffer;
6299 src_pitch = ft_face->glyph->bitmap.pitch;
6301 height = min( height, ft_face->glyph->bitmap.rows );
6302 while ( height-- )
6304 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6306 if ( src[x / 8] & masks[x % 8] )
6307 ((unsigned int *)dst)[x] = ~0u;
6309 src += src_pitch;
6310 dst += pitch;
6313 break;
6316 case FT_GLYPH_FORMAT_OUTLINE:
6318 unsigned int *dst;
6319 BYTE *src;
6320 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6321 INT x_shift, y_shift;
6322 BOOL rgb;
6323 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6324 FT_Render_Mode render_mode =
6325 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6326 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6328 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6330 if ( render_mode == FT_RENDER_MODE_LCD)
6332 lpgm->gmBlackBoxX += 2;
6333 lpgm->gmptGlyphOrigin.x -= 1;
6335 else
6337 lpgm->gmBlackBoxY += 2;
6338 lpgm->gmptGlyphOrigin.y += 1;
6342 width = lpgm->gmBlackBoxX;
6343 height = lpgm->gmBlackBoxY;
6344 pitch = width * 4;
6345 needed = pitch * height;
6347 if (!buf || !buflen) break;
6349 memset(buf, 0, buflen);
6350 dst = buf;
6351 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6353 if ( needsTransform )
6354 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6356 if ( pFT_Library_SetLcdFilter )
6357 pFT_Library_SetLcdFilter( library, lcdfilter );
6358 pFT_Render_Glyph (ft_face->glyph, render_mode);
6360 src = ft_face->glyph->bitmap.buffer;
6361 src_pitch = ft_face->glyph->bitmap.pitch;
6362 src_width = ft_face->glyph->bitmap.width;
6363 src_height = ft_face->glyph->bitmap.rows;
6365 if ( render_mode == FT_RENDER_MODE_LCD)
6367 rgb_interval = 1;
6368 hmul = 3;
6369 vmul = 1;
6371 else
6373 rgb_interval = src_pitch;
6374 hmul = 1;
6375 vmul = 3;
6378 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6379 if ( x_shift < 0 )
6381 src += hmul * -x_shift;
6382 src_width -= hmul * -x_shift;
6384 else if ( x_shift > 0 )
6386 dst += x_shift;
6387 width -= x_shift;
6390 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6391 if ( y_shift < 0 )
6393 src += src_pitch * vmul * -y_shift;
6394 src_height -= vmul * -y_shift;
6396 else if ( y_shift > 0 )
6398 dst += y_shift * ( pitch / sizeof(*dst) );
6399 height -= y_shift;
6402 width = min( width, src_width / hmul );
6403 height = min( height, src_height / vmul );
6405 while ( height-- )
6407 for ( x = 0; x < width; x++ )
6409 if ( rgb )
6411 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6412 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6413 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6414 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6416 else
6418 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6419 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6420 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6421 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6424 src += src_pitch * vmul;
6425 dst += pitch / sizeof(*dst);
6428 break;
6431 default:
6432 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6433 return GDI_ERROR;
6436 break;
6438 #else
6439 return GDI_ERROR;
6440 #endif
6442 case GGO_NATIVE:
6444 int contour, point = 0, first_pt;
6445 FT_Outline *outline = &ft_face->glyph->outline;
6446 TTPOLYGONHEADER *pph;
6447 TTPOLYCURVE *ppc;
6448 DWORD pph_start, cpfx, type;
6450 if(buflen == 0) buf = NULL;
6452 if (needsTransform && buf) {
6453 pFT_Outline_Transform(outline, &transMat);
6456 for(contour = 0; contour < outline->n_contours; contour++) {
6457 /* Ignore contours containing one point */
6458 if(point == outline->contours[contour]) {
6459 point++;
6460 continue;
6463 pph_start = needed;
6464 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6465 first_pt = point;
6466 if(buf) {
6467 pph->dwType = TT_POLYGON_TYPE;
6468 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6470 needed += sizeof(*pph);
6471 point++;
6472 while(point <= outline->contours[contour]) {
6473 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6474 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6475 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6476 cpfx = 0;
6477 do {
6478 if(buf)
6479 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6480 cpfx++;
6481 point++;
6482 } while(point <= outline->contours[contour] &&
6483 (outline->tags[point] & FT_Curve_Tag_On) ==
6484 (outline->tags[point-1] & FT_Curve_Tag_On));
6485 /* At the end of a contour Windows adds the start point, but
6486 only for Beziers */
6487 if(point > outline->contours[contour] &&
6488 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6489 if(buf)
6490 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6491 cpfx++;
6492 } else if(point <= outline->contours[contour] &&
6493 outline->tags[point] & FT_Curve_Tag_On) {
6494 /* add closing pt for bezier */
6495 if(buf)
6496 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6497 cpfx++;
6498 point++;
6500 if(buf) {
6501 ppc->wType = type;
6502 ppc->cpfx = cpfx;
6504 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6506 if(buf)
6507 pph->cb = needed - pph_start;
6509 break;
6511 case GGO_BEZIER:
6513 /* Convert the quadratic Beziers to cubic Beziers.
6514 The parametric eqn for a cubic Bezier is, from PLRM:
6515 r(t) = at^3 + bt^2 + ct + r0
6516 with the control points:
6517 r1 = r0 + c/3
6518 r2 = r1 + (c + b)/3
6519 r3 = r0 + c + b + a
6521 A quadratic Bezier has the form:
6522 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6524 So equating powers of t leads to:
6525 r1 = 2/3 p1 + 1/3 p0
6526 r2 = 2/3 p1 + 1/3 p2
6527 and of course r0 = p0, r3 = p2
6530 int contour, point = 0, first_pt;
6531 FT_Outline *outline = &ft_face->glyph->outline;
6532 TTPOLYGONHEADER *pph;
6533 TTPOLYCURVE *ppc;
6534 DWORD pph_start, cpfx, type;
6535 FT_Vector cubic_control[4];
6536 if(buflen == 0) buf = NULL;
6538 if (needsTransform && buf) {
6539 pFT_Outline_Transform(outline, &transMat);
6542 for(contour = 0; contour < outline->n_contours; contour++) {
6543 pph_start = needed;
6544 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6545 first_pt = point;
6546 if(buf) {
6547 pph->dwType = TT_POLYGON_TYPE;
6548 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6550 needed += sizeof(*pph);
6551 point++;
6552 while(point <= outline->contours[contour]) {
6553 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6554 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6555 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6556 cpfx = 0;
6557 do {
6558 if(type == TT_PRIM_LINE) {
6559 if(buf)
6560 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6561 cpfx++;
6562 point++;
6563 } else {
6564 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6565 so cpfx = 3n */
6567 /* FIXME: Possible optimization in endpoint calculation
6568 if there are two consecutive curves */
6569 cubic_control[0] = outline->points[point-1];
6570 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6571 cubic_control[0].x += outline->points[point].x + 1;
6572 cubic_control[0].y += outline->points[point].y + 1;
6573 cubic_control[0].x >>= 1;
6574 cubic_control[0].y >>= 1;
6576 if(point+1 > outline->contours[contour])
6577 cubic_control[3] = outline->points[first_pt];
6578 else {
6579 cubic_control[3] = outline->points[point+1];
6580 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6581 cubic_control[3].x += outline->points[point].x + 1;
6582 cubic_control[3].y += outline->points[point].y + 1;
6583 cubic_control[3].x >>= 1;
6584 cubic_control[3].y >>= 1;
6587 /* r1 = 1/3 p0 + 2/3 p1
6588 r2 = 1/3 p2 + 2/3 p1 */
6589 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6590 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6591 cubic_control[2] = cubic_control[1];
6592 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6593 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6594 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6595 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6596 if(buf) {
6597 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6598 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6599 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6601 cpfx += 3;
6602 point++;
6604 } while(point <= outline->contours[contour] &&
6605 (outline->tags[point] & FT_Curve_Tag_On) ==
6606 (outline->tags[point-1] & FT_Curve_Tag_On));
6607 /* At the end of a contour Windows adds the start point,
6608 but only for Beziers and we've already done that.
6610 if(point <= outline->contours[contour] &&
6611 outline->tags[point] & FT_Curve_Tag_On) {
6612 /* This is the closing pt of a bezier, but we've already
6613 added it, so just inc point and carry on */
6614 point++;
6616 if(buf) {
6617 ppc->wType = type;
6618 ppc->cpfx = cpfx;
6620 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6622 if(buf)
6623 pph->cb = needed - pph_start;
6625 break;
6628 default:
6629 FIXME("Unsupported format %d\n", format);
6630 return GDI_ERROR;
6632 return needed;
6635 static BOOL get_bitmap_text_metrics(GdiFont *font)
6637 FT_Face ft_face = font->ft_face;
6638 FT_WinFNT_HeaderRec winfnt_header;
6639 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6640 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6641 font->potm->otmSize = size;
6643 #define TM font->potm->otmTextMetrics
6644 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6646 TM.tmHeight = winfnt_header.pixel_height;
6647 TM.tmAscent = winfnt_header.ascent;
6648 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6649 TM.tmInternalLeading = winfnt_header.internal_leading;
6650 TM.tmExternalLeading = winfnt_header.external_leading;
6651 TM.tmAveCharWidth = winfnt_header.avg_width;
6652 TM.tmMaxCharWidth = winfnt_header.max_width;
6653 TM.tmWeight = winfnt_header.weight;
6654 TM.tmOverhang = 0;
6655 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6656 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6657 TM.tmFirstChar = winfnt_header.first_char;
6658 TM.tmLastChar = winfnt_header.last_char;
6659 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6660 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6661 TM.tmItalic = winfnt_header.italic;
6662 TM.tmUnderlined = font->underline;
6663 TM.tmStruckOut = font->strikeout;
6664 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6665 TM.tmCharSet = winfnt_header.charset;
6667 else
6669 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6670 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6671 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6672 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6673 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6674 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6675 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6676 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6677 TM.tmOverhang = 0;
6678 TM.tmDigitizedAspectX = 96; /* FIXME */
6679 TM.tmDigitizedAspectY = 96; /* FIXME */
6680 TM.tmFirstChar = 1;
6681 TM.tmLastChar = 255;
6682 TM.tmDefaultChar = 32;
6683 TM.tmBreakChar = 32;
6684 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6685 TM.tmUnderlined = font->underline;
6686 TM.tmStruckOut = font->strikeout;
6687 /* NB inverted meaning of TMPF_FIXED_PITCH */
6688 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6689 TM.tmCharSet = font->charset;
6691 #undef TM
6693 return TRUE;
6697 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6699 double scale_x, scale_y;
6701 if (font->aveWidth)
6703 scale_x = (double)font->aveWidth;
6704 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6706 else
6707 scale_x = font->scale_y;
6709 scale_x *= fabs(font->font_desc.matrix.eM11);
6710 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6712 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6713 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6715 SCALE_Y(ptm->tmHeight);
6716 SCALE_Y(ptm->tmAscent);
6717 SCALE_Y(ptm->tmDescent);
6718 SCALE_Y(ptm->tmInternalLeading);
6719 SCALE_Y(ptm->tmExternalLeading);
6720 SCALE_Y(ptm->tmOverhang);
6722 SCALE_X(ptm->tmAveCharWidth);
6723 SCALE_X(ptm->tmMaxCharWidth);
6725 #undef SCALE_X
6726 #undef SCALE_Y
6729 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6731 double scale_x, scale_y;
6733 if (font->aveWidth)
6735 scale_x = (double)font->aveWidth;
6736 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6738 else
6739 scale_x = font->scale_y;
6741 scale_x *= fabs(font->font_desc.matrix.eM11);
6742 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6744 scale_font_metrics(font, &potm->otmTextMetrics);
6746 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6747 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6749 SCALE_Y(potm->otmAscent);
6750 SCALE_Y(potm->otmDescent);
6751 SCALE_Y(potm->otmLineGap);
6752 SCALE_Y(potm->otmsCapEmHeight);
6753 SCALE_Y(potm->otmsXHeight);
6754 SCALE_Y(potm->otmrcFontBox.top);
6755 SCALE_Y(potm->otmrcFontBox.bottom);
6756 SCALE_X(potm->otmrcFontBox.left);
6757 SCALE_X(potm->otmrcFontBox.right);
6758 SCALE_Y(potm->otmMacAscent);
6759 SCALE_Y(potm->otmMacDescent);
6760 SCALE_Y(potm->otmMacLineGap);
6761 SCALE_X(potm->otmptSubscriptSize.x);
6762 SCALE_Y(potm->otmptSubscriptSize.y);
6763 SCALE_X(potm->otmptSubscriptOffset.x);
6764 SCALE_Y(potm->otmptSubscriptOffset.y);
6765 SCALE_X(potm->otmptSuperscriptSize.x);
6766 SCALE_Y(potm->otmptSuperscriptSize.y);
6767 SCALE_X(potm->otmptSuperscriptOffset.x);
6768 SCALE_Y(potm->otmptSuperscriptOffset.y);
6769 SCALE_Y(potm->otmsStrikeoutSize);
6770 SCALE_Y(potm->otmsStrikeoutPosition);
6771 SCALE_Y(potm->otmsUnderscoreSize);
6772 SCALE_Y(potm->otmsUnderscorePosition);
6774 #undef SCALE_X
6775 #undef SCALE_Y
6778 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6780 if(!font->potm)
6782 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6784 /* Make sure that the font has sane width/height ratio */
6785 if (font->aveWidth)
6787 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6789 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6790 font->aveWidth = 0;
6794 *ptm = font->potm->otmTextMetrics;
6795 scale_font_metrics(font, ptm);
6796 return TRUE;
6799 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6801 int i;
6803 for(i = 0; i < ft_face->num_charmaps; i++)
6805 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6806 return TRUE;
6808 return FALSE;
6811 static BOOL get_outline_text_metrics(GdiFont *font)
6813 BOOL ret = FALSE;
6814 FT_Face ft_face = font->ft_face;
6815 UINT needed, lenfam, lensty, lenface, lenfull;
6816 TT_OS2 *pOS2;
6817 TT_HoriHeader *pHori;
6818 TT_Postscript *pPost;
6819 FT_Fixed em_scale;
6820 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6821 char *cp;
6822 INT ascent, descent;
6824 TRACE("font=%p\n", font);
6826 if(!FT_IS_SCALABLE(ft_face))
6827 return FALSE;
6829 needed = sizeof(*font->potm);
6831 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6832 family_nameW = strdupW(font->name);
6834 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6835 if (!style_nameW)
6836 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6837 if (!style_nameW)
6839 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6840 style_nameW = towstr( CP_ACP, ft_face->style_name );
6842 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6844 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6845 if (!face_nameW)
6846 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6847 if (!face_nameW)
6849 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6850 face_nameW = strdupW(font->name);
6852 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6853 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6855 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6856 if (!full_nameW)
6857 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6858 if (!full_nameW)
6860 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6861 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6862 full_nameW = strdupW(fake_nameW);
6864 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6866 /* These names should be read from the TT name table */
6868 /* length of otmpFamilyName */
6869 needed += lenfam;
6871 /* length of otmpFaceName */
6872 needed += lenface;
6874 /* length of otmpStyleName */
6875 needed += lensty;
6877 /* length of otmpFullName */
6878 needed += lenfull;
6881 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
6883 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6884 if(!pOS2) {
6885 FIXME("Can't find OS/2 table - not TT font?\n");
6886 goto end;
6889 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6890 if(!pHori) {
6891 FIXME("Can't find HHEA table - not TT font?\n");
6892 goto end;
6895 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6897 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",
6898 pOS2->usWinAscent, pOS2->usWinDescent,
6899 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6900 pOS2->xAvgCharWidth,
6901 ft_face->ascender, ft_face->descender, ft_face->height,
6902 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6903 ft_face->bbox.yMax, ft_face->bbox.yMin);
6905 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6906 font->potm->otmSize = needed;
6908 #define TM font->potm->otmTextMetrics
6910 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6911 ascent = pHori->Ascender;
6912 descent = -pHori->Descender;
6913 } else {
6914 ascent = pOS2->usWinAscent;
6915 descent = pOS2->usWinDescent;
6918 font->ntmCellHeight = ascent + descent;
6919 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6921 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
6922 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
6924 if(font->yMax) {
6925 TM.tmAscent = font->yMax;
6926 TM.tmDescent = -font->yMin;
6927 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6928 } else {
6929 TM.tmAscent = SCALE_Y(ascent);
6930 TM.tmDescent = SCALE_Y(descent);
6931 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
6934 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6936 /* MSDN says:
6937 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6939 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
6940 ((ascent + descent) -
6941 (pHori->Ascender - pHori->Descender))));
6943 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
6944 if (TM.tmAveCharWidth == 0) {
6945 TM.tmAveCharWidth = 1;
6947 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
6948 TM.tmWeight = FW_REGULAR;
6949 if (font->fake_bold)
6950 TM.tmWeight = FW_BOLD;
6951 else
6953 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6955 if (pOS2->usWeightClass > FW_MEDIUM)
6956 TM.tmWeight = pOS2->usWeightClass;
6958 else if (pOS2->usWeightClass <= FW_MEDIUM)
6959 TM.tmWeight = pOS2->usWeightClass;
6961 TM.tmOverhang = 0;
6962 TM.tmDigitizedAspectX = 96; /* FIXME */
6963 TM.tmDigitizedAspectY = 96; /* FIXME */
6964 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6965 * symbol range to 0 - f0ff
6968 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6970 TM.tmFirstChar = 0;
6971 switch(GetACP())
6973 case 1257: /* Baltic */
6974 TM.tmLastChar = 0xf8fd;
6975 break;
6976 default:
6977 TM.tmLastChar = 0xf0ff;
6979 TM.tmBreakChar = 0x20;
6980 TM.tmDefaultChar = 0x1f;
6982 else
6984 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6985 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6987 if(pOS2->usFirstCharIndex <= 1)
6988 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6989 else if (pOS2->usFirstCharIndex > 0xff)
6990 TM.tmBreakChar = 0x20;
6991 else
6992 TM.tmBreakChar = pOS2->usFirstCharIndex;
6993 TM.tmDefaultChar = TM.tmBreakChar - 1;
6995 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6996 TM.tmUnderlined = font->underline;
6997 TM.tmStruckOut = font->strikeout;
6999 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7000 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7001 (pOS2->version == 0xFFFFU ||
7002 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7003 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7004 else
7005 TM.tmPitchAndFamily = 0;
7007 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7009 case PAN_FAMILY_SCRIPT:
7010 TM.tmPitchAndFamily |= FF_SCRIPT;
7011 break;
7013 case PAN_FAMILY_DECORATIVE:
7014 TM.tmPitchAndFamily |= FF_DECORATIVE;
7015 break;
7017 case PAN_ANY:
7018 case PAN_NO_FIT:
7019 case PAN_FAMILY_TEXT_DISPLAY:
7020 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7021 /* which is clearly not what the panose spec says. */
7022 default:
7023 if(TM.tmPitchAndFamily == 0 || /* fixed */
7024 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7025 TM.tmPitchAndFamily = FF_MODERN;
7026 else
7028 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7030 case PAN_ANY:
7031 case PAN_NO_FIT:
7032 default:
7033 TM.tmPitchAndFamily |= FF_DONTCARE;
7034 break;
7036 case PAN_SERIF_COVE:
7037 case PAN_SERIF_OBTUSE_COVE:
7038 case PAN_SERIF_SQUARE_COVE:
7039 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7040 case PAN_SERIF_SQUARE:
7041 case PAN_SERIF_THIN:
7042 case PAN_SERIF_BONE:
7043 case PAN_SERIF_EXAGGERATED:
7044 case PAN_SERIF_TRIANGLE:
7045 TM.tmPitchAndFamily |= FF_ROMAN;
7046 break;
7048 case PAN_SERIF_NORMAL_SANS:
7049 case PAN_SERIF_OBTUSE_SANS:
7050 case PAN_SERIF_PERP_SANS:
7051 case PAN_SERIF_FLARED:
7052 case PAN_SERIF_ROUNDED:
7053 TM.tmPitchAndFamily |= FF_SWISS;
7054 break;
7057 break;
7060 if(FT_IS_SCALABLE(ft_face))
7061 TM.tmPitchAndFamily |= TMPF_VECTOR;
7063 if(FT_IS_SFNT(ft_face))
7065 if (font->ntmFlags & NTM_PS_OPENTYPE)
7066 TM.tmPitchAndFamily |= TMPF_DEVICE;
7067 else
7068 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7071 TM.tmCharSet = font->charset;
7073 font->potm->otmFiller = 0;
7074 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7075 font->potm->otmfsSelection = pOS2->fsSelection;
7076 font->potm->otmfsType = pOS2->fsType;
7077 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7078 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7079 font->potm->otmItalicAngle = 0; /* POST table */
7080 font->potm->otmEMSquare = ft_face->units_per_EM;
7081 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7082 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7083 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7084 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7085 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7086 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7087 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7088 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7089 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7090 font->potm->otmMacAscent = TM.tmAscent;
7091 font->potm->otmMacDescent = -TM.tmDescent;
7092 font->potm->otmMacLineGap = font->potm->otmLineGap;
7093 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7094 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7095 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7096 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7097 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7098 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7099 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7100 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7101 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7102 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7103 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7104 if(!pPost) {
7105 font->potm->otmsUnderscoreSize = 0;
7106 font->potm->otmsUnderscorePosition = 0;
7107 } else {
7108 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7109 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7111 #undef SCALE_X
7112 #undef SCALE_Y
7113 #undef TM
7115 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7116 cp = (char*)font->potm + sizeof(*font->potm);
7117 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7118 strcpyW((WCHAR*)cp, family_nameW);
7119 cp += lenfam;
7120 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7121 strcpyW((WCHAR*)cp, style_nameW);
7122 cp += lensty;
7123 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7124 strcpyW((WCHAR*)cp, face_nameW);
7125 cp += lenface;
7126 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7127 strcpyW((WCHAR*)cp, full_nameW);
7128 ret = TRUE;
7130 end:
7131 HeapFree(GetProcessHeap(), 0, style_nameW);
7132 HeapFree(GetProcessHeap(), 0, family_nameW);
7133 HeapFree(GetProcessHeap(), 0, face_nameW);
7134 HeapFree(GetProcessHeap(), 0, full_nameW);
7135 return ret;
7138 /*************************************************************
7139 * freetype_GetGlyphOutline
7141 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7142 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7144 struct freetype_physdev *physdev = get_freetype_dev( dev );
7145 DWORD ret;
7146 ABC abc;
7148 if (!physdev->font)
7150 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7151 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7154 GDI_CheckNotLock();
7155 EnterCriticalSection( &freetype_cs );
7156 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7157 LeaveCriticalSection( &freetype_cs );
7158 return ret;
7161 /*************************************************************
7162 * freetype_GetTextMetrics
7164 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7166 struct freetype_physdev *physdev = get_freetype_dev( dev );
7167 BOOL ret;
7169 if (!physdev->font)
7171 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7172 return dev->funcs->pGetTextMetrics( dev, metrics );
7175 GDI_CheckNotLock();
7176 EnterCriticalSection( &freetype_cs );
7177 ret = get_text_metrics( physdev->font, metrics );
7178 LeaveCriticalSection( &freetype_cs );
7179 return ret;
7182 /*************************************************************
7183 * freetype_GetOutlineTextMetrics
7185 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7187 struct freetype_physdev *physdev = get_freetype_dev( dev );
7188 UINT ret = 0;
7190 if (!physdev->font)
7192 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7193 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7196 TRACE("font=%p\n", physdev->font);
7198 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7200 GDI_CheckNotLock();
7201 EnterCriticalSection( &freetype_cs );
7203 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7205 if(cbSize >= physdev->font->potm->otmSize)
7207 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7208 scale_outline_font_metrics(physdev->font, potm);
7210 ret = physdev->font->potm->otmSize;
7212 LeaveCriticalSection( &freetype_cs );
7213 return ret;
7216 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7218 child->font = alloc_font();
7219 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7220 if(!child->font->ft_face)
7222 free_font(child->font);
7223 child->font = NULL;
7224 return FALSE;
7227 child->font->font_desc = font->font_desc;
7228 child->font->ntmFlags = child->face->ntmFlags;
7229 child->font->orientation = font->orientation;
7230 child->font->scale_y = font->scale_y;
7231 child->font->name = strdupW(child->face->family->FamilyName);
7232 child->font->base_font = font;
7233 TRACE("created child font %p for base %p\n", child->font, font);
7234 return TRUE;
7237 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7239 FT_UInt g;
7240 CHILD_FONT *child_font;
7242 if(font->base_font)
7243 font = font->base_font;
7245 *linked_font = font;
7247 if((*glyph = get_glyph_index(font, c)))
7249 *glyph = get_GSUB_vert_glyph(font, *glyph);
7250 return TRUE;
7253 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7255 if(!child_font->font)
7256 if(!load_child_font(font, child_font))
7257 continue;
7259 if(!child_font->font->ft_face)
7260 continue;
7261 g = get_glyph_index(child_font->font, c);
7262 g = get_GSUB_vert_glyph(child_font->font, g);
7263 if(g)
7265 *glyph = g;
7266 *linked_font = child_font->font;
7267 return TRUE;
7270 return FALSE;
7273 /*************************************************************
7274 * freetype_GetCharWidth
7276 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7278 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7279 UINT c;
7280 GLYPHMETRICS gm;
7281 ABC abc;
7282 struct freetype_physdev *physdev = get_freetype_dev( dev );
7284 if (!physdev->font)
7286 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7287 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7290 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7292 GDI_CheckNotLock();
7293 EnterCriticalSection( &freetype_cs );
7294 for(c = firstChar; c <= lastChar; c++) {
7295 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7296 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7298 LeaveCriticalSection( &freetype_cs );
7299 return TRUE;
7302 /*************************************************************
7303 * freetype_GetCharABCWidths
7305 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7307 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7308 UINT c;
7309 GLYPHMETRICS gm;
7310 struct freetype_physdev *physdev = get_freetype_dev( dev );
7312 if (!physdev->font)
7314 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7315 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7318 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7320 GDI_CheckNotLock();
7321 EnterCriticalSection( &freetype_cs );
7323 for(c = firstChar; c <= lastChar; c++, buffer++)
7324 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7326 LeaveCriticalSection( &freetype_cs );
7327 return TRUE;
7330 /*************************************************************
7331 * freetype_GetCharABCWidthsI
7333 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7335 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7336 UINT c;
7337 GLYPHMETRICS gm;
7338 struct freetype_physdev *physdev = get_freetype_dev( dev );
7340 if (!physdev->font)
7342 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7343 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7346 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7347 return FALSE;
7349 GDI_CheckNotLock();
7350 EnterCriticalSection( &freetype_cs );
7352 for(c = 0; c < count; c++, buffer++)
7353 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7354 &gm, buffer, 0, NULL, &identity );
7356 LeaveCriticalSection( &freetype_cs );
7357 return TRUE;
7360 /*************************************************************
7361 * freetype_GetTextExtentExPoint
7363 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7365 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7366 INT idx, pos;
7367 ABC abc;
7368 GLYPHMETRICS gm;
7369 struct freetype_physdev *physdev = get_freetype_dev( dev );
7371 if (!physdev->font)
7373 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7374 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7377 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7379 GDI_CheckNotLock();
7380 EnterCriticalSection( &freetype_cs );
7382 for (idx = pos = 0; idx < count; idx++)
7384 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7385 pos += abc.abcA + abc.abcB + abc.abcC;
7386 dxs[idx] = pos;
7389 LeaveCriticalSection( &freetype_cs );
7390 return TRUE;
7393 /*************************************************************
7394 * freetype_GetTextExtentExPointI
7396 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7398 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7399 INT idx, pos;
7400 ABC abc;
7401 GLYPHMETRICS gm;
7402 struct freetype_physdev *physdev = get_freetype_dev( dev );
7404 if (!physdev->font)
7406 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7407 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7410 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7412 GDI_CheckNotLock();
7413 EnterCriticalSection( &freetype_cs );
7415 for (idx = pos = 0; idx < count; idx++)
7417 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7418 &gm, &abc, 0, NULL, &identity );
7419 pos += abc.abcA + abc.abcB + abc.abcC;
7420 dxs[idx] = pos;
7423 LeaveCriticalSection( &freetype_cs );
7424 return TRUE;
7427 /*************************************************************
7428 * freetype_GetFontData
7430 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7432 struct freetype_physdev *physdev = get_freetype_dev( dev );
7434 if (!physdev->font)
7436 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7437 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7440 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7441 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7442 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7444 return get_font_data( physdev->font, table, offset, buf, cbData );
7447 /*************************************************************
7448 * freetype_GetTextFace
7450 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7452 INT n;
7453 struct freetype_physdev *physdev = get_freetype_dev( dev );
7455 if (!physdev->font)
7457 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7458 return dev->funcs->pGetTextFace( dev, count, str );
7461 n = strlenW(physdev->font->name) + 1;
7462 if (str)
7464 lstrcpynW(str, physdev->font->name, count);
7465 n = min(count, n);
7467 return n;
7470 /*************************************************************
7471 * freetype_GetTextCharsetInfo
7473 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7475 struct freetype_physdev *physdev = get_freetype_dev( dev );
7477 if (!physdev->font)
7479 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7480 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7482 if (fs) *fs = physdev->font->fs;
7483 return physdev->font->charset;
7486 /* Retrieve a list of supported Unicode ranges for a given font.
7487 * Can be called with NULL gs to calculate the buffer size. Returns
7488 * the number of ranges found.
7490 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7492 DWORD num_ranges = 0;
7494 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7496 FT_UInt glyph_code;
7497 FT_ULong char_code, char_code_prev;
7499 glyph_code = 0;
7500 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7502 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7503 face->num_glyphs, glyph_code, char_code);
7505 if (!glyph_code) return 0;
7507 if (gs)
7509 gs->ranges[0].wcLow = (USHORT)char_code;
7510 gs->ranges[0].cGlyphs = 0;
7511 gs->cGlyphsSupported = 0;
7514 num_ranges = 1;
7515 while (glyph_code)
7517 if (char_code < char_code_prev)
7519 ERR("expected increasing char code from FT_Get_Next_Char\n");
7520 return 0;
7522 if (char_code - char_code_prev > 1)
7524 num_ranges++;
7525 if (gs)
7527 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7528 gs->ranges[num_ranges - 1].cGlyphs = 1;
7529 gs->cGlyphsSupported++;
7532 else if (gs)
7534 gs->ranges[num_ranges - 1].cGlyphs++;
7535 gs->cGlyphsSupported++;
7537 char_code_prev = char_code;
7538 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7541 else
7542 FIXME("encoding %u not supported\n", face->charmap->encoding);
7544 return num_ranges;
7547 /*************************************************************
7548 * freetype_GetFontUnicodeRanges
7550 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7552 struct freetype_physdev *physdev = get_freetype_dev( dev );
7553 DWORD size, num_ranges;
7555 if (!physdev->font)
7557 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7558 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7561 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7562 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7563 if (glyphset)
7565 glyphset->cbThis = size;
7566 glyphset->cRanges = num_ranges;
7567 glyphset->flAccel = 0;
7569 return size;
7572 /*************************************************************
7573 * freetype_FontIsLinked
7575 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7577 struct freetype_physdev *physdev = get_freetype_dev( dev );
7578 BOOL ret;
7580 if (!physdev->font)
7582 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7583 return dev->funcs->pFontIsLinked( dev );
7586 GDI_CheckNotLock();
7587 EnterCriticalSection( &freetype_cs );
7588 ret = !list_empty(&physdev->font->child_fonts);
7589 LeaveCriticalSection( &freetype_cs );
7590 return ret;
7593 /*************************************************************************
7594 * GetRasterizerCaps (GDI32.@)
7596 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7598 lprs->nSize = sizeof(RASTERIZER_STATUS);
7599 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7600 lprs->nLanguageID = 0;
7601 return TRUE;
7604 /*************************************************************
7605 * freetype_GdiRealizationInfo
7607 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7609 struct freetype_physdev *physdev = get_freetype_dev( dev );
7610 realization_info_t *info = ptr;
7612 if (!physdev->font)
7614 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7615 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7618 FIXME("(%p, %p): stub!\n", physdev->font, info);
7620 info->flags = 1;
7621 if(FT_IS_SCALABLE(physdev->font->ft_face))
7622 info->flags |= 2;
7624 info->cache_num = physdev->font->cache_num;
7625 info->unknown2 = -1;
7626 return TRUE;
7629 /*************************************************************************
7630 * Kerning support for TrueType fonts
7632 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7634 struct TT_kern_table
7636 USHORT version;
7637 USHORT nTables;
7640 struct TT_kern_subtable
7642 USHORT version;
7643 USHORT length;
7644 union
7646 USHORT word;
7647 struct
7649 USHORT horizontal : 1;
7650 USHORT minimum : 1;
7651 USHORT cross_stream: 1;
7652 USHORT override : 1;
7653 USHORT reserved1 : 4;
7654 USHORT format : 8;
7655 } bits;
7656 } coverage;
7659 struct TT_format0_kern_subtable
7661 USHORT nPairs;
7662 USHORT searchRange;
7663 USHORT entrySelector;
7664 USHORT rangeShift;
7667 struct TT_kern_pair
7669 USHORT left;
7670 USHORT right;
7671 short value;
7674 static DWORD parse_format0_kern_subtable(GdiFont *font,
7675 const struct TT_format0_kern_subtable *tt_f0_ks,
7676 const USHORT *glyph_to_char,
7677 KERNINGPAIR *kern_pair, DWORD cPairs)
7679 USHORT i, nPairs;
7680 const struct TT_kern_pair *tt_kern_pair;
7682 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7684 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7686 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7687 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7688 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7690 if (!kern_pair || !cPairs)
7691 return nPairs;
7693 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7695 nPairs = min(nPairs, cPairs);
7697 for (i = 0; i < nPairs; i++)
7699 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7700 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7701 /* this algorithm appears to better match what Windows does */
7702 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7703 if (kern_pair->iKernAmount < 0)
7705 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7706 kern_pair->iKernAmount -= font->ppem;
7708 else if (kern_pair->iKernAmount > 0)
7710 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7711 kern_pair->iKernAmount += font->ppem;
7713 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7715 TRACE("left %u right %u value %d\n",
7716 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7718 kern_pair++;
7720 TRACE("copied %u entries\n", nPairs);
7721 return nPairs;
7724 /*************************************************************
7725 * freetype_GetKerningPairs
7727 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7729 DWORD length;
7730 void *buf;
7731 const struct TT_kern_table *tt_kern_table;
7732 const struct TT_kern_subtable *tt_kern_subtable;
7733 USHORT i, nTables;
7734 USHORT *glyph_to_char;
7735 GdiFont *font;
7736 struct freetype_physdev *physdev = get_freetype_dev( dev );
7738 if (!(font = physdev->font))
7740 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7741 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7744 GDI_CheckNotLock();
7745 EnterCriticalSection( &freetype_cs );
7746 if (font->total_kern_pairs != (DWORD)-1)
7748 if (cPairs && kern_pair)
7750 cPairs = min(cPairs, font->total_kern_pairs);
7751 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7753 else cPairs = font->total_kern_pairs;
7755 LeaveCriticalSection( &freetype_cs );
7756 return cPairs;
7759 font->total_kern_pairs = 0;
7761 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7763 if (length == GDI_ERROR)
7765 TRACE("no kerning data in the font\n");
7766 LeaveCriticalSection( &freetype_cs );
7767 return 0;
7770 buf = HeapAlloc(GetProcessHeap(), 0, length);
7771 if (!buf)
7773 WARN("Out of memory\n");
7774 LeaveCriticalSection( &freetype_cs );
7775 return 0;
7778 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7780 /* build a glyph index to char code map */
7781 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7782 if (!glyph_to_char)
7784 WARN("Out of memory allocating a glyph index to char code map\n");
7785 HeapFree(GetProcessHeap(), 0, buf);
7786 LeaveCriticalSection( &freetype_cs );
7787 return 0;
7790 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7792 FT_UInt glyph_code;
7793 FT_ULong char_code;
7795 glyph_code = 0;
7796 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7798 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7799 font->ft_face->num_glyphs, glyph_code, char_code);
7801 while (glyph_code)
7803 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7805 /* FIXME: This doesn't match what Windows does: it does some fancy
7806 * things with duplicate glyph index to char code mappings, while
7807 * we just avoid overriding existing entries.
7809 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7810 glyph_to_char[glyph_code] = (USHORT)char_code;
7812 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7815 else
7817 ULONG n;
7819 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7820 for (n = 0; n <= 65535; n++)
7821 glyph_to_char[n] = (USHORT)n;
7824 tt_kern_table = buf;
7825 nTables = GET_BE_WORD(tt_kern_table->nTables);
7826 TRACE("version %u, nTables %u\n",
7827 GET_BE_WORD(tt_kern_table->version), nTables);
7829 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7831 for (i = 0; i < nTables; i++)
7833 struct TT_kern_subtable tt_kern_subtable_copy;
7835 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7836 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7837 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7839 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7840 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7841 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7843 /* According to the TrueType specification this is the only format
7844 * that will be properly interpreted by Windows and OS/2
7846 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7848 DWORD new_chunk, old_total = font->total_kern_pairs;
7850 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7851 glyph_to_char, NULL, 0);
7852 font->total_kern_pairs += new_chunk;
7854 if (!font->kern_pairs)
7855 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7856 font->total_kern_pairs * sizeof(*font->kern_pairs));
7857 else
7858 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7859 font->total_kern_pairs * sizeof(*font->kern_pairs));
7861 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7862 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7864 else
7865 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7867 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7870 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7871 HeapFree(GetProcessHeap(), 0, buf);
7873 if (cPairs && kern_pair)
7875 cPairs = min(cPairs, font->total_kern_pairs);
7876 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7878 else cPairs = font->total_kern_pairs;
7880 LeaveCriticalSection( &freetype_cs );
7881 return cPairs;
7884 static const struct gdi_dc_funcs freetype_funcs =
7886 NULL, /* pAbortDoc */
7887 NULL, /* pAbortPath */
7888 NULL, /* pAlphaBlend */
7889 NULL, /* pAngleArc */
7890 NULL, /* pArc */
7891 NULL, /* pArcTo */
7892 NULL, /* pBeginPath */
7893 NULL, /* pBlendImage */
7894 NULL, /* pChord */
7895 NULL, /* pCloseFigure */
7896 NULL, /* pCreateCompatibleDC */
7897 freetype_CreateDC, /* pCreateDC */
7898 freetype_DeleteDC, /* pDeleteDC */
7899 NULL, /* pDeleteObject */
7900 NULL, /* pDeviceCapabilities */
7901 NULL, /* pEllipse */
7902 NULL, /* pEndDoc */
7903 NULL, /* pEndPage */
7904 NULL, /* pEndPath */
7905 freetype_EnumFonts, /* pEnumFonts */
7906 NULL, /* pEnumICMProfiles */
7907 NULL, /* pExcludeClipRect */
7908 NULL, /* pExtDeviceMode */
7909 NULL, /* pExtEscape */
7910 NULL, /* pExtFloodFill */
7911 NULL, /* pExtSelectClipRgn */
7912 NULL, /* pExtTextOut */
7913 NULL, /* pFillPath */
7914 NULL, /* pFillRgn */
7915 NULL, /* pFlattenPath */
7916 freetype_FontIsLinked, /* pFontIsLinked */
7917 NULL, /* pFrameRgn */
7918 NULL, /* pGdiComment */
7919 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7920 NULL, /* pGetBoundsRect */
7921 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7922 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7923 freetype_GetCharWidth, /* pGetCharWidth */
7924 NULL, /* pGetDeviceCaps */
7925 NULL, /* pGetDeviceGammaRamp */
7926 freetype_GetFontData, /* pGetFontData */
7927 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7928 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7929 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7930 NULL, /* pGetICMProfile */
7931 NULL, /* pGetImage */
7932 freetype_GetKerningPairs, /* pGetKerningPairs */
7933 NULL, /* pGetNearestColor */
7934 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7935 NULL, /* pGetPixel */
7936 NULL, /* pGetSystemPaletteEntries */
7937 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7938 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7939 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7940 freetype_GetTextFace, /* pGetTextFace */
7941 freetype_GetTextMetrics, /* pGetTextMetrics */
7942 NULL, /* pGradientFill */
7943 NULL, /* pIntersectClipRect */
7944 NULL, /* pInvertRgn */
7945 NULL, /* pLineTo */
7946 NULL, /* pModifyWorldTransform */
7947 NULL, /* pMoveTo */
7948 NULL, /* pOffsetClipRgn */
7949 NULL, /* pOffsetViewportOrg */
7950 NULL, /* pOffsetWindowOrg */
7951 NULL, /* pPaintRgn */
7952 NULL, /* pPatBlt */
7953 NULL, /* pPie */
7954 NULL, /* pPolyBezier */
7955 NULL, /* pPolyBezierTo */
7956 NULL, /* pPolyDraw */
7957 NULL, /* pPolyPolygon */
7958 NULL, /* pPolyPolyline */
7959 NULL, /* pPolygon */
7960 NULL, /* pPolyline */
7961 NULL, /* pPolylineTo */
7962 NULL, /* pPutImage */
7963 NULL, /* pRealizeDefaultPalette */
7964 NULL, /* pRealizePalette */
7965 NULL, /* pRectangle */
7966 NULL, /* pResetDC */
7967 NULL, /* pRestoreDC */
7968 NULL, /* pRoundRect */
7969 NULL, /* pSaveDC */
7970 NULL, /* pScaleViewportExt */
7971 NULL, /* pScaleWindowExt */
7972 NULL, /* pSelectBitmap */
7973 NULL, /* pSelectBrush */
7974 NULL, /* pSelectClipPath */
7975 freetype_SelectFont, /* pSelectFont */
7976 NULL, /* pSelectPalette */
7977 NULL, /* pSelectPen */
7978 NULL, /* pSetArcDirection */
7979 NULL, /* pSetBkColor */
7980 NULL, /* pSetBkMode */
7981 NULL, /* pSetDCBrushColor */
7982 NULL, /* pSetDCPenColor */
7983 NULL, /* pSetDIBColorTable */
7984 NULL, /* pSetDIBitsToDevice */
7985 NULL, /* pSetDeviceClipping */
7986 NULL, /* pSetDeviceGammaRamp */
7987 NULL, /* pSetLayout */
7988 NULL, /* pSetMapMode */
7989 NULL, /* pSetMapperFlags */
7990 NULL, /* pSetPixel */
7991 NULL, /* pSetPolyFillMode */
7992 NULL, /* pSetROP2 */
7993 NULL, /* pSetRelAbs */
7994 NULL, /* pSetStretchBltMode */
7995 NULL, /* pSetTextAlign */
7996 NULL, /* pSetTextCharacterExtra */
7997 NULL, /* pSetTextColor */
7998 NULL, /* pSetTextJustification */
7999 NULL, /* pSetViewportExt */
8000 NULL, /* pSetViewportOrg */
8001 NULL, /* pSetWindowExt */
8002 NULL, /* pSetWindowOrg */
8003 NULL, /* pSetWorldTransform */
8004 NULL, /* pStartDoc */
8005 NULL, /* pStartPage */
8006 NULL, /* pStretchBlt */
8007 NULL, /* pStretchDIBits */
8008 NULL, /* pStrokeAndFillPath */
8009 NULL, /* pStrokePath */
8010 NULL, /* pUnrealizePalette */
8011 NULL, /* pWidenPath */
8012 NULL, /* wine_get_wgl_driver */
8013 GDI_PRIORITY_FONT_DRV /* priority */
8016 #else /* HAVE_FREETYPE */
8018 /*************************************************************************/
8020 BOOL WineEngInit(void)
8022 return FALSE;
8025 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8027 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8028 return 1;
8031 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8033 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8034 return TRUE;
8037 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8039 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8040 return NULL;
8043 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8044 LPCWSTR font_file, LPCWSTR font_path )
8046 FIXME("stub\n");
8047 return FALSE;
8050 /*************************************************************************
8051 * GetRasterizerCaps (GDI32.@)
8053 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8055 lprs->nSize = sizeof(RASTERIZER_STATUS);
8056 lprs->wFlags = 0;
8057 lprs->nLanguageID = 0;
8058 return TRUE;
8061 #endif /* HAVE_FREETYPE */