gdi32: GetGlyphIndices does substitute glyph.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blobae48914f0b7d0c564088a10b0e6054c1f38bde50
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;
5844 else
5845 pgi[i] = get_GSUB_vert_glyph(physdev->font, pgi[i]);
5847 LeaveCriticalSection( &freetype_cs );
5848 return count;
5851 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5853 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5854 return !memcmp(matrix, &identity, sizeof(FMAT2));
5857 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5859 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5860 return !memcmp(matrix, &identity, sizeof(MAT2));
5863 static inline BYTE get_max_level( UINT format )
5865 switch( format )
5867 case GGO_GRAY2_BITMAP: return 4;
5868 case GGO_GRAY4_BITMAP: return 16;
5869 case GGO_GRAY8_BITMAP: return 64;
5871 return 255;
5874 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5876 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5877 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5878 const MAT2* lpmat)
5880 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5881 FT_Face ft_face = incoming_font->ft_face;
5882 GdiFont *font = incoming_font;
5883 FT_Glyph_Metrics metrics;
5884 FT_UInt glyph_index;
5885 DWORD width, height, pitch, needed = 0;
5886 FT_Bitmap ft_bitmap;
5887 FT_Error err;
5888 INT left, right, top = 0, bottom = 0, adv;
5889 FT_Angle angle = 0;
5890 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5891 double widthRatio = 1.0;
5892 FT_Matrix transMat = identityMat;
5893 FT_Matrix transMatUnrotated;
5894 BOOL needsTransform = FALSE;
5895 BOOL tategaki = (font->GSUB_Table != NULL);
5896 UINT original_index;
5897 LONG avgAdvance = 0;
5898 FT_Fixed em_scale;
5900 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5901 buflen, buf, lpmat);
5903 TRACE("font transform %f %f %f %f\n",
5904 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5905 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5907 if(format & GGO_GLYPH_INDEX) {
5908 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5909 original_index = glyph;
5910 format &= ~GGO_GLYPH_INDEX;
5911 } else {
5912 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5913 ft_face = font->ft_face;
5914 original_index = glyph_index;
5917 if(format & GGO_UNHINTED) {
5918 load_flags |= FT_LOAD_NO_HINTING;
5919 format &= ~GGO_UNHINTED;
5922 /* tategaki never appears to happen to lower glyph index */
5923 if (glyph_index < TATEGAKI_LOWER_BOUND )
5924 tategaki = FALSE;
5926 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5927 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5928 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5929 font->gmsize * sizeof(GM*));
5930 } else {
5931 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5932 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5934 *lpgm = FONT_GM(font,original_index)->gm;
5935 *abc = FONT_GM(font,original_index)->abc;
5936 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5937 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5938 lpgm->gmCellIncX, lpgm->gmCellIncY);
5939 return 1; /* FIXME */
5943 if (!font->gm[original_index / GM_BLOCK_SIZE])
5944 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5946 /* Scaling factor */
5947 if (font->aveWidth)
5949 TEXTMETRICW tm;
5951 get_text_metrics(font, &tm);
5953 widthRatio = (double)font->aveWidth;
5954 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5956 else
5957 widthRatio = font->scale_y;
5959 /* Scaling transform */
5960 if (widthRatio != 1.0 || font->scale_y != 1.0)
5962 FT_Matrix scaleMat;
5963 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5964 scaleMat.xy = 0;
5965 scaleMat.yx = 0;
5966 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5968 pFT_Matrix_Multiply(&scaleMat, &transMat);
5969 needsTransform = TRUE;
5972 /* Slant transform */
5973 if (font->fake_italic) {
5974 FT_Matrix slantMat;
5976 slantMat.xx = (1 << 16);
5977 slantMat.xy = ((1 << 16) >> 2);
5978 slantMat.yx = 0;
5979 slantMat.yy = (1 << 16);
5980 pFT_Matrix_Multiply(&slantMat, &transMat);
5981 needsTransform = TRUE;
5984 /* Rotation transform */
5985 transMatUnrotated = transMat;
5986 if(font->orientation && !tategaki) {
5987 FT_Matrix rotationMat;
5988 FT_Vector vecAngle;
5989 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5990 pFT_Vector_Unit(&vecAngle, angle);
5991 rotationMat.xx = vecAngle.x;
5992 rotationMat.xy = -vecAngle.y;
5993 rotationMat.yx = -rotationMat.xy;
5994 rotationMat.yy = rotationMat.xx;
5996 pFT_Matrix_Multiply(&rotationMat, &transMat);
5997 needsTransform = TRUE;
6000 /* World transform */
6001 if (!is_identity_FMAT2(&font->font_desc.matrix))
6003 FT_Matrix worldMat;
6004 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
6005 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
6006 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
6007 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
6008 pFT_Matrix_Multiply(&worldMat, &transMat);
6009 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
6010 needsTransform = TRUE;
6013 /* Extra transformation specified by caller */
6014 if (!is_identity_MAT2(lpmat))
6016 FT_Matrix extraMat;
6017 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6018 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6019 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6020 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6021 pFT_Matrix_Multiply(&extraMat, &transMat);
6022 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6023 needsTransform = TRUE;
6026 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6028 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6030 if(err) {
6031 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6032 return GDI_ERROR;
6035 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6036 * by the text metrics. The proper behavior is to clip the glyph metrics to
6037 * fit within the maximums specified in the text metrics. */
6038 metrics = ft_face->glyph->metrics;
6039 if(incoming_font->potm || get_outline_text_metrics(incoming_font) ||
6040 get_bitmap_text_metrics(incoming_font)) {
6041 TEXTMETRICW *ptm = &incoming_font->potm->otmTextMetrics;
6042 top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
6043 bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
6044 metrics.horiBearingY = top;
6045 metrics.height = top - bottom;
6047 /* TODO: Are we supposed to clip the width as well...? */
6048 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6051 if(FT_IS_SCALABLE(incoming_font->ft_face)) {
6052 TEXTMETRICW tm;
6053 if (get_text_metrics(incoming_font, &tm) &&
6054 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6055 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6056 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6057 if (avgAdvance &&
6058 (metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6059 TRACE("Fixed-pitch full-width character detected\n");
6060 else
6061 avgAdvance = 0; /* cancel this feature */
6065 if(!needsTransform) {
6066 left = (INT)(metrics.horiBearingX) & -64;
6067 right = (INT)((metrics.horiBearingX + metrics.width) + 63) & -64;
6068 if (!avgAdvance)
6069 adv = (INT)(metrics.horiAdvance + 63) >> 6;
6070 else
6071 adv = (INT)avgAdvance * 2;
6073 top = (metrics.horiBearingY + 63) & -64;
6074 bottom = (metrics.horiBearingY - metrics.height) & -64;
6075 lpgm->gmCellIncX = adv;
6076 lpgm->gmCellIncY = 0;
6077 } else {
6078 INT xc, yc;
6079 FT_Vector vec;
6081 left = right = 0;
6083 for(xc = 0; xc < 2; xc++) {
6084 for(yc = 0; yc < 2; yc++) {
6085 vec.x = metrics.horiBearingX + xc * metrics.width;
6086 vec.y = metrics.horiBearingY - yc * metrics.height;
6087 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6088 pFT_Vector_Transform(&vec, &transMat);
6089 if(xc == 0 && yc == 0) {
6090 left = right = vec.x;
6091 top = bottom = vec.y;
6092 } else {
6093 if(vec.x < left) left = vec.x;
6094 else if(vec.x > right) right = vec.x;
6095 if(vec.y < bottom) bottom = vec.y;
6096 else if(vec.y > top) top = vec.y;
6100 left = left & -64;
6101 right = (right + 63) & -64;
6102 bottom = bottom & -64;
6103 top = (top + 63) & -64;
6105 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6106 vec.x = metrics.horiAdvance;
6107 vec.y = 0;
6108 pFT_Vector_Transform(&vec, &transMat);
6109 lpgm->gmCellIncY = -((vec.y+63) >> 6);
6110 if (!avgAdvance || vec.y)
6111 lpgm->gmCellIncX = (vec.x+63) >> 6;
6112 else {
6113 vec.x = incoming_font->ntmAvgWidth;
6114 vec.y = 0;
6115 pFT_Vector_Transform(&vec, &transMat);
6116 lpgm->gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6119 vec.x = metrics.horiAdvance;
6120 vec.y = 0;
6121 pFT_Vector_Transform(&vec, &transMatUnrotated);
6122 if (!avgAdvance || vec.y)
6123 adv = (vec.x+63) >> 6;
6124 else {
6125 vec.x = incoming_font->ntmAvgWidth;
6126 vec.y = 0;
6127 pFT_Vector_Transform(&vec, &transMatUnrotated);
6128 adv = pFT_MulFix(vec.x, em_scale) * 2;
6132 lpgm->gmBlackBoxX = (right - left) >> 6;
6133 lpgm->gmBlackBoxY = (top - bottom) >> 6;
6134 lpgm->gmptGlyphOrigin.x = left >> 6;
6135 lpgm->gmptGlyphOrigin.y = top >> 6;
6136 abc->abcA = left >> 6;
6137 abc->abcB = (right - left) >> 6;
6138 abc->abcC = adv - abc->abcA - abc->abcB;
6140 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6141 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6142 lpgm->gmCellIncX, lpgm->gmCellIncY);
6144 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6145 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6147 FONT_GM(font,original_index)->gm = *lpgm;
6148 FONT_GM(font,original_index)->abc = *abc;
6149 FONT_GM(font,original_index)->init = TRUE;
6152 if(format == GGO_METRICS)
6154 return 1; /* FIXME */
6157 if(ft_face->glyph->format != ft_glyph_format_outline &&
6158 (format == GGO_NATIVE || format == GGO_BEZIER))
6160 TRACE("loaded a bitmap\n");
6161 return GDI_ERROR;
6164 switch(format) {
6165 case GGO_BITMAP:
6166 width = lpgm->gmBlackBoxX;
6167 height = lpgm->gmBlackBoxY;
6168 pitch = ((width + 31) >> 5) << 2;
6169 needed = pitch * height;
6171 if(!buf || !buflen) break;
6173 switch(ft_face->glyph->format) {
6174 case ft_glyph_format_bitmap:
6176 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6177 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
6178 INT h = min( height, ft_face->glyph->bitmap.rows );
6179 while(h--) {
6180 memcpy(dst, src, w);
6181 src += ft_face->glyph->bitmap.pitch;
6182 dst += pitch;
6184 break;
6187 case ft_glyph_format_outline:
6188 ft_bitmap.width = width;
6189 ft_bitmap.rows = height;
6190 ft_bitmap.pitch = pitch;
6191 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6192 ft_bitmap.buffer = buf;
6194 if(needsTransform)
6195 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6197 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6199 /* Note: FreeType will only set 'black' bits for us. */
6200 memset(buf, 0, needed);
6201 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6202 break;
6204 default:
6205 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6206 return GDI_ERROR;
6208 break;
6210 case GGO_GRAY2_BITMAP:
6211 case GGO_GRAY4_BITMAP:
6212 case GGO_GRAY8_BITMAP:
6213 case WINE_GGO_GRAY16_BITMAP:
6215 unsigned int max_level, row, col;
6216 BYTE *start, *ptr;
6218 width = lpgm->gmBlackBoxX;
6219 height = lpgm->gmBlackBoxY;
6220 pitch = (width + 3) / 4 * 4;
6221 needed = pitch * height;
6223 if(!buf || !buflen) break;
6225 max_level = get_max_level( format );
6227 switch(ft_face->glyph->format) {
6228 case ft_glyph_format_bitmap:
6230 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6231 INT h = min( height, ft_face->glyph->bitmap.rows );
6232 INT x;
6233 memset( buf, 0, needed );
6234 while(h--) {
6235 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6236 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6237 src += ft_face->glyph->bitmap.pitch;
6238 dst += pitch;
6240 return needed;
6242 case ft_glyph_format_outline:
6244 ft_bitmap.width = width;
6245 ft_bitmap.rows = height;
6246 ft_bitmap.pitch = pitch;
6247 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6248 ft_bitmap.buffer = buf;
6250 if(needsTransform)
6251 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6253 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6255 memset(ft_bitmap.buffer, 0, buflen);
6257 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6259 if (max_level != 255)
6261 for (row = 0, start = buf; row < height; row++)
6263 for (col = 0, ptr = start; col < width; col++, ptr++)
6264 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6265 start += pitch;
6268 return needed;
6271 default:
6272 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6273 return GDI_ERROR;
6275 break;
6278 case WINE_GGO_HRGB_BITMAP:
6279 case WINE_GGO_HBGR_BITMAP:
6280 case WINE_GGO_VRGB_BITMAP:
6281 case WINE_GGO_VBGR_BITMAP:
6282 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6284 switch (ft_face->glyph->format)
6286 case FT_GLYPH_FORMAT_BITMAP:
6288 BYTE *src, *dst;
6289 INT src_pitch, x;
6291 width = lpgm->gmBlackBoxX;
6292 height = lpgm->gmBlackBoxY;
6293 pitch = width * 4;
6294 needed = pitch * height;
6296 if (!buf || !buflen) break;
6298 memset(buf, 0, buflen);
6299 dst = buf;
6300 src = ft_face->glyph->bitmap.buffer;
6301 src_pitch = ft_face->glyph->bitmap.pitch;
6303 height = min( height, ft_face->glyph->bitmap.rows );
6304 while ( height-- )
6306 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6308 if ( src[x / 8] & masks[x % 8] )
6309 ((unsigned int *)dst)[x] = ~0u;
6311 src += src_pitch;
6312 dst += pitch;
6315 break;
6318 case FT_GLYPH_FORMAT_OUTLINE:
6320 unsigned int *dst;
6321 BYTE *src;
6322 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6323 INT x_shift, y_shift;
6324 BOOL rgb;
6325 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6326 FT_Render_Mode render_mode =
6327 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6328 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6330 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6332 if ( render_mode == FT_RENDER_MODE_LCD)
6334 lpgm->gmBlackBoxX += 2;
6335 lpgm->gmptGlyphOrigin.x -= 1;
6337 else
6339 lpgm->gmBlackBoxY += 2;
6340 lpgm->gmptGlyphOrigin.y += 1;
6344 width = lpgm->gmBlackBoxX;
6345 height = lpgm->gmBlackBoxY;
6346 pitch = width * 4;
6347 needed = pitch * height;
6349 if (!buf || !buflen) break;
6351 memset(buf, 0, buflen);
6352 dst = buf;
6353 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6355 if ( needsTransform )
6356 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6358 if ( pFT_Library_SetLcdFilter )
6359 pFT_Library_SetLcdFilter( library, lcdfilter );
6360 pFT_Render_Glyph (ft_face->glyph, render_mode);
6362 src = ft_face->glyph->bitmap.buffer;
6363 src_pitch = ft_face->glyph->bitmap.pitch;
6364 src_width = ft_face->glyph->bitmap.width;
6365 src_height = ft_face->glyph->bitmap.rows;
6367 if ( render_mode == FT_RENDER_MODE_LCD)
6369 rgb_interval = 1;
6370 hmul = 3;
6371 vmul = 1;
6373 else
6375 rgb_interval = src_pitch;
6376 hmul = 1;
6377 vmul = 3;
6380 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6381 if ( x_shift < 0 )
6383 src += hmul * -x_shift;
6384 src_width -= hmul * -x_shift;
6386 else if ( x_shift > 0 )
6388 dst += x_shift;
6389 width -= x_shift;
6392 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6393 if ( y_shift < 0 )
6395 src += src_pitch * vmul * -y_shift;
6396 src_height -= vmul * -y_shift;
6398 else if ( y_shift > 0 )
6400 dst += y_shift * ( pitch / sizeof(*dst) );
6401 height -= y_shift;
6404 width = min( width, src_width / hmul );
6405 height = min( height, src_height / vmul );
6407 while ( height-- )
6409 for ( x = 0; x < width; x++ )
6411 if ( rgb )
6413 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6414 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6415 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6416 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6418 else
6420 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6421 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6422 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6423 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6426 src += src_pitch * vmul;
6427 dst += pitch / sizeof(*dst);
6430 break;
6433 default:
6434 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6435 return GDI_ERROR;
6438 break;
6440 #else
6441 return GDI_ERROR;
6442 #endif
6444 case GGO_NATIVE:
6446 int contour, point = 0, first_pt;
6447 FT_Outline *outline = &ft_face->glyph->outline;
6448 TTPOLYGONHEADER *pph;
6449 TTPOLYCURVE *ppc;
6450 DWORD pph_start, cpfx, type;
6452 if(buflen == 0) buf = NULL;
6454 if (needsTransform && buf) {
6455 pFT_Outline_Transform(outline, &transMat);
6458 for(contour = 0; contour < outline->n_contours; contour++) {
6459 /* Ignore contours containing one point */
6460 if(point == outline->contours[contour]) {
6461 point++;
6462 continue;
6465 pph_start = needed;
6466 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6467 first_pt = point;
6468 if(buf) {
6469 pph->dwType = TT_POLYGON_TYPE;
6470 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6472 needed += sizeof(*pph);
6473 point++;
6474 while(point <= outline->contours[contour]) {
6475 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6476 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6477 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6478 cpfx = 0;
6479 do {
6480 if(buf)
6481 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6482 cpfx++;
6483 point++;
6484 } while(point <= outline->contours[contour] &&
6485 (outline->tags[point] & FT_Curve_Tag_On) ==
6486 (outline->tags[point-1] & FT_Curve_Tag_On));
6487 /* At the end of a contour Windows adds the start point, but
6488 only for Beziers */
6489 if(point > outline->contours[contour] &&
6490 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6491 if(buf)
6492 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6493 cpfx++;
6494 } else if(point <= outline->contours[contour] &&
6495 outline->tags[point] & FT_Curve_Tag_On) {
6496 /* add closing pt for bezier */
6497 if(buf)
6498 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6499 cpfx++;
6500 point++;
6502 if(buf) {
6503 ppc->wType = type;
6504 ppc->cpfx = cpfx;
6506 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6508 if(buf)
6509 pph->cb = needed - pph_start;
6511 break;
6513 case GGO_BEZIER:
6515 /* Convert the quadratic Beziers to cubic Beziers.
6516 The parametric eqn for a cubic Bezier is, from PLRM:
6517 r(t) = at^3 + bt^2 + ct + r0
6518 with the control points:
6519 r1 = r0 + c/3
6520 r2 = r1 + (c + b)/3
6521 r3 = r0 + c + b + a
6523 A quadratic Bezier has the form:
6524 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6526 So equating powers of t leads to:
6527 r1 = 2/3 p1 + 1/3 p0
6528 r2 = 2/3 p1 + 1/3 p2
6529 and of course r0 = p0, r3 = p2
6532 int contour, point = 0, first_pt;
6533 FT_Outline *outline = &ft_face->glyph->outline;
6534 TTPOLYGONHEADER *pph;
6535 TTPOLYCURVE *ppc;
6536 DWORD pph_start, cpfx, type;
6537 FT_Vector cubic_control[4];
6538 if(buflen == 0) buf = NULL;
6540 if (needsTransform && buf) {
6541 pFT_Outline_Transform(outline, &transMat);
6544 for(contour = 0; contour < outline->n_contours; contour++) {
6545 pph_start = needed;
6546 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6547 first_pt = point;
6548 if(buf) {
6549 pph->dwType = TT_POLYGON_TYPE;
6550 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6552 needed += sizeof(*pph);
6553 point++;
6554 while(point <= outline->contours[contour]) {
6555 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6556 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6557 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6558 cpfx = 0;
6559 do {
6560 if(type == TT_PRIM_LINE) {
6561 if(buf)
6562 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6563 cpfx++;
6564 point++;
6565 } else {
6566 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6567 so cpfx = 3n */
6569 /* FIXME: Possible optimization in endpoint calculation
6570 if there are two consecutive curves */
6571 cubic_control[0] = outline->points[point-1];
6572 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6573 cubic_control[0].x += outline->points[point].x + 1;
6574 cubic_control[0].y += outline->points[point].y + 1;
6575 cubic_control[0].x >>= 1;
6576 cubic_control[0].y >>= 1;
6578 if(point+1 > outline->contours[contour])
6579 cubic_control[3] = outline->points[first_pt];
6580 else {
6581 cubic_control[3] = outline->points[point+1];
6582 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6583 cubic_control[3].x += outline->points[point].x + 1;
6584 cubic_control[3].y += outline->points[point].y + 1;
6585 cubic_control[3].x >>= 1;
6586 cubic_control[3].y >>= 1;
6589 /* r1 = 1/3 p0 + 2/3 p1
6590 r2 = 1/3 p2 + 2/3 p1 */
6591 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6592 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6593 cubic_control[2] = cubic_control[1];
6594 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6595 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6596 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6597 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6598 if(buf) {
6599 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6600 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6601 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6603 cpfx += 3;
6604 point++;
6606 } while(point <= outline->contours[contour] &&
6607 (outline->tags[point] & FT_Curve_Tag_On) ==
6608 (outline->tags[point-1] & FT_Curve_Tag_On));
6609 /* At the end of a contour Windows adds the start point,
6610 but only for Beziers and we've already done that.
6612 if(point <= outline->contours[contour] &&
6613 outline->tags[point] & FT_Curve_Tag_On) {
6614 /* This is the closing pt of a bezier, but we've already
6615 added it, so just inc point and carry on */
6616 point++;
6618 if(buf) {
6619 ppc->wType = type;
6620 ppc->cpfx = cpfx;
6622 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6624 if(buf)
6625 pph->cb = needed - pph_start;
6627 break;
6630 default:
6631 FIXME("Unsupported format %d\n", format);
6632 return GDI_ERROR;
6634 return needed;
6637 static BOOL get_bitmap_text_metrics(GdiFont *font)
6639 FT_Face ft_face = font->ft_face;
6640 FT_WinFNT_HeaderRec winfnt_header;
6641 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6642 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6643 font->potm->otmSize = size;
6645 #define TM font->potm->otmTextMetrics
6646 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6648 TM.tmHeight = winfnt_header.pixel_height;
6649 TM.tmAscent = winfnt_header.ascent;
6650 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6651 TM.tmInternalLeading = winfnt_header.internal_leading;
6652 TM.tmExternalLeading = winfnt_header.external_leading;
6653 TM.tmAveCharWidth = winfnt_header.avg_width;
6654 TM.tmMaxCharWidth = winfnt_header.max_width;
6655 TM.tmWeight = winfnt_header.weight;
6656 TM.tmOverhang = 0;
6657 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6658 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6659 TM.tmFirstChar = winfnt_header.first_char;
6660 TM.tmLastChar = winfnt_header.last_char;
6661 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6662 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6663 TM.tmItalic = winfnt_header.italic;
6664 TM.tmUnderlined = font->underline;
6665 TM.tmStruckOut = font->strikeout;
6666 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6667 TM.tmCharSet = winfnt_header.charset;
6669 else
6671 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6672 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6673 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6674 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6675 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6676 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6677 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6678 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6679 TM.tmOverhang = 0;
6680 TM.tmDigitizedAspectX = 96; /* FIXME */
6681 TM.tmDigitizedAspectY = 96; /* FIXME */
6682 TM.tmFirstChar = 1;
6683 TM.tmLastChar = 255;
6684 TM.tmDefaultChar = 32;
6685 TM.tmBreakChar = 32;
6686 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6687 TM.tmUnderlined = font->underline;
6688 TM.tmStruckOut = font->strikeout;
6689 /* NB inverted meaning of TMPF_FIXED_PITCH */
6690 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6691 TM.tmCharSet = font->charset;
6693 #undef TM
6695 return TRUE;
6699 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6701 double scale_x, scale_y;
6703 if (font->aveWidth)
6705 scale_x = (double)font->aveWidth;
6706 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6708 else
6709 scale_x = font->scale_y;
6711 scale_x *= fabs(font->font_desc.matrix.eM11);
6712 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6714 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6715 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6717 SCALE_Y(ptm->tmHeight);
6718 SCALE_Y(ptm->tmAscent);
6719 SCALE_Y(ptm->tmDescent);
6720 SCALE_Y(ptm->tmInternalLeading);
6721 SCALE_Y(ptm->tmExternalLeading);
6722 SCALE_Y(ptm->tmOverhang);
6724 SCALE_X(ptm->tmAveCharWidth);
6725 SCALE_X(ptm->tmMaxCharWidth);
6727 #undef SCALE_X
6728 #undef SCALE_Y
6731 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6733 double scale_x, scale_y;
6735 if (font->aveWidth)
6737 scale_x = (double)font->aveWidth;
6738 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6740 else
6741 scale_x = font->scale_y;
6743 scale_x *= fabs(font->font_desc.matrix.eM11);
6744 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6746 scale_font_metrics(font, &potm->otmTextMetrics);
6748 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6749 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6751 SCALE_Y(potm->otmAscent);
6752 SCALE_Y(potm->otmDescent);
6753 SCALE_Y(potm->otmLineGap);
6754 SCALE_Y(potm->otmsCapEmHeight);
6755 SCALE_Y(potm->otmsXHeight);
6756 SCALE_Y(potm->otmrcFontBox.top);
6757 SCALE_Y(potm->otmrcFontBox.bottom);
6758 SCALE_X(potm->otmrcFontBox.left);
6759 SCALE_X(potm->otmrcFontBox.right);
6760 SCALE_Y(potm->otmMacAscent);
6761 SCALE_Y(potm->otmMacDescent);
6762 SCALE_Y(potm->otmMacLineGap);
6763 SCALE_X(potm->otmptSubscriptSize.x);
6764 SCALE_Y(potm->otmptSubscriptSize.y);
6765 SCALE_X(potm->otmptSubscriptOffset.x);
6766 SCALE_Y(potm->otmptSubscriptOffset.y);
6767 SCALE_X(potm->otmptSuperscriptSize.x);
6768 SCALE_Y(potm->otmptSuperscriptSize.y);
6769 SCALE_X(potm->otmptSuperscriptOffset.x);
6770 SCALE_Y(potm->otmptSuperscriptOffset.y);
6771 SCALE_Y(potm->otmsStrikeoutSize);
6772 SCALE_Y(potm->otmsStrikeoutPosition);
6773 SCALE_Y(potm->otmsUnderscoreSize);
6774 SCALE_Y(potm->otmsUnderscorePosition);
6776 #undef SCALE_X
6777 #undef SCALE_Y
6780 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6782 if(!font->potm)
6784 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6786 /* Make sure that the font has sane width/height ratio */
6787 if (font->aveWidth)
6789 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6791 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6792 font->aveWidth = 0;
6796 *ptm = font->potm->otmTextMetrics;
6797 scale_font_metrics(font, ptm);
6798 return TRUE;
6801 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6803 int i;
6805 for(i = 0; i < ft_face->num_charmaps; i++)
6807 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6808 return TRUE;
6810 return FALSE;
6813 static BOOL get_outline_text_metrics(GdiFont *font)
6815 BOOL ret = FALSE;
6816 FT_Face ft_face = font->ft_face;
6817 UINT needed, lenfam, lensty, lenface, lenfull;
6818 TT_OS2 *pOS2;
6819 TT_HoriHeader *pHori;
6820 TT_Postscript *pPost;
6821 FT_Fixed em_scale;
6822 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6823 char *cp;
6824 INT ascent, descent;
6826 TRACE("font=%p\n", font);
6828 if(!FT_IS_SCALABLE(ft_face))
6829 return FALSE;
6831 needed = sizeof(*font->potm);
6833 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6834 family_nameW = strdupW(font->name);
6836 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6837 if (!style_nameW)
6838 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6839 if (!style_nameW)
6841 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6842 style_nameW = towstr( CP_ACP, ft_face->style_name );
6844 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6846 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6847 if (!face_nameW)
6848 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6849 if (!face_nameW)
6851 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6852 face_nameW = strdupW(font->name);
6854 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6855 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6857 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6858 if (!full_nameW)
6859 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6860 if (!full_nameW)
6862 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6863 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6864 full_nameW = strdupW(fake_nameW);
6866 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6868 /* These names should be read from the TT name table */
6870 /* length of otmpFamilyName */
6871 needed += lenfam;
6873 /* length of otmpFaceName */
6874 needed += lenface;
6876 /* length of otmpStyleName */
6877 needed += lensty;
6879 /* length of otmpFullName */
6880 needed += lenfull;
6883 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
6885 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6886 if(!pOS2) {
6887 FIXME("Can't find OS/2 table - not TT font?\n");
6888 goto end;
6891 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6892 if(!pHori) {
6893 FIXME("Can't find HHEA table - not TT font?\n");
6894 goto end;
6897 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6899 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",
6900 pOS2->usWinAscent, pOS2->usWinDescent,
6901 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6902 pOS2->xAvgCharWidth,
6903 ft_face->ascender, ft_face->descender, ft_face->height,
6904 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6905 ft_face->bbox.yMax, ft_face->bbox.yMin);
6907 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6908 font->potm->otmSize = needed;
6910 #define TM font->potm->otmTextMetrics
6912 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6913 ascent = pHori->Ascender;
6914 descent = -pHori->Descender;
6915 } else {
6916 ascent = pOS2->usWinAscent;
6917 descent = pOS2->usWinDescent;
6920 font->ntmCellHeight = ascent + descent;
6921 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6923 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
6924 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
6926 if(font->yMax) {
6927 TM.tmAscent = font->yMax;
6928 TM.tmDescent = -font->yMin;
6929 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6930 } else {
6931 TM.tmAscent = SCALE_Y(ascent);
6932 TM.tmDescent = SCALE_Y(descent);
6933 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
6936 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6938 /* MSDN says:
6939 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6941 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
6942 ((ascent + descent) -
6943 (pHori->Ascender - pHori->Descender))));
6945 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
6946 if (TM.tmAveCharWidth == 0) {
6947 TM.tmAveCharWidth = 1;
6949 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
6950 TM.tmWeight = FW_REGULAR;
6951 if (font->fake_bold)
6952 TM.tmWeight = FW_BOLD;
6953 else
6955 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6957 if (pOS2->usWeightClass > FW_MEDIUM)
6958 TM.tmWeight = pOS2->usWeightClass;
6960 else if (pOS2->usWeightClass <= FW_MEDIUM)
6961 TM.tmWeight = pOS2->usWeightClass;
6963 TM.tmOverhang = 0;
6964 TM.tmDigitizedAspectX = 96; /* FIXME */
6965 TM.tmDigitizedAspectY = 96; /* FIXME */
6966 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6967 * symbol range to 0 - f0ff
6970 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6972 TM.tmFirstChar = 0;
6973 switch(GetACP())
6975 case 1257: /* Baltic */
6976 TM.tmLastChar = 0xf8fd;
6977 break;
6978 default:
6979 TM.tmLastChar = 0xf0ff;
6981 TM.tmBreakChar = 0x20;
6982 TM.tmDefaultChar = 0x1f;
6984 else
6986 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6987 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6989 if(pOS2->usFirstCharIndex <= 1)
6990 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6991 else if (pOS2->usFirstCharIndex > 0xff)
6992 TM.tmBreakChar = 0x20;
6993 else
6994 TM.tmBreakChar = pOS2->usFirstCharIndex;
6995 TM.tmDefaultChar = TM.tmBreakChar - 1;
6997 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6998 TM.tmUnderlined = font->underline;
6999 TM.tmStruckOut = font->strikeout;
7001 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7002 if(!FT_IS_FIXED_WIDTH(ft_face) &&
7003 (pOS2->version == 0xFFFFU ||
7004 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
7005 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
7006 else
7007 TM.tmPitchAndFamily = 0;
7009 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
7011 case PAN_FAMILY_SCRIPT:
7012 TM.tmPitchAndFamily |= FF_SCRIPT;
7013 break;
7015 case PAN_FAMILY_DECORATIVE:
7016 TM.tmPitchAndFamily |= FF_DECORATIVE;
7017 break;
7019 case PAN_ANY:
7020 case PAN_NO_FIT:
7021 case PAN_FAMILY_TEXT_DISPLAY:
7022 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
7023 /* which is clearly not what the panose spec says. */
7024 default:
7025 if(TM.tmPitchAndFamily == 0 || /* fixed */
7026 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
7027 TM.tmPitchAndFamily = FF_MODERN;
7028 else
7030 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
7032 case PAN_ANY:
7033 case PAN_NO_FIT:
7034 default:
7035 TM.tmPitchAndFamily |= FF_DONTCARE;
7036 break;
7038 case PAN_SERIF_COVE:
7039 case PAN_SERIF_OBTUSE_COVE:
7040 case PAN_SERIF_SQUARE_COVE:
7041 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7042 case PAN_SERIF_SQUARE:
7043 case PAN_SERIF_THIN:
7044 case PAN_SERIF_BONE:
7045 case PAN_SERIF_EXAGGERATED:
7046 case PAN_SERIF_TRIANGLE:
7047 TM.tmPitchAndFamily |= FF_ROMAN;
7048 break;
7050 case PAN_SERIF_NORMAL_SANS:
7051 case PAN_SERIF_OBTUSE_SANS:
7052 case PAN_SERIF_PERP_SANS:
7053 case PAN_SERIF_FLARED:
7054 case PAN_SERIF_ROUNDED:
7055 TM.tmPitchAndFamily |= FF_SWISS;
7056 break;
7059 break;
7062 if(FT_IS_SCALABLE(ft_face))
7063 TM.tmPitchAndFamily |= TMPF_VECTOR;
7065 if(FT_IS_SFNT(ft_face))
7067 if (font->ntmFlags & NTM_PS_OPENTYPE)
7068 TM.tmPitchAndFamily |= TMPF_DEVICE;
7069 else
7070 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7073 TM.tmCharSet = font->charset;
7075 font->potm->otmFiller = 0;
7076 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7077 font->potm->otmfsSelection = pOS2->fsSelection;
7078 font->potm->otmfsType = pOS2->fsType;
7079 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7080 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7081 font->potm->otmItalicAngle = 0; /* POST table */
7082 font->potm->otmEMSquare = ft_face->units_per_EM;
7083 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7084 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7085 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7086 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7087 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7088 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7089 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7090 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7091 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7092 font->potm->otmMacAscent = TM.tmAscent;
7093 font->potm->otmMacDescent = -TM.tmDescent;
7094 font->potm->otmMacLineGap = font->potm->otmLineGap;
7095 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7096 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7097 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7098 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7099 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7100 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7101 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7102 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7103 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7104 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7105 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7106 if(!pPost) {
7107 font->potm->otmsUnderscoreSize = 0;
7108 font->potm->otmsUnderscorePosition = 0;
7109 } else {
7110 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7111 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7113 #undef SCALE_X
7114 #undef SCALE_Y
7115 #undef TM
7117 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7118 cp = (char*)font->potm + sizeof(*font->potm);
7119 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7120 strcpyW((WCHAR*)cp, family_nameW);
7121 cp += lenfam;
7122 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7123 strcpyW((WCHAR*)cp, style_nameW);
7124 cp += lensty;
7125 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7126 strcpyW((WCHAR*)cp, face_nameW);
7127 cp += lenface;
7128 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7129 strcpyW((WCHAR*)cp, full_nameW);
7130 ret = TRUE;
7132 end:
7133 HeapFree(GetProcessHeap(), 0, style_nameW);
7134 HeapFree(GetProcessHeap(), 0, family_nameW);
7135 HeapFree(GetProcessHeap(), 0, face_nameW);
7136 HeapFree(GetProcessHeap(), 0, full_nameW);
7137 return ret;
7140 /*************************************************************
7141 * freetype_GetGlyphOutline
7143 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7144 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7146 struct freetype_physdev *physdev = get_freetype_dev( dev );
7147 DWORD ret;
7148 ABC abc;
7150 if (!physdev->font)
7152 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7153 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7156 GDI_CheckNotLock();
7157 EnterCriticalSection( &freetype_cs );
7158 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7159 LeaveCriticalSection( &freetype_cs );
7160 return ret;
7163 /*************************************************************
7164 * freetype_GetTextMetrics
7166 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7168 struct freetype_physdev *physdev = get_freetype_dev( dev );
7169 BOOL ret;
7171 if (!physdev->font)
7173 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7174 return dev->funcs->pGetTextMetrics( dev, metrics );
7177 GDI_CheckNotLock();
7178 EnterCriticalSection( &freetype_cs );
7179 ret = get_text_metrics( physdev->font, metrics );
7180 LeaveCriticalSection( &freetype_cs );
7181 return ret;
7184 /*************************************************************
7185 * freetype_GetOutlineTextMetrics
7187 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7189 struct freetype_physdev *physdev = get_freetype_dev( dev );
7190 UINT ret = 0;
7192 if (!physdev->font)
7194 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7195 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7198 TRACE("font=%p\n", physdev->font);
7200 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7202 GDI_CheckNotLock();
7203 EnterCriticalSection( &freetype_cs );
7205 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7207 if(cbSize >= physdev->font->potm->otmSize)
7209 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7210 scale_outline_font_metrics(physdev->font, potm);
7212 ret = physdev->font->potm->otmSize;
7214 LeaveCriticalSection( &freetype_cs );
7215 return ret;
7218 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7220 child->font = alloc_font();
7221 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7222 if(!child->font->ft_face)
7224 free_font(child->font);
7225 child->font = NULL;
7226 return FALSE;
7229 child->font->font_desc = font->font_desc;
7230 child->font->ntmFlags = child->face->ntmFlags;
7231 child->font->orientation = font->orientation;
7232 child->font->scale_y = font->scale_y;
7233 child->font->name = strdupW(child->face->family->FamilyName);
7234 child->font->base_font = font;
7235 TRACE("created child font %p for base %p\n", child->font, font);
7236 return TRUE;
7239 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7241 FT_UInt g;
7242 CHILD_FONT *child_font;
7244 if(font->base_font)
7245 font = font->base_font;
7247 *linked_font = font;
7249 if((*glyph = get_glyph_index(font, c)))
7251 *glyph = get_GSUB_vert_glyph(font, *glyph);
7252 return TRUE;
7255 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7257 if(!child_font->font)
7258 if(!load_child_font(font, child_font))
7259 continue;
7261 if(!child_font->font->ft_face)
7262 continue;
7263 g = get_glyph_index(child_font->font, c);
7264 g = get_GSUB_vert_glyph(child_font->font, g);
7265 if(g)
7267 *glyph = g;
7268 *linked_font = child_font->font;
7269 return TRUE;
7272 return FALSE;
7275 /*************************************************************
7276 * freetype_GetCharWidth
7278 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7280 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7281 UINT c;
7282 GLYPHMETRICS gm;
7283 ABC abc;
7284 struct freetype_physdev *physdev = get_freetype_dev( dev );
7286 if (!physdev->font)
7288 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7289 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7292 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7294 GDI_CheckNotLock();
7295 EnterCriticalSection( &freetype_cs );
7296 for(c = firstChar; c <= lastChar; c++) {
7297 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7298 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7300 LeaveCriticalSection( &freetype_cs );
7301 return TRUE;
7304 /*************************************************************
7305 * freetype_GetCharABCWidths
7307 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7309 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7310 UINT c;
7311 GLYPHMETRICS gm;
7312 struct freetype_physdev *physdev = get_freetype_dev( dev );
7314 if (!physdev->font)
7316 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7317 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7320 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7322 GDI_CheckNotLock();
7323 EnterCriticalSection( &freetype_cs );
7325 for(c = firstChar; c <= lastChar; c++, buffer++)
7326 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7328 LeaveCriticalSection( &freetype_cs );
7329 return TRUE;
7332 /*************************************************************
7333 * freetype_GetCharABCWidthsI
7335 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7337 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7338 UINT c;
7339 GLYPHMETRICS gm;
7340 struct freetype_physdev *physdev = get_freetype_dev( dev );
7342 if (!physdev->font)
7344 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7345 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7348 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7349 return FALSE;
7351 GDI_CheckNotLock();
7352 EnterCriticalSection( &freetype_cs );
7354 for(c = 0; c < count; c++, buffer++)
7355 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7356 &gm, buffer, 0, NULL, &identity );
7358 LeaveCriticalSection( &freetype_cs );
7359 return TRUE;
7362 /*************************************************************
7363 * freetype_GetTextExtentExPoint
7365 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7367 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7368 INT idx, pos;
7369 ABC abc;
7370 GLYPHMETRICS gm;
7371 struct freetype_physdev *physdev = get_freetype_dev( dev );
7373 if (!physdev->font)
7375 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7376 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7379 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7381 GDI_CheckNotLock();
7382 EnterCriticalSection( &freetype_cs );
7384 for (idx = pos = 0; idx < count; idx++)
7386 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7387 pos += abc.abcA + abc.abcB + abc.abcC;
7388 dxs[idx] = pos;
7391 LeaveCriticalSection( &freetype_cs );
7392 return TRUE;
7395 /*************************************************************
7396 * freetype_GetTextExtentExPointI
7398 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7400 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7401 INT idx, pos;
7402 ABC abc;
7403 GLYPHMETRICS gm;
7404 struct freetype_physdev *physdev = get_freetype_dev( dev );
7406 if (!physdev->font)
7408 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7409 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7412 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7414 GDI_CheckNotLock();
7415 EnterCriticalSection( &freetype_cs );
7417 for (idx = pos = 0; idx < count; idx++)
7419 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7420 &gm, &abc, 0, NULL, &identity );
7421 pos += abc.abcA + abc.abcB + abc.abcC;
7422 dxs[idx] = pos;
7425 LeaveCriticalSection( &freetype_cs );
7426 return TRUE;
7429 /*************************************************************
7430 * freetype_GetFontData
7432 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7434 struct freetype_physdev *physdev = get_freetype_dev( dev );
7436 if (!physdev->font)
7438 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7439 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7442 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7443 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7444 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7446 return get_font_data( physdev->font, table, offset, buf, cbData );
7449 /*************************************************************
7450 * freetype_GetTextFace
7452 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7454 INT n;
7455 struct freetype_physdev *physdev = get_freetype_dev( dev );
7457 if (!physdev->font)
7459 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7460 return dev->funcs->pGetTextFace( dev, count, str );
7463 n = strlenW(physdev->font->name) + 1;
7464 if (str)
7466 lstrcpynW(str, physdev->font->name, count);
7467 n = min(count, n);
7469 return n;
7472 /*************************************************************
7473 * freetype_GetTextCharsetInfo
7475 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7477 struct freetype_physdev *physdev = get_freetype_dev( dev );
7479 if (!physdev->font)
7481 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7482 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7484 if (fs) *fs = physdev->font->fs;
7485 return physdev->font->charset;
7488 /* Retrieve a list of supported Unicode ranges for a given font.
7489 * Can be called with NULL gs to calculate the buffer size. Returns
7490 * the number of ranges found.
7492 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7494 DWORD num_ranges = 0;
7496 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7498 FT_UInt glyph_code;
7499 FT_ULong char_code, char_code_prev;
7501 glyph_code = 0;
7502 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7504 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7505 face->num_glyphs, glyph_code, char_code);
7507 if (!glyph_code) return 0;
7509 if (gs)
7511 gs->ranges[0].wcLow = (USHORT)char_code;
7512 gs->ranges[0].cGlyphs = 0;
7513 gs->cGlyphsSupported = 0;
7516 num_ranges = 1;
7517 while (glyph_code)
7519 if (char_code < char_code_prev)
7521 ERR("expected increasing char code from FT_Get_Next_Char\n");
7522 return 0;
7524 if (char_code - char_code_prev > 1)
7526 num_ranges++;
7527 if (gs)
7529 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7530 gs->ranges[num_ranges - 1].cGlyphs = 1;
7531 gs->cGlyphsSupported++;
7534 else if (gs)
7536 gs->ranges[num_ranges - 1].cGlyphs++;
7537 gs->cGlyphsSupported++;
7539 char_code_prev = char_code;
7540 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7543 else
7544 FIXME("encoding %u not supported\n", face->charmap->encoding);
7546 return num_ranges;
7549 /*************************************************************
7550 * freetype_GetFontUnicodeRanges
7552 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7554 struct freetype_physdev *physdev = get_freetype_dev( dev );
7555 DWORD size, num_ranges;
7557 if (!physdev->font)
7559 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7560 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7563 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7564 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7565 if (glyphset)
7567 glyphset->cbThis = size;
7568 glyphset->cRanges = num_ranges;
7569 glyphset->flAccel = 0;
7571 return size;
7574 /*************************************************************
7575 * freetype_FontIsLinked
7577 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7579 struct freetype_physdev *physdev = get_freetype_dev( dev );
7580 BOOL ret;
7582 if (!physdev->font)
7584 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7585 return dev->funcs->pFontIsLinked( dev );
7588 GDI_CheckNotLock();
7589 EnterCriticalSection( &freetype_cs );
7590 ret = !list_empty(&physdev->font->child_fonts);
7591 LeaveCriticalSection( &freetype_cs );
7592 return ret;
7595 /*************************************************************************
7596 * GetRasterizerCaps (GDI32.@)
7598 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7600 lprs->nSize = sizeof(RASTERIZER_STATUS);
7601 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7602 lprs->nLanguageID = 0;
7603 return TRUE;
7606 /*************************************************************
7607 * freetype_GdiRealizationInfo
7609 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7611 struct freetype_physdev *physdev = get_freetype_dev( dev );
7612 realization_info_t *info = ptr;
7614 if (!physdev->font)
7616 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7617 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7620 FIXME("(%p, %p): stub!\n", physdev->font, info);
7622 info->flags = 1;
7623 if(FT_IS_SCALABLE(physdev->font->ft_face))
7624 info->flags |= 2;
7626 info->cache_num = physdev->font->cache_num;
7627 info->unknown2 = -1;
7628 return TRUE;
7631 /*************************************************************************
7632 * Kerning support for TrueType fonts
7634 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7636 struct TT_kern_table
7638 USHORT version;
7639 USHORT nTables;
7642 struct TT_kern_subtable
7644 USHORT version;
7645 USHORT length;
7646 union
7648 USHORT word;
7649 struct
7651 USHORT horizontal : 1;
7652 USHORT minimum : 1;
7653 USHORT cross_stream: 1;
7654 USHORT override : 1;
7655 USHORT reserved1 : 4;
7656 USHORT format : 8;
7657 } bits;
7658 } coverage;
7661 struct TT_format0_kern_subtable
7663 USHORT nPairs;
7664 USHORT searchRange;
7665 USHORT entrySelector;
7666 USHORT rangeShift;
7669 struct TT_kern_pair
7671 USHORT left;
7672 USHORT right;
7673 short value;
7676 static DWORD parse_format0_kern_subtable(GdiFont *font,
7677 const struct TT_format0_kern_subtable *tt_f0_ks,
7678 const USHORT *glyph_to_char,
7679 KERNINGPAIR *kern_pair, DWORD cPairs)
7681 USHORT i, nPairs;
7682 const struct TT_kern_pair *tt_kern_pair;
7684 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7686 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7688 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7689 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7690 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7692 if (!kern_pair || !cPairs)
7693 return nPairs;
7695 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7697 nPairs = min(nPairs, cPairs);
7699 for (i = 0; i < nPairs; i++)
7701 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7702 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7703 /* this algorithm appears to better match what Windows does */
7704 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7705 if (kern_pair->iKernAmount < 0)
7707 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7708 kern_pair->iKernAmount -= font->ppem;
7710 else if (kern_pair->iKernAmount > 0)
7712 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7713 kern_pair->iKernAmount += font->ppem;
7715 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7717 TRACE("left %u right %u value %d\n",
7718 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7720 kern_pair++;
7722 TRACE("copied %u entries\n", nPairs);
7723 return nPairs;
7726 /*************************************************************
7727 * freetype_GetKerningPairs
7729 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7731 DWORD length;
7732 void *buf;
7733 const struct TT_kern_table *tt_kern_table;
7734 const struct TT_kern_subtable *tt_kern_subtable;
7735 USHORT i, nTables;
7736 USHORT *glyph_to_char;
7737 GdiFont *font;
7738 struct freetype_physdev *physdev = get_freetype_dev( dev );
7740 if (!(font = physdev->font))
7742 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7743 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7746 GDI_CheckNotLock();
7747 EnterCriticalSection( &freetype_cs );
7748 if (font->total_kern_pairs != (DWORD)-1)
7750 if (cPairs && kern_pair)
7752 cPairs = min(cPairs, font->total_kern_pairs);
7753 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7755 else cPairs = font->total_kern_pairs;
7757 LeaveCriticalSection( &freetype_cs );
7758 return cPairs;
7761 font->total_kern_pairs = 0;
7763 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7765 if (length == GDI_ERROR)
7767 TRACE("no kerning data in the font\n");
7768 LeaveCriticalSection( &freetype_cs );
7769 return 0;
7772 buf = HeapAlloc(GetProcessHeap(), 0, length);
7773 if (!buf)
7775 WARN("Out of memory\n");
7776 LeaveCriticalSection( &freetype_cs );
7777 return 0;
7780 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7782 /* build a glyph index to char code map */
7783 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7784 if (!glyph_to_char)
7786 WARN("Out of memory allocating a glyph index to char code map\n");
7787 HeapFree(GetProcessHeap(), 0, buf);
7788 LeaveCriticalSection( &freetype_cs );
7789 return 0;
7792 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7794 FT_UInt glyph_code;
7795 FT_ULong char_code;
7797 glyph_code = 0;
7798 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7800 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7801 font->ft_face->num_glyphs, glyph_code, char_code);
7803 while (glyph_code)
7805 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7807 /* FIXME: This doesn't match what Windows does: it does some fancy
7808 * things with duplicate glyph index to char code mappings, while
7809 * we just avoid overriding existing entries.
7811 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7812 glyph_to_char[glyph_code] = (USHORT)char_code;
7814 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7817 else
7819 ULONG n;
7821 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7822 for (n = 0; n <= 65535; n++)
7823 glyph_to_char[n] = (USHORT)n;
7826 tt_kern_table = buf;
7827 nTables = GET_BE_WORD(tt_kern_table->nTables);
7828 TRACE("version %u, nTables %u\n",
7829 GET_BE_WORD(tt_kern_table->version), nTables);
7831 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7833 for (i = 0; i < nTables; i++)
7835 struct TT_kern_subtable tt_kern_subtable_copy;
7837 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7838 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7839 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7841 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7842 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7843 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7845 /* According to the TrueType specification this is the only format
7846 * that will be properly interpreted by Windows and OS/2
7848 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7850 DWORD new_chunk, old_total = font->total_kern_pairs;
7852 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7853 glyph_to_char, NULL, 0);
7854 font->total_kern_pairs += new_chunk;
7856 if (!font->kern_pairs)
7857 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7858 font->total_kern_pairs * sizeof(*font->kern_pairs));
7859 else
7860 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7861 font->total_kern_pairs * sizeof(*font->kern_pairs));
7863 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7864 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7866 else
7867 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7869 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7872 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7873 HeapFree(GetProcessHeap(), 0, buf);
7875 if (cPairs && kern_pair)
7877 cPairs = min(cPairs, font->total_kern_pairs);
7878 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7880 else cPairs = font->total_kern_pairs;
7882 LeaveCriticalSection( &freetype_cs );
7883 return cPairs;
7886 static const struct gdi_dc_funcs freetype_funcs =
7888 NULL, /* pAbortDoc */
7889 NULL, /* pAbortPath */
7890 NULL, /* pAlphaBlend */
7891 NULL, /* pAngleArc */
7892 NULL, /* pArc */
7893 NULL, /* pArcTo */
7894 NULL, /* pBeginPath */
7895 NULL, /* pBlendImage */
7896 NULL, /* pChord */
7897 NULL, /* pCloseFigure */
7898 NULL, /* pCreateCompatibleDC */
7899 freetype_CreateDC, /* pCreateDC */
7900 freetype_DeleteDC, /* pDeleteDC */
7901 NULL, /* pDeleteObject */
7902 NULL, /* pDeviceCapabilities */
7903 NULL, /* pEllipse */
7904 NULL, /* pEndDoc */
7905 NULL, /* pEndPage */
7906 NULL, /* pEndPath */
7907 freetype_EnumFonts, /* pEnumFonts */
7908 NULL, /* pEnumICMProfiles */
7909 NULL, /* pExcludeClipRect */
7910 NULL, /* pExtDeviceMode */
7911 NULL, /* pExtEscape */
7912 NULL, /* pExtFloodFill */
7913 NULL, /* pExtSelectClipRgn */
7914 NULL, /* pExtTextOut */
7915 NULL, /* pFillPath */
7916 NULL, /* pFillRgn */
7917 NULL, /* pFlattenPath */
7918 freetype_FontIsLinked, /* pFontIsLinked */
7919 NULL, /* pFrameRgn */
7920 NULL, /* pGdiComment */
7921 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7922 NULL, /* pGetBoundsRect */
7923 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7924 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7925 freetype_GetCharWidth, /* pGetCharWidth */
7926 NULL, /* pGetDeviceCaps */
7927 NULL, /* pGetDeviceGammaRamp */
7928 freetype_GetFontData, /* pGetFontData */
7929 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7930 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7931 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7932 NULL, /* pGetICMProfile */
7933 NULL, /* pGetImage */
7934 freetype_GetKerningPairs, /* pGetKerningPairs */
7935 NULL, /* pGetNearestColor */
7936 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7937 NULL, /* pGetPixel */
7938 NULL, /* pGetSystemPaletteEntries */
7939 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7940 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7941 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7942 freetype_GetTextFace, /* pGetTextFace */
7943 freetype_GetTextMetrics, /* pGetTextMetrics */
7944 NULL, /* pGradientFill */
7945 NULL, /* pIntersectClipRect */
7946 NULL, /* pInvertRgn */
7947 NULL, /* pLineTo */
7948 NULL, /* pModifyWorldTransform */
7949 NULL, /* pMoveTo */
7950 NULL, /* pOffsetClipRgn */
7951 NULL, /* pOffsetViewportOrg */
7952 NULL, /* pOffsetWindowOrg */
7953 NULL, /* pPaintRgn */
7954 NULL, /* pPatBlt */
7955 NULL, /* pPie */
7956 NULL, /* pPolyBezier */
7957 NULL, /* pPolyBezierTo */
7958 NULL, /* pPolyDraw */
7959 NULL, /* pPolyPolygon */
7960 NULL, /* pPolyPolyline */
7961 NULL, /* pPolygon */
7962 NULL, /* pPolyline */
7963 NULL, /* pPolylineTo */
7964 NULL, /* pPutImage */
7965 NULL, /* pRealizeDefaultPalette */
7966 NULL, /* pRealizePalette */
7967 NULL, /* pRectangle */
7968 NULL, /* pResetDC */
7969 NULL, /* pRestoreDC */
7970 NULL, /* pRoundRect */
7971 NULL, /* pSaveDC */
7972 NULL, /* pScaleViewportExt */
7973 NULL, /* pScaleWindowExt */
7974 NULL, /* pSelectBitmap */
7975 NULL, /* pSelectBrush */
7976 NULL, /* pSelectClipPath */
7977 freetype_SelectFont, /* pSelectFont */
7978 NULL, /* pSelectPalette */
7979 NULL, /* pSelectPen */
7980 NULL, /* pSetArcDirection */
7981 NULL, /* pSetBkColor */
7982 NULL, /* pSetBkMode */
7983 NULL, /* pSetDCBrushColor */
7984 NULL, /* pSetDCPenColor */
7985 NULL, /* pSetDIBColorTable */
7986 NULL, /* pSetDIBitsToDevice */
7987 NULL, /* pSetDeviceClipping */
7988 NULL, /* pSetDeviceGammaRamp */
7989 NULL, /* pSetLayout */
7990 NULL, /* pSetMapMode */
7991 NULL, /* pSetMapperFlags */
7992 NULL, /* pSetPixel */
7993 NULL, /* pSetPolyFillMode */
7994 NULL, /* pSetROP2 */
7995 NULL, /* pSetRelAbs */
7996 NULL, /* pSetStretchBltMode */
7997 NULL, /* pSetTextAlign */
7998 NULL, /* pSetTextCharacterExtra */
7999 NULL, /* pSetTextColor */
8000 NULL, /* pSetTextJustification */
8001 NULL, /* pSetViewportExt */
8002 NULL, /* pSetViewportOrg */
8003 NULL, /* pSetWindowExt */
8004 NULL, /* pSetWindowOrg */
8005 NULL, /* pSetWorldTransform */
8006 NULL, /* pStartDoc */
8007 NULL, /* pStartPage */
8008 NULL, /* pStretchBlt */
8009 NULL, /* pStretchDIBits */
8010 NULL, /* pStrokeAndFillPath */
8011 NULL, /* pStrokePath */
8012 NULL, /* pUnrealizePalette */
8013 NULL, /* pWidenPath */
8014 NULL, /* wine_get_wgl_driver */
8015 GDI_PRIORITY_FONT_DRV /* priority */
8018 #else /* HAVE_FREETYPE */
8020 /*************************************************************************/
8022 BOOL WineEngInit(void)
8024 return FALSE;
8027 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8029 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8030 return 1;
8033 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
8035 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
8036 return TRUE;
8039 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8041 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8042 return NULL;
8045 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8046 LPCWSTR font_file, LPCWSTR font_path )
8048 FIXME("stub\n");
8049 return FALSE;
8052 /*************************************************************************
8053 * GetRasterizerCaps (GDI32.@)
8055 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8057 lprs->nSize = sizeof(RASTERIZER_STATUS);
8058 lprs->wFlags = 0;
8059 lprs->nLanguageID = 0;
8060 return TRUE;
8063 #endif /* HAVE_FREETYPE */