gdi32: Store the font stat information when loading it.
[wine.git] / dlls / gdi32 / freetype.c
blob5b10d0d9cc008213b23739203856ca3f74c660b2
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_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
542 static void remove_face_from_cache( Face *face );
544 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
545 'W','i','n','d','o','w','s',' ','N','T','\\',
546 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
547 'S','y','s','t','e','m','L','i','n','k',0};
549 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
550 'F','o','n','t','L','i','n','k','\\',
551 'S','y','s','t','e','m','L','i','n','k',0};
553 /****************************************
554 * Notes on .fon files
556 * The fonts System, FixedSys and Terminal are special. There are typically multiple
557 * versions installed for different resolutions and codepages. Windows stores which one to use
558 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
559 * Key Meaning
560 * FIXEDFON.FON FixedSys
561 * FONTS.FON System
562 * OEMFONT.FON Terminal
563 * LogPixels Current dpi set by the display control panel applet
564 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
565 * also has a LogPixels value that appears to mirror this)
567 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
568 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
569 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
570 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
571 * so that makes sense.
573 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
574 * to be mapped into the registry on Windows 2000 at least).
575 * I have
576 * woafont=app850.fon
577 * ega80woa.fon=ega80850.fon
578 * ega40woa.fon=ega40850.fon
579 * cga80woa.fon=cga80850.fon
580 * cga40woa.fon=cga40850.fon
583 /* These are all structures needed for the GSUB table */
585 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
586 #define TATEGAKI_LOWER_BOUND 0x02F1
588 typedef struct {
589 DWORD version;
590 WORD ScriptList;
591 WORD FeatureList;
592 WORD LookupList;
593 } GSUB_Header;
595 typedef struct {
596 CHAR ScriptTag[4];
597 WORD Script;
598 } GSUB_ScriptRecord;
600 typedef struct {
601 WORD ScriptCount;
602 GSUB_ScriptRecord ScriptRecord[1];
603 } GSUB_ScriptList;
605 typedef struct {
606 CHAR LangSysTag[4];
607 WORD LangSys;
608 } GSUB_LangSysRecord;
610 typedef struct {
611 WORD DefaultLangSys;
612 WORD LangSysCount;
613 GSUB_LangSysRecord LangSysRecord[1];
614 } GSUB_Script;
616 typedef struct {
617 WORD LookupOrder; /* Reserved */
618 WORD ReqFeatureIndex;
619 WORD FeatureCount;
620 WORD FeatureIndex[1];
621 } GSUB_LangSys;
623 typedef struct {
624 CHAR FeatureTag[4];
625 WORD Feature;
626 } GSUB_FeatureRecord;
628 typedef struct {
629 WORD FeatureCount;
630 GSUB_FeatureRecord FeatureRecord[1];
631 } GSUB_FeatureList;
633 typedef struct {
634 WORD FeatureParams; /* Reserved */
635 WORD LookupCount;
636 WORD LookupListIndex[1];
637 } GSUB_Feature;
639 typedef struct {
640 WORD LookupCount;
641 WORD Lookup[1];
642 } GSUB_LookupList;
644 typedef struct {
645 WORD LookupType;
646 WORD LookupFlag;
647 WORD SubTableCount;
648 WORD SubTable[1];
649 } GSUB_LookupTable;
651 typedef struct {
652 WORD CoverageFormat;
653 WORD GlyphCount;
654 WORD GlyphArray[1];
655 } GSUB_CoverageFormat1;
657 typedef struct {
658 WORD Start;
659 WORD End;
660 WORD StartCoverageIndex;
661 } GSUB_RangeRecord;
663 typedef struct {
664 WORD CoverageFormat;
665 WORD RangeCount;
666 GSUB_RangeRecord RangeRecord[1];
667 } GSUB_CoverageFormat2;
669 typedef struct {
670 WORD SubstFormat; /* = 1 */
671 WORD Coverage;
672 WORD DeltaGlyphID;
673 } GSUB_SingleSubstFormat1;
675 typedef struct {
676 WORD SubstFormat; /* = 2 */
677 WORD Coverage;
678 WORD GlyphCount;
679 WORD Substitute[1];
680 }GSUB_SingleSubstFormat2;
682 #ifdef HAVE_CARBON_CARBON_H
683 static char *find_cache_dir(void)
685 FSRef ref;
686 OSErr err;
687 static char cached_path[MAX_PATH];
688 static const char *wine = "/Wine", *fonts = "/Fonts";
690 if(*cached_path) return cached_path;
692 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
693 if(err != noErr)
695 WARN("can't create cached data folder\n");
696 return NULL;
698 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
699 if(err != noErr)
701 WARN("can't create cached data path\n");
702 *cached_path = '\0';
703 return NULL;
705 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
707 ERR("Could not create full path\n");
708 *cached_path = '\0';
709 return NULL;
711 strcat(cached_path, wine);
713 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
715 WARN("Couldn't mkdir %s\n", cached_path);
716 *cached_path = '\0';
717 return NULL;
719 strcat(cached_path, fonts);
720 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
722 WARN("Couldn't mkdir %s\n", cached_path);
723 *cached_path = '\0';
724 return NULL;
726 return cached_path;
729 /******************************************************************
730 * expand_mac_font
732 * Extracts individual TrueType font files from a Mac suitcase font
733 * and saves them into the user's caches directory (see
734 * find_cache_dir()).
735 * Returns a NULL terminated array of filenames.
737 * We do this because they are apps that try to read ttf files
738 * themselves and they don't like Mac suitcase files.
740 static char **expand_mac_font(const char *path)
742 FSRef ref;
743 SInt16 res_ref;
744 OSStatus s;
745 unsigned int idx;
746 const char *out_dir;
747 const char *filename;
748 int output_len;
749 struct {
750 char **array;
751 unsigned int size, max_size;
752 } ret;
754 TRACE("path %s\n", path);
756 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
757 if(s != noErr)
759 WARN("failed to get ref\n");
760 return NULL;
763 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
764 if(s != noErr)
766 TRACE("no data fork, so trying resource fork\n");
767 res_ref = FSOpenResFile(&ref, fsRdPerm);
768 if(res_ref == -1)
770 TRACE("unable to open resource fork\n");
771 return NULL;
775 ret.size = 0;
776 ret.max_size = 10;
777 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
778 if(!ret.array)
780 CloseResFile(res_ref);
781 return NULL;
784 out_dir = find_cache_dir();
786 filename = strrchr(path, '/');
787 if(!filename) filename = path;
788 else filename++;
790 /* output filename has the form out_dir/filename_%04x.ttf */
791 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
793 UseResFile(res_ref);
794 idx = 1;
795 while(1)
797 FamRec *fam_rec;
798 unsigned short *num_faces_ptr, num_faces, face;
799 AsscEntry *assoc;
800 Handle fond;
801 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
803 fond = Get1IndResource(fond_res, idx);
804 if(!fond) break;
805 TRACE("got fond resource %d\n", idx);
806 HLock(fond);
808 fam_rec = *(FamRec**)fond;
809 num_faces_ptr = (unsigned short *)(fam_rec + 1);
810 num_faces = GET_BE_WORD(*num_faces_ptr);
811 num_faces++;
812 assoc = (AsscEntry*)(num_faces_ptr + 1);
813 TRACE("num faces %04x\n", num_faces);
814 for(face = 0; face < num_faces; face++, assoc++)
816 Handle sfnt;
817 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
818 unsigned short size, font_id;
819 char *output;
821 size = GET_BE_WORD(assoc->fontSize);
822 font_id = GET_BE_WORD(assoc->fontID);
823 if(size != 0)
825 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
826 continue;
829 TRACE("trying to load sfnt id %04x\n", font_id);
830 sfnt = GetResource(sfnt_res, font_id);
831 if(!sfnt)
833 TRACE("can't get sfnt resource %04x\n", font_id);
834 continue;
837 output = HeapAlloc(GetProcessHeap(), 0, output_len);
838 if(output)
840 int fd;
842 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
844 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
845 if(fd != -1 || errno == EEXIST)
847 if(fd != -1)
849 unsigned char *sfnt_data;
851 HLock(sfnt);
852 sfnt_data = *(unsigned char**)sfnt;
853 write(fd, sfnt_data, GetHandleSize(sfnt));
854 HUnlock(sfnt);
855 close(fd);
857 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
859 ret.max_size *= 2;
860 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
862 ret.array[ret.size++] = output;
864 else
866 WARN("unable to create %s\n", output);
867 HeapFree(GetProcessHeap(), 0, output);
870 ReleaseResource(sfnt);
872 HUnlock(fond);
873 ReleaseResource(fond);
874 idx++;
876 CloseResFile(res_ref);
878 return ret.array;
881 #endif /* HAVE_CARBON_CARBON_H */
883 static inline BOOL is_win9x(void)
885 return GetVersion() & 0x80000000;
888 This function builds an FT_Fixed from a double. It fails if the absolute
889 value of the float number is greater than 32768.
891 static inline FT_Fixed FT_FixedFromFloat(double f)
893 return f * 0x10000;
897 This function builds an FT_Fixed from a FIXED. It simply put f.value
898 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
900 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
902 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
905 static BOOL is_hinting_enabled(void)
907 static int enabled = -1;
909 if (enabled == -1)
911 /* Use the >= 2.2.0 function if available */
912 if (pFT_Get_TrueType_Engine_Type)
914 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
915 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
917 #ifdef FT_DRIVER_HAS_HINTER
918 else
920 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
921 FT_Module mod = pFT_Get_Module(library, "truetype");
922 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
924 #endif
925 else enabled = FALSE;
926 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
928 return enabled;
931 static BOOL is_subpixel_rendering_enabled( void )
933 #ifdef HAVE_FREETYPE_FTLCDFIL_H
934 static int enabled = -1;
935 if (enabled == -1)
937 enabled = (pFT_Library_SetLcdFilter &&
938 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
939 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
941 return enabled;
942 #else
943 return FALSE;
944 #endif
948 static const struct list *get_face_list_from_family(const Family *family)
950 if (!list_empty(&family->faces))
951 return &family->faces;
952 else
953 return family->replacement;
956 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
958 Family *family;
959 Face *face;
960 const WCHAR *file;
962 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
964 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
966 const struct list *face_list;
967 if(face_name && strcmpiW(face_name, family->FamilyName))
968 continue;
969 face_list = get_face_list_from_family(family);
970 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
972 if (!face->file)
973 continue;
974 file = strrchrW(face->file, '/');
975 if(!file)
976 file = face->file;
977 else
978 file++;
979 if(strcmpiW(file, file_name)) continue;
980 face->refcount++;
981 return face;
984 return NULL;
987 static Family *find_family_from_name(const WCHAR *name)
989 Family *family;
991 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
993 if(!strcmpiW(family->FamilyName, name))
994 return family;
997 return NULL;
1000 static Family *find_family_from_any_name(const WCHAR *name)
1002 Family *family;
1004 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
1006 if(!strcmpiW(family->FamilyName, name))
1007 return family;
1008 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1009 return family;
1012 return NULL;
1015 static void DumpSubstList(void)
1017 FontSubst *psub;
1019 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1021 if(psub->from.charset != -1 || psub->to.charset != -1)
1022 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1023 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1024 else
1025 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1026 debugstr_w(psub->to.name));
1028 return;
1031 static LPWSTR strdupW(LPCWSTR p)
1033 LPWSTR ret;
1034 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1035 ret = HeapAlloc(GetProcessHeap(), 0, len);
1036 memcpy(ret, p, len);
1037 return ret;
1040 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1041 INT from_charset)
1043 FontSubst *element;
1045 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1047 if(!strcmpiW(element->from.name, from_name) &&
1048 (element->from.charset == from_charset ||
1049 element->from.charset == -1))
1050 return element;
1053 return NULL;
1056 #define ADD_FONT_SUBST_FORCE 1
1058 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1060 FontSubst *from_exist, *to_exist;
1062 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1064 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1066 list_remove(&from_exist->entry);
1067 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1068 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1069 HeapFree(GetProcessHeap(), 0, from_exist);
1070 from_exist = NULL;
1073 if(!from_exist)
1075 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1077 if(to_exist)
1079 HeapFree(GetProcessHeap(), 0, subst->to.name);
1080 subst->to.name = strdupW(to_exist->to.name);
1083 list_add_tail(subst_list, &subst->entry);
1085 return TRUE;
1088 HeapFree(GetProcessHeap(), 0, subst->from.name);
1089 HeapFree(GetProcessHeap(), 0, subst->to.name);
1090 HeapFree(GetProcessHeap(), 0, subst);
1091 return FALSE;
1094 static WCHAR *towstr(UINT cp, const char *str)
1096 int len;
1097 WCHAR *wstr;
1099 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1100 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1101 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1102 return wstr;
1105 static char *strWtoA(UINT cp, const WCHAR *str)
1107 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1108 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1109 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1110 return ret;
1113 static void split_subst_info(NameCs *nc, LPSTR str)
1115 CHAR *p = strrchr(str, ',');
1117 nc->charset = -1;
1118 if(p && *(p+1)) {
1119 nc->charset = strtol(p+1, NULL, 10);
1120 *p = '\0';
1122 nc->name = towstr(CP_ACP, str);
1125 static void LoadSubstList(void)
1127 FontSubst *psub;
1128 HKEY hkey;
1129 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1130 LPSTR value;
1131 LPVOID data;
1133 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1134 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1135 &hkey) == ERROR_SUCCESS) {
1137 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1138 &valuelen, &datalen, NULL, NULL);
1140 valuelen++; /* returned value doesn't include room for '\0' */
1141 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1142 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1144 dlen = datalen;
1145 vlen = valuelen;
1146 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1147 &dlen) == ERROR_SUCCESS) {
1148 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1150 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1151 split_subst_info(&psub->from, value);
1152 split_subst_info(&psub->to, data);
1154 /* Win 2000 doesn't allow mapping between different charsets
1155 or mapping of DEFAULT_CHARSET */
1156 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1157 psub->to.charset == DEFAULT_CHARSET) {
1158 HeapFree(GetProcessHeap(), 0, psub->to.name);
1159 HeapFree(GetProcessHeap(), 0, psub->from.name);
1160 HeapFree(GetProcessHeap(), 0, psub);
1161 } else {
1162 add_font_subst(&font_subst_list, psub, 0);
1164 /* reset dlen and vlen */
1165 dlen = datalen;
1166 vlen = valuelen;
1168 HeapFree(GetProcessHeap(), 0, data);
1169 HeapFree(GetProcessHeap(), 0, value);
1170 RegCloseKey(hkey);
1175 /*****************************************************************
1176 * get_name_table_entry
1178 * Supply the platform, encoding, language and name ids in req
1179 * and if the name exists the function will fill in the string
1180 * and string_len members. The string is owned by FreeType so
1181 * don't free it. Returns TRUE if the name is found else FALSE.
1183 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1185 FT_SfntName name;
1186 FT_UInt num_names, name_index;
1188 if(FT_IS_SFNT(ft_face))
1190 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1192 for(name_index = 0; name_index < num_names; name_index++)
1194 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1196 if((name.platform_id == req->platform_id) &&
1197 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1198 (name.language_id == req->language_id) &&
1199 (name.name_id == req->name_id))
1201 req->string = name.string;
1202 req->string_len = name.string_len;
1203 return TRUE;
1208 req->string = NULL;
1209 req->string_len = 0;
1210 return FALSE;
1213 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1215 WCHAR *ret = NULL;
1216 FT_SfntName name;
1218 name.platform_id = TT_PLATFORM_MICROSOFT;
1219 name.language_id = language_id;
1220 name.name_id = name_id;
1222 if(get_name_table_entry(ft_face, &name))
1224 FT_UInt i;
1226 /* String is not nul terminated and string_len is a byte length. */
1227 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1228 for(i = 0; i < name.string_len / 2; i++)
1230 WORD *tmp = (WORD *)&name.string[i * 2];
1231 ret[i] = GET_BE_WORD(*tmp);
1233 ret[i] = 0;
1234 TRACE("Got localised name %s\n", debugstr_w(ret));
1237 return ret;
1240 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1242 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1243 if (f1->scalable) return TRUE;
1244 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1245 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1248 static void release_family( Family *family )
1250 if (--family->refcount) return;
1251 assert( list_empty( &family->faces ));
1252 list_remove( &family->entry );
1253 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1254 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1255 HeapFree( GetProcessHeap(), 0, family );
1258 static void release_face( Face *face )
1260 if (--face->refcount) return;
1261 if (face->family)
1263 if (face->flags & ADDFONT_ADD_TO_CACHE) remove_face_from_cache( face );
1264 list_remove( &face->entry );
1265 release_family( face->family );
1267 HeapFree( GetProcessHeap(), 0, face->file );
1268 HeapFree( GetProcessHeap(), 0, face->StyleName );
1269 HeapFree( GetProcessHeap(), 0, face->FullName );
1270 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1271 HeapFree( GetProcessHeap(), 0, face );
1274 static inline int style_order(const Face *face)
1276 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1278 case NTM_REGULAR:
1279 return 0;
1280 case NTM_BOLD:
1281 return 1;
1282 case NTM_ITALIC:
1283 return 2;
1284 case NTM_BOLD | NTM_ITALIC:
1285 return 3;
1286 default:
1287 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1288 debugstr_w(face->family->FamilyName),
1289 debugstr_w(face->StyleName),
1290 face->ntmFlags);
1291 return 9999;
1295 static BOOL insert_face_in_family_list( Face *face, Family *family )
1297 Face *cursor;
1299 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1301 if (faces_equal( face, cursor ))
1303 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1304 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1305 cursor->font_version, face->font_version);
1307 if (face->font_version <= cursor->font_version)
1309 TRACE("Original font %s is newer so skipping %s\n",
1310 debugstr_w(cursor->file), debugstr_w(face->file));
1311 return FALSE;
1313 else
1315 TRACE("Replacing original %s with %s\n",
1316 debugstr_w(cursor->file), debugstr_w(face->file));
1317 list_add_before( &cursor->entry, &face->entry );
1318 face->family = family;
1319 family->refcount++;
1320 face->refcount++;
1321 release_face( cursor );
1322 return TRUE;
1325 else
1326 TRACE("Adding new %s\n", debugstr_w(face->file));
1328 if (style_order( face ) < style_order( cursor )) break;
1331 list_add_before( &cursor->entry, &face->entry );
1332 face->family = family;
1333 family->refcount++;
1334 face->refcount++;
1335 return TRUE;
1338 /****************************************************************
1339 * NB This function stores the ptrs to the strings to save copying.
1340 * Don't free them after calling.
1342 static Family *create_family( WCHAR *name, WCHAR *english_name )
1344 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1345 family->refcount = 1;
1346 family->FamilyName = name;
1347 family->EnglishName = english_name;
1348 list_init( &family->faces );
1349 family->replacement = &family->faces;
1350 list_add_tail( &font_list, &family->entry );
1352 return family;
1355 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1357 DWORD type, size = sizeof(DWORD);
1359 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1360 type != REG_DWORD || size != sizeof(DWORD))
1362 *data = 0;
1363 return ERROR_BAD_CONFIGURATION;
1365 return ERROR_SUCCESS;
1368 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1370 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1373 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1375 DWORD needed, strike_index = 0;
1376 HKEY hkey_strike;
1378 /* If we have a File Name key then this is a real font, not just the parent
1379 key of a bunch of non-scalable strikes */
1380 needed = buffer_size;
1381 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1383 Face *face;
1384 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1385 face->cached_enum_data = NULL;
1386 face->family = NULL;
1388 face->refcount = 1;
1389 face->file = strdupW( buffer );
1390 face->StyleName = strdupW(face_name);
1392 needed = buffer_size;
1393 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1394 face->FullName = strdupW( buffer );
1395 else
1396 face->FullName = NULL;
1398 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1399 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1400 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1401 reg_load_dword(hkey_face, face_flags_value, (DWORD*)&face->flags);
1403 needed = sizeof(face->fs);
1404 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1406 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1408 face->scalable = TRUE;
1409 memset(&face->size, 0, sizeof(face->size));
1411 else
1413 face->scalable = FALSE;
1414 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1415 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1416 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1417 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1418 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1420 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1421 face->size.height, face->size.width, face->size.size >> 6,
1422 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1425 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1426 face->fs.fsCsb[0], face->fs.fsCsb[1],
1427 face->fs.fsUsb[0], face->fs.fsUsb[1],
1428 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1430 if (insert_face_in_family_list(face, family))
1431 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1433 release_face( face );
1436 /* load bitmap strikes */
1438 needed = buffer_size;
1439 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1441 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1443 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1444 RegCloseKey(hkey_strike);
1446 needed = buffer_size;
1450 static void load_font_list_from_cache(HKEY hkey_font_cache)
1452 DWORD size, family_index = 0;
1453 Family *family;
1454 HKEY hkey_family;
1455 WCHAR buffer[4096];
1457 size = sizeof(buffer);
1458 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1460 WCHAR *english_family = NULL;
1461 WCHAR *family_name = strdupW( buffer );
1462 DWORD face_index = 0;
1464 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1465 TRACE("opened family key %s\n", debugstr_w(family_name));
1466 size = sizeof(buffer);
1467 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1468 english_family = strdupW( buffer );
1470 family = create_family(family_name, english_family);
1472 if(english_family)
1474 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1475 subst->from.name = strdupW(english_family);
1476 subst->from.charset = -1;
1477 subst->to.name = strdupW(family_name);
1478 subst->to.charset = -1;
1479 add_font_subst(&font_subst_list, subst, 0);
1482 size = sizeof(buffer);
1483 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1485 WCHAR *face_name = strdupW( buffer );
1486 HKEY hkey_face;
1488 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1490 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1491 RegCloseKey(hkey_face);
1493 HeapFree( GetProcessHeap(), 0, face_name );
1494 size = sizeof(buffer);
1496 RegCloseKey(hkey_family);
1497 release_family( family );
1498 size = sizeof(buffer);
1502 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1504 LONG ret;
1505 HKEY hkey_wine_fonts;
1507 /* We don't want to create the fonts key as volatile, so open this first */
1508 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1509 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1510 if(ret != ERROR_SUCCESS)
1512 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1513 return ret;
1516 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1517 KEY_ALL_ACCESS, NULL, hkey, disposition);
1518 RegCloseKey(hkey_wine_fonts);
1519 return ret;
1522 static void add_face_to_cache(Face *face)
1524 HKEY hkey_family, hkey_face;
1525 WCHAR *face_key_name;
1527 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1528 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1529 if(face->family->EnglishName)
1530 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1531 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1533 if(face->scalable)
1534 face_key_name = face->StyleName;
1535 else
1537 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1538 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1539 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1541 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1542 &hkey_face, NULL);
1543 if(!face->scalable)
1544 HeapFree(GetProcessHeap(), 0, face_key_name);
1546 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1547 (strlenW(face->file) + 1) * sizeof(WCHAR));
1548 if (face->FullName)
1549 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1550 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1552 reg_save_dword(hkey_face, face_index_value, face->face_index);
1553 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1554 reg_save_dword(hkey_face, face_version_value, face->font_version);
1555 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1557 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1559 if(!face->scalable)
1561 reg_save_dword(hkey_face, face_height_value, face->size.height);
1562 reg_save_dword(hkey_face, face_width_value, face->size.width);
1563 reg_save_dword(hkey_face, face_size_value, face->size.size);
1564 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1565 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1566 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1568 RegCloseKey(hkey_face);
1569 RegCloseKey(hkey_family);
1572 static void remove_face_from_cache( Face *face )
1574 HKEY hkey_family;
1576 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1578 if (face->scalable)
1580 RegDeleteKeyW( hkey_family, face->StyleName );
1582 else
1584 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1585 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1586 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1587 RegDeleteKeyW( hkey_family, face_key_name );
1588 HeapFree(GetProcessHeap(), 0, face_key_name);
1590 RegCloseKey(hkey_family);
1593 static WCHAR *prepend_at(WCHAR *family)
1595 WCHAR *str;
1597 if (!family)
1598 return NULL;
1600 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1601 str[0] = '@';
1602 strcpyW(str + 1, family);
1603 HeapFree(GetProcessHeap(), 0, family);
1604 return str;
1607 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1609 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1610 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1612 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1613 if (!*name)
1615 *name = *english;
1616 *english = NULL;
1618 else if (!strcmpiW( *name, *english ))
1620 HeapFree( GetProcessHeap(), 0, *english );
1621 *english = NULL;
1624 if (vertical)
1626 *name = prepend_at( *name );
1627 *english = prepend_at( *english );
1631 static Family *get_family( FT_Face ft_face, BOOL vertical )
1633 Family *family;
1634 WCHAR *name, *english_name;
1636 get_family_names( ft_face, &name, &english_name, vertical );
1638 family = find_family_from_name( name );
1640 if (!family)
1642 family = create_family( name, english_name );
1643 if (english_name)
1645 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1646 subst->from.name = strdupW( english_name );
1647 subst->from.charset = -1;
1648 subst->to.name = strdupW( name );
1649 subst->to.charset = -1;
1650 add_font_subst( &font_subst_list, subst, 0 );
1653 else
1655 HeapFree( GetProcessHeap(), 0, name );
1656 HeapFree( GetProcessHeap(), 0, english_name );
1657 family->refcount++;
1660 return family;
1663 static inline FT_Fixed get_font_version( FT_Face ft_face )
1665 FT_Fixed version = 0;
1666 TT_Header *header;
1668 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1669 if (header) version = header->Font_Revision;
1671 return version;
1674 static inline DWORD get_ntm_flags( FT_Face ft_face )
1676 DWORD flags = 0;
1677 FT_ULong table_size = 0;
1679 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1680 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1681 if (flags == 0) flags = NTM_REGULAR;
1683 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1684 flags |= NTM_PS_OPENTYPE;
1686 return flags;
1689 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1691 int internal_leading = 0;
1692 FT_WinFNT_HeaderRec winfnt_header;
1694 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1695 internal_leading = winfnt_header.internal_leading;
1697 return internal_leading;
1700 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1702 TT_OS2 *os2;
1703 FT_UInt dummy;
1704 CHARSETINFO csi;
1705 FT_WinFNT_HeaderRec winfnt_header;
1706 int i;
1708 memset( fs, 0, sizeof(*fs) );
1710 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1711 if (os2)
1713 fs->fsUsb[0] = os2->ulUnicodeRange1;
1714 fs->fsUsb[1] = os2->ulUnicodeRange2;
1715 fs->fsUsb[2] = os2->ulUnicodeRange3;
1716 fs->fsUsb[3] = os2->ulUnicodeRange4;
1718 if (os2->version == 0)
1720 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1721 fs->fsCsb[0] = FS_LATIN1;
1722 else
1723 fs->fsCsb[0] = FS_SYMBOL;
1725 else
1727 fs->fsCsb[0] = os2->ulCodePageRange1;
1728 fs->fsCsb[1] = os2->ulCodePageRange2;
1731 else
1733 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1735 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1736 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1737 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1738 *fs = csi.fs;
1742 if (fs->fsCsb[0] == 0)
1744 /* let's see if we can find any interesting cmaps */
1745 for (i = 0; i < ft_face->num_charmaps; i++)
1747 switch (ft_face->charmaps[i]->encoding)
1749 case FT_ENCODING_UNICODE:
1750 case FT_ENCODING_APPLE_ROMAN:
1751 fs->fsCsb[0] |= FS_LATIN1;
1752 break;
1753 case FT_ENCODING_MS_SYMBOL:
1754 fs->fsCsb[0] |= FS_SYMBOL;
1755 break;
1756 default:
1757 break;
1763 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1764 DWORD flags )
1766 struct stat st;
1767 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1768 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1770 face->refcount = 1;
1771 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1772 if (!face->StyleName)
1773 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1774 if (!face->StyleName)
1776 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1779 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1780 if (!face->FullName)
1781 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1782 if (flags & ADDFONT_VERTICAL_FONT)
1783 face->FullName = prepend_at( face->FullName );
1785 face->dev = 0;
1786 face->ino = 0;
1787 if (file)
1789 face->file = towstr( CP_UNIXCP, file );
1790 face->font_data_ptr = NULL;
1791 face->font_data_size = 0;
1792 if (!stat( file, &st ))
1794 face->dev = st.st_dev;
1795 face->ino = st.st_ino;
1798 else
1800 face->file = NULL;
1801 face->font_data_ptr = font_data_ptr;
1802 face->font_data_size = font_data_size;
1805 face->face_index = face_index;
1806 get_fontsig( ft_face, &face->fs );
1807 face->ntmFlags = get_ntm_flags( ft_face );
1808 face->font_version = get_font_version( ft_face );
1810 if (FT_IS_SCALABLE( ft_face ))
1812 memset( &face->size, 0, sizeof(face->size) );
1813 face->scalable = TRUE;
1815 else
1817 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1818 size->height, size->width, size->size >> 6,
1819 size->x_ppem >> 6, size->y_ppem >> 6);
1820 face->size.height = size->height;
1821 face->size.width = size->width;
1822 face->size.size = size->size;
1823 face->size.x_ppem = size->x_ppem;
1824 face->size.y_ppem = size->y_ppem;
1825 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1826 face->scalable = FALSE;
1829 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1830 face->flags = flags;
1831 face->family = NULL;
1832 face->cached_enum_data = NULL;
1834 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1835 face->fs.fsCsb[0], face->fs.fsCsb[1],
1836 face->fs.fsUsb[0], face->fs.fsUsb[1],
1837 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1839 return face;
1842 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1843 FT_Long face_index, DWORD flags )
1845 Face *face;
1846 Family *family;
1848 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
1849 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
1850 if (insert_face_in_family_list( face, family ))
1852 if (flags & ADDFONT_ADD_TO_CACHE)
1853 add_face_to_cache( face );
1855 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1856 debugstr_w(face->StyleName));
1858 release_face( face );
1859 release_family( family );
1862 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1863 FT_Long face_index, BOOL allow_bitmap )
1865 FT_Error err;
1866 TT_OS2 *pOS2;
1867 FT_Face ft_face;
1869 if (file)
1871 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1872 err = pFT_New_Face(library, file, face_index, &ft_face);
1874 else
1876 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1877 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1880 if (err != 0)
1882 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1883 return NULL;
1886 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1887 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1889 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1890 goto fail;
1893 if (!FT_IS_SFNT( ft_face ))
1895 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1897 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1898 goto fail;
1901 else
1903 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1904 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1905 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1907 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1908 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1909 goto fail;
1912 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1913 we don't want to load these. */
1914 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1916 FT_ULong len = 0;
1918 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1920 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1921 goto fail;
1926 if (!ft_face->family_name || !ft_face->style_name)
1928 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1929 goto fail;
1932 return ft_face;
1933 fail:
1934 pFT_Done_Face( ft_face );
1935 return NULL;
1938 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1940 FT_Face ft_face;
1941 FT_Long face_index = 0, num_faces;
1942 INT ret = 0;
1944 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1945 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1947 #ifdef HAVE_CARBON_CARBON_H
1948 if(file)
1950 char **mac_list = expand_mac_font(file);
1951 if(mac_list)
1953 BOOL had_one = FALSE;
1954 char **cursor;
1955 for(cursor = mac_list; *cursor; cursor++)
1957 had_one = TRUE;
1958 AddFontToList(*cursor, NULL, 0, flags);
1959 HeapFree(GetProcessHeap(), 0, *cursor);
1961 HeapFree(GetProcessHeap(), 0, mac_list);
1962 if(had_one)
1963 return 1;
1966 #endif /* HAVE_CARBON_CARBON_H */
1968 do {
1969 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
1970 if (!ft_face) return 0;
1972 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1974 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1975 pFT_Done_Face(ft_face);
1976 return 0;
1979 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
1980 ++ret;
1982 if (FT_HAS_VERTICAL(ft_face))
1984 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
1985 flags | ADDFONT_VERTICAL_FONT);
1986 ++ret;
1989 num_faces = ft_face->num_faces;
1990 pFT_Done_Face(ft_face);
1991 } while(num_faces > ++face_index);
1992 return ret;
1995 static int remove_font_resource( const char *file, DWORD flags )
1997 Family *family, *family_next;
1998 Face *face, *face_next;
1999 struct stat st;
2000 int count = 0;
2002 if (stat( file, &st ) == -1) return 0;
2003 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2005 family->refcount++;
2006 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2008 if (!face->file) continue;
2009 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2010 if (st.st_dev == face->dev && st.st_ino == face->ino)
2012 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2013 release_face( face );
2014 count++;
2017 release_family( family );
2019 return count;
2022 static void DumpFontList(void)
2024 Family *family;
2025 Face *face;
2027 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2028 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2029 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2030 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2031 if(!face->scalable)
2032 TRACE(" %d", face->size.height);
2033 TRACE("\n");
2036 return;
2039 /***********************************************************
2040 * The replacement list is a way to map an entire font
2041 * family onto another family. For example adding
2043 * [HKCU\Software\Wine\Fonts\Replacements]
2044 * "Wingdings"="Winedings"
2046 * would enumerate the Winedings font both as Winedings and
2047 * Wingdings. However if a real Wingdings font is present the
2048 * replacement does not take place.
2051 static void LoadReplaceList(void)
2053 HKEY hkey;
2054 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2055 LPWSTR value;
2056 LPVOID data;
2058 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2059 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2061 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2062 &valuelen, &datalen, NULL, NULL);
2064 valuelen++; /* returned value doesn't include room for '\0' */
2065 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2066 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2068 dlen = datalen;
2069 vlen = valuelen;
2070 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2071 &dlen) == ERROR_SUCCESS) {
2072 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2073 /* "NewName"="Oldname" */
2074 if(!find_family_from_any_name(value))
2076 Family * const family = find_family_from_any_name(data);
2077 if (family != NULL)
2079 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2080 if (new_family != NULL)
2082 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2083 new_family->FamilyName = strdupW(value);
2084 new_family->EnglishName = NULL;
2085 list_init(&new_family->faces);
2086 new_family->replacement = &family->faces;
2087 list_add_tail(&font_list, &new_family->entry);
2090 else
2092 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2095 else
2097 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2099 /* reset dlen and vlen */
2100 dlen = datalen;
2101 vlen = valuelen;
2103 HeapFree(GetProcessHeap(), 0, data);
2104 HeapFree(GetProcessHeap(), 0, value);
2105 RegCloseKey(hkey);
2109 static const WCHAR *font_links_list[] =
2111 Lucida_Sans_Unicode,
2112 Microsoft_Sans_Serif,
2113 Tahoma
2116 static const struct font_links_defaults_list
2118 /* Keyed off substitution for "MS Shell Dlg" */
2119 const WCHAR *shelldlg;
2120 /* Maximum of four substitutes, plus terminating NULL pointer */
2121 const WCHAR *substitutes[5];
2122 } font_links_defaults_list[] =
2124 /* Non East-Asian */
2125 { Tahoma, /* FIXME unverified ordering */
2126 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2128 /* Below lists are courtesy of
2129 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2131 /* Japanese */
2132 { MS_UI_Gothic,
2133 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2135 /* Chinese Simplified */
2136 { SimSun,
2137 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2139 /* Korean */
2140 { Gulim,
2141 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2143 /* Chinese Traditional */
2144 { PMingLiU,
2145 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2150 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2152 SYSTEM_LINKS *font_link;
2154 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2156 if(!strcmpiW(font_link->font_name, name))
2157 return font_link;
2160 return NULL;
2163 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2165 const WCHAR *value;
2166 int i;
2167 FontSubst *psub;
2168 Family *family;
2169 Face *face;
2170 const WCHAR *file;
2172 if (values)
2174 SYSTEM_LINKS *font_link;
2176 psub = get_font_subst(&font_subst_list, name, -1);
2177 /* Don't store fonts that are only substitutes for other fonts */
2178 if(psub)
2180 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2181 return;
2184 font_link = find_font_link(name);
2185 if (font_link == NULL)
2187 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2188 font_link->font_name = strdupW(name);
2189 list_init(&font_link->links);
2190 list_add_tail(&system_links, &font_link->entry);
2193 memset(&font_link->fs, 0, sizeof font_link->fs);
2194 for (i = 0; values[i] != NULL; i++)
2196 const struct list *face_list;
2197 CHILD_FONT *child_font;
2199 value = values[i];
2200 if (!strcmpiW(name,value))
2201 continue;
2202 psub = get_font_subst(&font_subst_list, value, -1);
2203 if(psub)
2204 value = psub->to.name;
2205 family = find_family_from_name(value);
2206 if (!family)
2207 continue;
2208 file = NULL;
2209 /* Use first extant filename for this Family */
2210 face_list = get_face_list_from_family(family);
2211 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2213 if (!face->file)
2214 continue;
2215 file = strrchrW(face->file, '/');
2216 if (!file)
2217 file = face->file;
2218 else
2219 file++;
2220 break;
2222 if (!file)
2223 continue;
2224 face = find_face_from_filename(file, value);
2225 if(!face)
2227 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2228 continue;
2231 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2232 child_font->face = face;
2233 child_font->font = NULL;
2234 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2235 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2236 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2237 child_font->face->face_index);
2238 list_add_tail(&font_link->links, &child_font->entry);
2240 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2246 /*************************************************************
2247 * init_system_links
2249 static BOOL init_system_links(void)
2251 HKEY hkey;
2252 BOOL ret = FALSE;
2253 DWORD type, max_val, max_data, val_len, data_len, index;
2254 WCHAR *value, *data;
2255 WCHAR *entry, *next;
2256 SYSTEM_LINKS *font_link, *system_font_link;
2257 CHILD_FONT *child_font;
2258 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2259 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2260 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2261 Face *face;
2262 FontSubst *psub;
2263 UINT i, j;
2265 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2267 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2268 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2269 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2270 val_len = max_val + 1;
2271 data_len = max_data;
2272 index = 0;
2273 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2275 psub = get_font_subst(&font_subst_list, value, -1);
2276 /* Don't store fonts that are only substitutes for other fonts */
2277 if(psub)
2279 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2280 goto next;
2282 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2283 font_link->font_name = strdupW(value);
2284 memset(&font_link->fs, 0, sizeof font_link->fs);
2285 list_init(&font_link->links);
2286 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2288 WCHAR *face_name;
2289 CHILD_FONT *child_font;
2291 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2293 next = entry + strlenW(entry) + 1;
2295 face_name = strchrW(entry, ',');
2296 if(face_name)
2298 *face_name++ = 0;
2299 while(isspaceW(*face_name))
2300 face_name++;
2302 psub = get_font_subst(&font_subst_list, face_name, -1);
2303 if(psub)
2304 face_name = psub->to.name;
2306 face = find_face_from_filename(entry, face_name);
2307 if(!face)
2309 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2310 continue;
2313 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2314 child_font->face = face;
2315 child_font->font = NULL;
2316 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2317 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2318 TRACE("Adding file %s index %ld\n",
2319 debugstr_w(child_font->face->file), child_font->face->face_index);
2320 list_add_tail(&font_link->links, &child_font->entry);
2322 list_add_tail(&system_links, &font_link->entry);
2323 next:
2324 val_len = max_val + 1;
2325 data_len = max_data;
2328 HeapFree(GetProcessHeap(), 0, value);
2329 HeapFree(GetProcessHeap(), 0, data);
2330 RegCloseKey(hkey);
2334 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2335 if (!psub) {
2336 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2337 goto skip_internal;
2340 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2342 const FontSubst *psub2;
2343 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2345 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2347 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2348 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2350 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2351 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2353 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2355 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2359 skip_internal:
2361 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2362 that Tahoma has */
2364 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2365 system_font_link->font_name = strdupW(System);
2366 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2367 list_init(&system_font_link->links);
2369 face = find_face_from_filename(tahoma_ttf, Tahoma);
2370 if(face)
2372 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2373 child_font->face = face;
2374 child_font->font = NULL;
2375 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2376 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2377 TRACE("Found Tahoma in %s index %ld\n",
2378 debugstr_w(child_font->face->file), child_font->face->face_index);
2379 list_add_tail(&system_font_link->links, &child_font->entry);
2381 font_link = find_font_link(Tahoma);
2382 if (font_link != NULL)
2384 CHILD_FONT *font_link_entry;
2385 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2387 CHILD_FONT *new_child;
2388 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2389 new_child->face = font_link_entry->face;
2390 new_child->font = NULL;
2391 new_child->face->refcount++;
2392 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2393 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2394 list_add_tail(&system_font_link->links, &new_child->entry);
2397 list_add_tail(&system_links, &system_font_link->entry);
2398 return ret;
2401 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2403 DIR *dir;
2404 struct dirent *dent;
2405 char path[MAX_PATH];
2407 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2409 dir = opendir(dirname);
2410 if(!dir) {
2411 WARN("Can't open directory %s\n", debugstr_a(dirname));
2412 return FALSE;
2414 while((dent = readdir(dir)) != NULL) {
2415 struct stat statbuf;
2417 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2418 continue;
2420 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2422 sprintf(path, "%s/%s", dirname, dent->d_name);
2424 if(stat(path, &statbuf) == -1)
2426 WARN("Can't stat %s\n", debugstr_a(path));
2427 continue;
2429 if(S_ISDIR(statbuf.st_mode))
2430 ReadFontDir(path, external_fonts);
2431 else
2433 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2434 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2435 AddFontToList(path, NULL, 0, addfont_flags);
2438 closedir(dir);
2439 return TRUE;
2442 #ifdef SONAME_LIBFONTCONFIG
2444 static BOOL fontconfig_enabled;
2446 static UINT parse_aa_pattern( FcPattern *pattern )
2448 FcBool antialias;
2449 int rgba;
2450 UINT aa_flags = 0;
2452 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2453 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2455 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2457 switch (rgba)
2459 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2460 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2461 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2462 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2463 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2466 return aa_flags;
2469 static void init_fontconfig(void)
2471 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2473 if (!fc_handle)
2475 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2476 return;
2479 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2480 LOAD_FUNCPTR(FcConfigSubstitute);
2481 LOAD_FUNCPTR(FcFontList);
2482 LOAD_FUNCPTR(FcFontSetDestroy);
2483 LOAD_FUNCPTR(FcInit);
2484 LOAD_FUNCPTR(FcObjectSetAdd);
2485 LOAD_FUNCPTR(FcObjectSetCreate);
2486 LOAD_FUNCPTR(FcObjectSetDestroy);
2487 LOAD_FUNCPTR(FcPatternCreate);
2488 LOAD_FUNCPTR(FcPatternDestroy);
2489 LOAD_FUNCPTR(FcPatternGetBool);
2490 LOAD_FUNCPTR(FcPatternGetInteger);
2491 LOAD_FUNCPTR(FcPatternGetString);
2492 #undef LOAD_FUNCPTR
2494 if (pFcInit())
2496 FcPattern *pattern = pFcPatternCreate();
2497 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2498 default_aa_flags = parse_aa_pattern( pattern );
2499 pFcPatternDestroy( pattern );
2500 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2501 fontconfig_enabled = TRUE;
2505 static void load_fontconfig_fonts(void)
2507 FcPattern *pat;
2508 FcObjectSet *os;
2509 FcFontSet *fontset;
2510 int i, len;
2511 char *file;
2512 const char *ext;
2514 if (!fontconfig_enabled) return;
2516 pat = pFcPatternCreate();
2517 os = pFcObjectSetCreate();
2518 pFcObjectSetAdd(os, FC_FILE);
2519 pFcObjectSetAdd(os, FC_SCALABLE);
2520 pFcObjectSetAdd(os, FC_ANTIALIAS);
2521 pFcObjectSetAdd(os, FC_RGBA);
2522 fontset = pFcFontList(NULL, pat, os);
2523 if(!fontset) return;
2524 for(i = 0; i < fontset->nfont; i++) {
2525 FcBool scalable;
2526 DWORD aa_flags;
2528 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2529 continue;
2531 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2533 /* We're just interested in OT/TT fonts for now, so this hack just
2534 picks up the scalable fonts without extensions .pf[ab] to save time
2535 loading every other font */
2537 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2539 TRACE("not scalable\n");
2540 continue;
2543 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2544 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2546 len = strlen( file );
2547 if(len < 4) continue;
2548 ext = &file[ len - 3 ];
2549 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2550 AddFontToList(file, NULL, 0,
2551 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2553 pFcFontSetDestroy(fontset);
2554 pFcObjectSetDestroy(os);
2555 pFcPatternDestroy(pat);
2558 #elif defined(HAVE_CARBON_CARBON_H)
2560 static void load_mac_font_callback(const void *value, void *context)
2562 CFStringRef pathStr = value;
2563 CFIndex len;
2564 char* path;
2566 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2567 path = HeapAlloc(GetProcessHeap(), 0, len);
2568 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2570 TRACE("font file %s\n", path);
2571 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2573 HeapFree(GetProcessHeap(), 0, path);
2576 static void load_mac_fonts(void)
2578 CFStringRef removeDupesKey;
2579 CFBooleanRef removeDupesValue;
2580 CFDictionaryRef options;
2581 CTFontCollectionRef col;
2582 CFArrayRef descs;
2583 CFMutableSetRef paths;
2584 CFIndex i;
2586 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2587 removeDupesValue = kCFBooleanTrue;
2588 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2589 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2590 col = CTFontCollectionCreateFromAvailableFonts(options);
2591 if (options) CFRelease(options);
2592 if (!col)
2594 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2595 return;
2598 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2599 CFRelease(col);
2600 if (!descs)
2602 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2603 return;
2606 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2607 if (!paths)
2609 WARN("CFSetCreateMutable failed\n");
2610 CFRelease(descs);
2611 return;
2614 for (i = 0; i < CFArrayGetCount(descs); i++)
2616 CTFontDescriptorRef desc;
2617 CTFontRef font;
2618 ATSFontRef atsFont;
2619 OSStatus status;
2620 FSRef fsref;
2621 CFURLRef url;
2622 CFStringRef ext;
2623 CFStringRef path;
2625 desc = CFArrayGetValueAtIndex(descs, i);
2627 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2628 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2629 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2630 if (!font) continue;
2632 atsFont = CTFontGetPlatformFont(font, NULL);
2633 if (!atsFont)
2635 CFRelease(font);
2636 continue;
2639 status = ATSFontGetFileReference(atsFont, &fsref);
2640 CFRelease(font);
2641 if (status != noErr) continue;
2643 url = CFURLCreateFromFSRef(NULL, &fsref);
2644 if (!url) continue;
2646 ext = CFURLCopyPathExtension(url);
2647 if (ext)
2649 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2650 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2651 CFRelease(ext);
2652 if (skip)
2654 CFRelease(url);
2655 continue;
2659 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2660 CFRelease(url);
2661 if (!path) continue;
2663 CFSetAddValue(paths, path);
2664 CFRelease(path);
2667 CFRelease(descs);
2669 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2670 CFRelease(paths);
2673 #endif
2675 static char *get_data_dir_path( LPCWSTR file )
2677 char *unix_name = NULL;
2678 const char *data_dir = wine_get_data_dir();
2680 if (!data_dir) data_dir = wine_get_build_dir();
2682 if (data_dir)
2684 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2686 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2687 strcpy(unix_name, data_dir);
2688 strcat(unix_name, "/fonts/");
2690 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2692 return unix_name;
2695 static BOOL load_font_from_data_dir(LPCWSTR file)
2697 BOOL ret = FALSE;
2698 char *unix_name = get_data_dir_path( file );
2700 if (unix_name)
2702 EnterCriticalSection( &freetype_cs );
2703 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2704 LeaveCriticalSection( &freetype_cs );
2705 HeapFree(GetProcessHeap(), 0, unix_name);
2707 return ret;
2710 static char *get_winfonts_dir_path(LPCWSTR file)
2712 static const WCHAR slashW[] = {'\\','\0'};
2713 WCHAR windowsdir[MAX_PATH];
2715 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2716 strcatW(windowsdir, fontsW);
2717 strcatW(windowsdir, slashW);
2718 strcatW(windowsdir, file);
2719 return wine_get_unix_file_name( windowsdir );
2722 static void load_system_fonts(void)
2724 HKEY hkey;
2725 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2726 const WCHAR * const *value;
2727 DWORD dlen, type;
2728 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2729 char *unixname;
2731 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2732 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2733 strcatW(windowsdir, fontsW);
2734 for(value = SystemFontValues; *value; value++) {
2735 dlen = sizeof(data);
2736 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2737 type == REG_SZ) {
2738 BOOL added = FALSE;
2740 sprintfW(pathW, fmtW, windowsdir, data);
2741 if((unixname = wine_get_unix_file_name(pathW))) {
2742 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2743 HeapFree(GetProcessHeap(), 0, unixname);
2745 if (!added)
2746 load_font_from_data_dir(data);
2749 RegCloseKey(hkey);
2753 /*************************************************************
2755 * This adds registry entries for any externally loaded fonts
2756 * (fonts from fontconfig or FontDirs). It also deletes entries
2757 * of no longer existing fonts.
2760 static void update_reg_entries(void)
2762 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2763 LPWSTR valueW;
2764 DWORD len;
2765 Family *family;
2766 Face *face;
2767 WCHAR *file, *path;
2768 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2770 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2771 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2772 ERR("Can't create Windows font reg key\n");
2773 goto end;
2776 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2777 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2778 ERR("Can't create Windows font reg key\n");
2779 goto end;
2782 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2783 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2784 ERR("Can't create external font reg key\n");
2785 goto end;
2788 /* enumerate the fonts and add external ones to the two keys */
2790 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2791 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2792 char *buffer;
2793 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
2795 if(face->FullName)
2797 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2798 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2799 strcpyW(valueW, face->FullName);
2801 else
2803 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2804 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2805 strcpyW(valueW, family->FamilyName);
2808 buffer = strWtoA( CP_UNIXCP, face->file );
2809 path = wine_get_dos_file_name( buffer );
2810 HeapFree( GetProcessHeap(), 0, buffer );
2812 if (path)
2813 file = path;
2814 else if ((file = strrchrW(face->file, '/')))
2815 file++;
2816 else
2817 file = face->file;
2819 len = strlenW(file) + 1;
2820 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2821 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2822 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2824 HeapFree(GetProcessHeap(), 0, path);
2825 HeapFree(GetProcessHeap(), 0, valueW);
2828 end:
2829 if(external_key) RegCloseKey(external_key);
2830 if(win9x_key) RegCloseKey(win9x_key);
2831 if(winnt_key) RegCloseKey(winnt_key);
2832 return;
2835 static void delete_external_font_keys(void)
2837 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2838 DWORD dlen, vlen, datalen, valuelen, i, type;
2839 LPWSTR valueW;
2840 LPVOID data;
2842 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2843 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2844 ERR("Can't create Windows font reg key\n");
2845 goto end;
2848 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2849 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2850 ERR("Can't create Windows font reg key\n");
2851 goto end;
2854 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2855 ERR("Can't create external font reg key\n");
2856 goto end;
2859 /* Delete all external fonts added last time */
2861 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2862 &valuelen, &datalen, NULL, NULL);
2863 valuelen++; /* returned value doesn't include room for '\0' */
2864 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2865 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2867 dlen = datalen * sizeof(WCHAR);
2868 vlen = valuelen;
2869 i = 0;
2870 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2871 &dlen) == ERROR_SUCCESS) {
2873 RegDeleteValueW(winnt_key, valueW);
2874 RegDeleteValueW(win9x_key, valueW);
2875 /* reset dlen and vlen */
2876 dlen = datalen;
2877 vlen = valuelen;
2879 HeapFree(GetProcessHeap(), 0, data);
2880 HeapFree(GetProcessHeap(), 0, valueW);
2882 /* Delete the old external fonts key */
2883 RegCloseKey(external_key);
2884 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2886 end:
2887 if(win9x_key) RegCloseKey(win9x_key);
2888 if(winnt_key) RegCloseKey(winnt_key);
2891 /*************************************************************
2892 * WineEngAddFontResourceEx
2895 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2897 INT ret = 0;
2899 GDI_CheckNotLock();
2901 if (ft_handle) /* do it only if we have freetype up and running */
2903 char *unixname;
2905 EnterCriticalSection( &freetype_cs );
2907 if((unixname = wine_get_unix_file_name(file)))
2909 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
2911 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2912 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2913 HeapFree(GetProcessHeap(), 0, unixname);
2915 if (!ret && !strchrW(file, '\\')) {
2916 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2917 if ((unixname = get_winfonts_dir_path( file )))
2919 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2920 HeapFree(GetProcessHeap(), 0, unixname);
2922 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
2923 if (!ret && (unixname = get_data_dir_path( file )))
2925 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2926 HeapFree(GetProcessHeap(), 0, unixname);
2930 LeaveCriticalSection( &freetype_cs );
2932 return ret;
2935 /*************************************************************
2936 * WineEngAddFontMemResourceEx
2939 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2941 GDI_CheckNotLock();
2943 if (ft_handle) /* do it only if we have freetype up and running */
2945 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2947 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2948 memcpy(pFontCopy, pbFont, cbFont);
2950 EnterCriticalSection( &freetype_cs );
2951 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2952 LeaveCriticalSection( &freetype_cs );
2954 if (*pcFonts == 0)
2956 TRACE("AddFontToList failed\n");
2957 HeapFree(GetProcessHeap(), 0, pFontCopy);
2958 return 0;
2960 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2961 * For now return something unique but quite random
2963 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2964 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2967 *pcFonts = 0;
2968 return 0;
2971 /*************************************************************
2972 * WineEngRemoveFontResourceEx
2975 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2977 INT ret = 0;
2979 GDI_CheckNotLock();
2981 if (ft_handle) /* do it only if we have freetype up and running */
2983 char *unixname;
2985 EnterCriticalSection( &freetype_cs );
2987 if ((unixname = wine_get_unix_file_name(file)))
2989 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
2991 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2992 ret = remove_font_resource( unixname, addfont_flags );
2993 HeapFree(GetProcessHeap(), 0, unixname);
2995 if (!ret && !strchrW(file, '\\'))
2997 if ((unixname = get_winfonts_dir_path( file )))
2999 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3000 HeapFree(GetProcessHeap(), 0, unixname);
3002 if (!ret && (unixname = get_data_dir_path( file )))
3004 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3005 HeapFree(GetProcessHeap(), 0, unixname);
3009 LeaveCriticalSection( &freetype_cs );
3011 return ret;
3014 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3016 WCHAR *fullname;
3017 char *unix_name;
3018 int file_len;
3020 if (!font_file) return NULL;
3022 file_len = strlenW( font_file );
3024 if (font_path && font_path[0])
3026 int path_len = strlenW( font_path );
3027 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3028 if (!fullname) return NULL;
3029 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3030 fullname[path_len] = '\\';
3031 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3033 else
3035 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3036 if (!len) return NULL;
3037 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3038 if (!fullname) return NULL;
3039 GetFullPathNameW( font_file, len, fullname, NULL );
3042 unix_name = wine_get_unix_file_name( fullname );
3043 HeapFree( GetProcessHeap(), 0, fullname );
3044 return unix_name;
3047 #include <pshpack1.h>
3048 struct fontdir
3050 WORD num_of_resources;
3051 WORD res_id;
3052 WORD dfVersion;
3053 DWORD dfSize;
3054 CHAR dfCopyright[60];
3055 WORD dfType;
3056 WORD dfPoints;
3057 WORD dfVertRes;
3058 WORD dfHorizRes;
3059 WORD dfAscent;
3060 WORD dfInternalLeading;
3061 WORD dfExternalLeading;
3062 BYTE dfItalic;
3063 BYTE dfUnderline;
3064 BYTE dfStrikeOut;
3065 WORD dfWeight;
3066 BYTE dfCharSet;
3067 WORD dfPixWidth;
3068 WORD dfPixHeight;
3069 BYTE dfPitchAndFamily;
3070 WORD dfAvgWidth;
3071 WORD dfMaxWidth;
3072 BYTE dfFirstChar;
3073 BYTE dfLastChar;
3074 BYTE dfDefaultChar;
3075 BYTE dfBreakChar;
3076 WORD dfWidthBytes;
3077 DWORD dfDevice;
3078 DWORD dfFace;
3079 DWORD dfReserved;
3080 CHAR szFaceName[LF_FACESIZE];
3083 #include <poppack.h>
3085 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3086 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3088 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3090 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3091 Face *face;
3092 WCHAR *name, *english_name;
3093 ENUMLOGFONTEXW elf;
3094 NEWTEXTMETRICEXW ntm;
3095 DWORD type;
3097 if (!ft_face) return FALSE;
3098 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3099 get_family_names( ft_face, &name, &english_name, FALSE );
3100 pFT_Done_Face( ft_face );
3102 GetEnumStructs( face, name, &elf, &ntm, &type );
3103 release_face( face );
3104 HeapFree( GetProcessHeap(), 0, name );
3105 HeapFree( GetProcessHeap(), 0, english_name );
3107 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3109 memset( fd, 0, sizeof(*fd) );
3111 fd->num_of_resources = 1;
3112 fd->res_id = 0;
3113 fd->dfVersion = 0x200;
3114 fd->dfSize = sizeof(*fd);
3115 strcpy( fd->dfCopyright, "Wine fontdir" );
3116 fd->dfType = 0x4003; /* 0x0080 set if private */
3117 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3118 fd->dfVertRes = 72;
3119 fd->dfHorizRes = 72;
3120 fd->dfAscent = ntm.ntmTm.tmAscent;
3121 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3122 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3123 fd->dfItalic = ntm.ntmTm.tmItalic;
3124 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3125 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3126 fd->dfWeight = ntm.ntmTm.tmWeight;
3127 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3128 fd->dfPixWidth = 0;
3129 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3130 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3131 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3132 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3133 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3134 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3135 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3136 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3137 fd->dfWidthBytes = 0;
3138 fd->dfDevice = 0;
3139 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3140 fd->dfReserved = 0;
3141 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3143 return TRUE;
3146 #define NE_FFLAGS_LIBMODULE 0x8000
3147 #define NE_OSFLAGS_WINDOWS 0x02
3149 static const char dos_string[0x40] = "This is a TrueType resource file";
3150 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3152 #include <pshpack2.h>
3154 struct ne_typeinfo
3156 WORD type_id;
3157 WORD count;
3158 DWORD res;
3161 struct ne_nameinfo
3163 WORD off;
3164 WORD len;
3165 WORD flags;
3166 WORD id;
3167 DWORD res;
3170 struct rsrc_tab
3172 WORD align;
3173 struct ne_typeinfo fontdir_type;
3174 struct ne_nameinfo fontdir_name;
3175 struct ne_typeinfo scalable_type;
3176 struct ne_nameinfo scalable_name;
3177 WORD end_of_rsrc;
3178 BYTE fontdir_res_name[8];
3181 #include <poppack.h>
3183 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3185 BOOL ret = FALSE;
3186 HANDLE file;
3187 DWORD size, written;
3188 BYTE *ptr, *start;
3189 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3190 char *font_fileA, *last_part, *ext;
3191 IMAGE_DOS_HEADER dos;
3192 IMAGE_OS2_HEADER ne =
3194 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3195 0, 0, 0, 0, 0, 0,
3196 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3197 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3199 struct rsrc_tab rsrc_tab =
3202 { 0x8007, 1, 0 },
3203 { 0, 0, 0x0c50, 0x2c, 0 },
3204 { 0x80cc, 1, 0 },
3205 { 0, 0, 0x0c50, 0x8001, 0 },
3207 { 7,'F','O','N','T','D','I','R'}
3210 memset( &dos, 0, sizeof(dos) );
3211 dos.e_magic = IMAGE_DOS_SIGNATURE;
3212 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3214 /* import name is last part\0, resident name is last part without extension
3215 non-resident name is "FONTRES:" + lfFaceName */
3217 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3218 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3219 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3221 last_part = strrchr( font_fileA, '\\' );
3222 if (last_part) last_part++;
3223 else last_part = font_fileA;
3224 import_name_len = strlen( last_part ) + 1;
3226 ext = strchr( last_part, '.' );
3227 if (ext) res_name_len = ext - last_part;
3228 else res_name_len = import_name_len - 1;
3230 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3232 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3233 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3234 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3235 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3236 ne.ne_cbenttab = 2;
3237 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3239 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3240 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3241 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3242 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3244 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3245 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3247 if (!ptr)
3249 HeapFree( GetProcessHeap(), 0, font_fileA );
3250 return FALSE;
3253 memcpy( ptr, &dos, sizeof(dos) );
3254 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3255 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3257 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3258 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3260 ptr = start + dos.e_lfanew + ne.ne_restab;
3261 *ptr++ = res_name_len;
3262 memcpy( ptr, last_part, res_name_len );
3264 ptr = start + dos.e_lfanew + ne.ne_imptab;
3265 *ptr++ = import_name_len;
3266 memcpy( ptr, last_part, import_name_len );
3268 ptr = start + ne.ne_nrestab;
3269 *ptr++ = non_res_name_len;
3270 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3271 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3273 ptr = start + (rsrc_tab.scalable_name.off << 4);
3274 memcpy( ptr, font_fileA, font_file_len );
3276 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3277 memcpy( ptr, fontdir, fontdir->dfSize );
3279 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3280 if (file != INVALID_HANDLE_VALUE)
3282 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3283 ret = TRUE;
3284 CloseHandle( file );
3287 HeapFree( GetProcessHeap(), 0, start );
3288 HeapFree( GetProcessHeap(), 0, font_fileA );
3290 return ret;
3293 /*************************************************************
3294 * WineEngCreateScalableFontResource
3297 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3298 LPCWSTR font_file, LPCWSTR font_path )
3300 char *unix_name = get_ttf_file_name( font_file, font_path );
3301 struct fontdir fontdir;
3302 BOOL ret = FALSE;
3304 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3305 SetLastError( ERROR_INVALID_PARAMETER );
3306 else
3308 if (hidden) fontdir.dfType |= 0x80;
3309 ret = create_fot( resource, font_file, &fontdir );
3312 HeapFree( GetProcessHeap(), 0, unix_name );
3313 return ret;
3316 static const struct nls_update_font_list
3318 UINT ansi_cp, oem_cp;
3319 const char *oem, *fixed, *system;
3320 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3321 /* these are for font substitutes */
3322 const char *shelldlg, *tmsrmn;
3323 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3324 *helv_0, *tmsrmn_0;
3325 const struct subst
3327 const char *from, *to;
3328 } arial_0, courier_new_0, times_new_roman_0;
3329 } nls_update_font_list[] =
3331 /* Latin 1 (United States) */
3332 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3333 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3334 "Tahoma","Times New Roman",
3335 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3336 { 0 }, { 0 }, { 0 }
3338 /* Latin 1 (Multilingual) */
3339 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3340 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3341 "Tahoma","Times New Roman", /* FIXME unverified */
3342 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3343 { 0 }, { 0 }, { 0 }
3345 /* Eastern Europe */
3346 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3347 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3348 "Tahoma","Times New Roman", /* FIXME unverified */
3349 "Fixedsys,238", "System,238",
3350 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3351 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3352 { "Arial CE,0", "Arial,238" },
3353 { "Courier New CE,0", "Courier New,238" },
3354 { "Times New Roman CE,0", "Times New Roman,238" }
3356 /* Cyrillic */
3357 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3358 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3359 "Tahoma","Times New Roman", /* FIXME unverified */
3360 "Fixedsys,204", "System,204",
3361 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3362 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3363 { "Arial Cyr,0", "Arial,204" },
3364 { "Courier New Cyr,0", "Courier New,204" },
3365 { "Times New Roman Cyr,0", "Times New Roman,204" }
3367 /* Greek */
3368 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3369 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3370 "Tahoma","Times New Roman", /* FIXME unverified */
3371 "Fixedsys,161", "System,161",
3372 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3373 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3374 { "Arial Greek,0", "Arial,161" },
3375 { "Courier New Greek,0", "Courier New,161" },
3376 { "Times New Roman Greek,0", "Times New Roman,161" }
3378 /* Turkish */
3379 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3380 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3381 "Tahoma","Times New Roman", /* FIXME unverified */
3382 "Fixedsys,162", "System,162",
3383 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3384 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3385 { "Arial Tur,0", "Arial,162" },
3386 { "Courier New Tur,0", "Courier New,162" },
3387 { "Times New Roman Tur,0", "Times New Roman,162" }
3389 /* Hebrew */
3390 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3391 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3392 "Tahoma","Times New Roman", /* FIXME unverified */
3393 "Fixedsys,177", "System,177",
3394 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3395 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3396 { 0 }, { 0 }, { 0 }
3398 /* Arabic */
3399 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3400 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3401 "Tahoma","Times New Roman", /* FIXME unverified */
3402 "Fixedsys,178", "System,178",
3403 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3404 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3405 { 0 }, { 0 }, { 0 }
3407 /* Baltic */
3408 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3409 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3410 "Tahoma","Times New Roman", /* FIXME unverified */
3411 "Fixedsys,186", "System,186",
3412 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3413 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3414 { "Arial Baltic,0", "Arial,186" },
3415 { "Courier New Baltic,0", "Courier New,186" },
3416 { "Times New Roman Baltic,0", "Times New Roman,186" }
3418 /* Vietnamese */
3419 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3420 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3421 "Tahoma","Times New Roman", /* FIXME unverified */
3422 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3423 { 0 }, { 0 }, { 0 }
3425 /* Thai */
3426 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3427 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3428 "Tahoma","Times New Roman", /* FIXME unverified */
3429 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3430 { 0 }, { 0 }, { 0 }
3432 /* Japanese */
3433 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3434 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3435 "MS UI Gothic","MS Serif",
3436 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3437 { 0 }, { 0 }, { 0 }
3439 /* Chinese Simplified */
3440 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3441 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3442 "SimSun", "NSimSun",
3443 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3444 { 0 }, { 0 }, { 0 }
3446 /* Korean */
3447 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3448 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3449 "Gulim", "Batang",
3450 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3451 { 0 }, { 0 }, { 0 }
3453 /* Chinese Traditional */
3454 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3455 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3456 "PMingLiU", "MingLiU",
3457 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3458 { 0 }, { 0 }, { 0 }
3462 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3464 return ( ansi_cp == 932 /* CP932 for Japanese */
3465 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3466 || ansi_cp == 949 /* CP949 for Korean */
3467 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3470 static inline HKEY create_fonts_NT_registry_key(void)
3472 HKEY hkey = 0;
3474 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3475 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3476 return hkey;
3479 static inline HKEY create_fonts_9x_registry_key(void)
3481 HKEY hkey = 0;
3483 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3484 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3485 return hkey;
3488 static inline HKEY create_config_fonts_registry_key(void)
3490 HKEY hkey = 0;
3492 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3493 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3494 return hkey;
3497 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3499 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3501 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3502 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3503 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3504 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3507 static void set_value_key(HKEY hkey, const char *name, const char *value)
3509 if (value)
3510 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3511 else if (name)
3512 RegDeleteValueA(hkey, name);
3515 static void update_font_association_info(UINT current_ansi_codepage)
3517 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3518 static const char *assoc_charset_subkey = "Associated Charset";
3520 if (is_dbcs_ansi_cp(current_ansi_codepage))
3522 HKEY hkey;
3523 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3525 HKEY hsubkey;
3526 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3528 switch (current_ansi_codepage)
3530 case 932:
3531 set_value_key(hsubkey, "ANSI(00)", "NO");
3532 set_value_key(hsubkey, "OEM(FF)", "NO");
3533 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3534 break;
3535 case 936:
3536 case 949:
3537 case 950:
3538 set_value_key(hsubkey, "ANSI(00)", "YES");
3539 set_value_key(hsubkey, "OEM(FF)", "YES");
3540 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3541 break;
3543 RegCloseKey(hsubkey);
3546 /* TODO: Associated DefaultFonts */
3548 RegCloseKey(hkey);
3551 else
3552 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3555 static void update_font_info(void)
3557 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3558 char buf[40], cpbuf[40];
3559 DWORD len, type;
3560 HKEY hkey = 0;
3561 UINT i, ansi_cp = 0, oem_cp = 0;
3562 DWORD screen_dpi = 96, font_dpi = 0;
3563 BOOL done = FALSE;
3565 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3566 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3567 &hkey) == ERROR_SUCCESS)
3569 reg_load_dword(hkey, logpixels, &screen_dpi);
3570 RegCloseKey(hkey);
3573 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3574 return;
3576 reg_load_dword(hkey, logpixels, &font_dpi);
3578 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3579 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3580 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3581 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3582 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3584 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3585 if (is_dbcs_ansi_cp(ansi_cp))
3586 use_default_fallback = TRUE;
3588 buf[0] = 0;
3589 len = sizeof(buf);
3590 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3592 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3594 RegCloseKey(hkey);
3595 return;
3597 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3598 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3600 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3601 ansi_cp, oem_cp, screen_dpi);
3603 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3604 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3605 RegCloseKey(hkey);
3607 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3609 HKEY hkey;
3611 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3612 nls_update_font_list[i].oem_cp == oem_cp)
3614 hkey = create_config_fonts_registry_key();
3615 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3616 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3617 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3618 RegCloseKey(hkey);
3620 hkey = create_fonts_NT_registry_key();
3621 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3622 RegCloseKey(hkey);
3624 hkey = create_fonts_9x_registry_key();
3625 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3626 RegCloseKey(hkey);
3628 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3630 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3631 strlen(nls_update_font_list[i].shelldlg)+1);
3632 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3633 strlen(nls_update_font_list[i].tmsrmn)+1);
3635 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3636 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3637 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3638 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3639 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3640 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3641 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3642 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3644 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3645 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3646 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3648 RegCloseKey(hkey);
3650 done = TRUE;
3652 else
3654 /* Delete the FontSubstitutes from other locales */
3655 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3657 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3658 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3659 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3660 RegCloseKey(hkey);
3664 if (!done)
3665 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3667 /* update locale dependent font association info in registry.
3668 update only when codepages changed, not logpixels. */
3669 if (strcmp(buf, cpbuf) != 0)
3670 update_font_association_info(ansi_cp);
3673 static BOOL init_freetype(void)
3675 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3676 if(!ft_handle) {
3677 WINE_MESSAGE(
3678 "Wine cannot find the FreeType font library. To enable Wine to\n"
3679 "use TrueType fonts please install a version of FreeType greater than\n"
3680 "or equal to 2.0.5.\n"
3681 "http://www.freetype.org\n");
3682 return FALSE;
3685 #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;}
3687 LOAD_FUNCPTR(FT_Done_Face)
3688 LOAD_FUNCPTR(FT_Get_Char_Index)
3689 LOAD_FUNCPTR(FT_Get_First_Char)
3690 LOAD_FUNCPTR(FT_Get_Module)
3691 LOAD_FUNCPTR(FT_Get_Next_Char)
3692 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3693 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3694 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3695 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3696 LOAD_FUNCPTR(FT_Init_FreeType)
3697 LOAD_FUNCPTR(FT_Library_Version)
3698 LOAD_FUNCPTR(FT_Load_Glyph)
3699 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3700 LOAD_FUNCPTR(FT_Matrix_Multiply)
3701 #ifndef FT_MULFIX_INLINED
3702 LOAD_FUNCPTR(FT_MulFix)
3703 #endif
3704 LOAD_FUNCPTR(FT_New_Face)
3705 LOAD_FUNCPTR(FT_New_Memory_Face)
3706 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3707 LOAD_FUNCPTR(FT_Outline_Transform)
3708 LOAD_FUNCPTR(FT_Outline_Translate)
3709 LOAD_FUNCPTR(FT_Render_Glyph)
3710 LOAD_FUNCPTR(FT_Select_Charmap)
3711 LOAD_FUNCPTR(FT_Set_Charmap)
3712 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3713 LOAD_FUNCPTR(FT_Vector_Transform)
3714 LOAD_FUNCPTR(FT_Vector_Unit)
3715 #undef LOAD_FUNCPTR
3716 /* Don't warn if these ones are missing */
3717 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3718 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3719 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3720 #endif
3722 if(pFT_Init_FreeType(&library) != 0) {
3723 ERR("Can't init FreeType library\n");
3724 wine_dlclose(ft_handle, NULL, 0);
3725 ft_handle = NULL;
3726 return FALSE;
3728 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3730 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3731 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3732 ((FT_Version.minor << 8) & 0x00ff00) |
3733 ((FT_Version.patch ) & 0x0000ff);
3735 font_driver = &freetype_funcs;
3736 return TRUE;
3738 sym_not_found:
3739 WINE_MESSAGE(
3740 "Wine cannot find certain functions that it needs inside the FreeType\n"
3741 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3742 "FreeType to at least version 2.1.4.\n"
3743 "http://www.freetype.org\n");
3744 wine_dlclose(ft_handle, NULL, 0);
3745 ft_handle = NULL;
3746 return FALSE;
3749 static void init_font_list(void)
3751 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3752 static const WCHAR pathW[] = {'P','a','t','h',0};
3753 HKEY hkey;
3754 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3755 WCHAR windowsdir[MAX_PATH];
3756 char *unixname;
3757 const char *data_dir;
3759 delete_external_font_keys();
3761 /* load the system bitmap fonts */
3762 load_system_fonts();
3764 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3765 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3766 strcatW(windowsdir, fontsW);
3767 if((unixname = wine_get_unix_file_name(windowsdir)))
3769 ReadFontDir(unixname, FALSE);
3770 HeapFree(GetProcessHeap(), 0, unixname);
3773 /* load the system truetype fonts */
3774 data_dir = wine_get_data_dir();
3775 if (!data_dir) data_dir = wine_get_build_dir();
3776 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3778 strcpy(unixname, data_dir);
3779 strcat(unixname, "/fonts/");
3780 ReadFontDir(unixname, TRUE);
3781 HeapFree(GetProcessHeap(), 0, unixname);
3784 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3785 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3786 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3787 will skip these. */
3788 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3789 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3790 &hkey) == ERROR_SUCCESS)
3792 LPWSTR data, valueW;
3793 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3794 &valuelen, &datalen, NULL, NULL);
3796 valuelen++; /* returned value doesn't include room for '\0' */
3797 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3798 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3799 if (valueW && data)
3801 dlen = datalen * sizeof(WCHAR);
3802 vlen = valuelen;
3803 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3804 &dlen) == ERROR_SUCCESS)
3806 if(data[0] && (data[1] == ':'))
3808 if((unixname = wine_get_unix_file_name(data)))
3810 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3811 HeapFree(GetProcessHeap(), 0, unixname);
3814 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3816 WCHAR pathW[MAX_PATH];
3817 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3818 BOOL added = FALSE;
3820 sprintfW(pathW, fmtW, windowsdir, data);
3821 if((unixname = wine_get_unix_file_name(pathW)))
3823 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3824 HeapFree(GetProcessHeap(), 0, unixname);
3826 if (!added)
3827 load_font_from_data_dir(data);
3829 /* reset dlen and vlen */
3830 dlen = datalen;
3831 vlen = valuelen;
3834 HeapFree(GetProcessHeap(), 0, data);
3835 HeapFree(GetProcessHeap(), 0, valueW);
3836 RegCloseKey(hkey);
3839 #ifdef SONAME_LIBFONTCONFIG
3840 load_fontconfig_fonts();
3841 #elif defined(HAVE_CARBON_CARBON_H)
3842 load_mac_fonts();
3843 #endif
3845 /* then look in any directories that we've specified in the config file */
3846 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3847 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3849 DWORD len;
3850 LPWSTR valueW;
3851 LPSTR valueA, ptr;
3853 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3855 len += sizeof(WCHAR);
3856 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3857 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3859 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3860 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3861 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3862 TRACE( "got font path %s\n", debugstr_a(valueA) );
3863 ptr = valueA;
3864 while (ptr)
3866 const char* home;
3867 LPSTR next = strchr( ptr, ':' );
3868 if (next) *next++ = 0;
3869 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3870 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3872 strcpy( unixname, home );
3873 strcat( unixname, ptr + 1 );
3874 ReadFontDir( unixname, TRUE );
3875 HeapFree( GetProcessHeap(), 0, unixname );
3877 else
3878 ReadFontDir( ptr, TRUE );
3879 ptr = next;
3881 HeapFree( GetProcessHeap(), 0, valueA );
3883 HeapFree( GetProcessHeap(), 0, valueW );
3885 RegCloseKey(hkey);
3889 static BOOL move_to_front(const WCHAR *name)
3891 Family *family, *cursor2;
3892 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3894 if(!strcmpiW(family->FamilyName, name))
3896 list_remove(&family->entry);
3897 list_add_head(&font_list, &family->entry);
3898 return TRUE;
3901 return FALSE;
3904 static BOOL set_default(const WCHAR **name_list)
3906 while (*name_list)
3908 if (move_to_front(*name_list)) return TRUE;
3909 name_list++;
3912 return FALSE;
3915 static void reorder_font_list(void)
3917 set_default( default_serif_list );
3918 set_default( default_fixed_list );
3919 set_default( default_sans_list );
3922 /*************************************************************
3923 * WineEngInit
3925 * Initialize FreeType library and create a list of available faces
3927 BOOL WineEngInit(void)
3929 DWORD disposition;
3930 HANDLE font_mutex;
3932 /* update locale dependent font info in registry */
3933 update_font_info();
3935 if(!init_freetype()) return FALSE;
3937 #ifdef SONAME_LIBFONTCONFIG
3938 init_fontconfig();
3939 #endif
3941 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3943 ERR("Failed to create font mutex\n");
3944 return FALSE;
3946 WaitForSingleObject(font_mutex, INFINITE);
3948 create_font_cache_key(&hkey_font_cache, &disposition);
3950 if(disposition == REG_CREATED_NEW_KEY)
3951 init_font_list();
3952 else
3953 load_font_list_from_cache(hkey_font_cache);
3955 reorder_font_list();
3957 DumpFontList();
3958 LoadSubstList();
3959 DumpSubstList();
3960 LoadReplaceList();
3962 if(disposition == REG_CREATED_NEW_KEY)
3963 update_reg_entries();
3965 init_system_links();
3967 ReleaseMutex(font_mutex);
3968 return TRUE;
3972 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3974 TT_OS2 *pOS2;
3975 TT_HoriHeader *pHori;
3977 LONG ppem;
3979 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3980 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3982 if(height == 0) height = 16;
3984 /* Calc. height of EM square:
3986 * For +ve lfHeight we have
3987 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3988 * Re-arranging gives:
3989 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3991 * For -ve lfHeight we have
3992 * |lfHeight| = ppem
3993 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3994 * with il = winAscent + winDescent - units_per_em]
3998 if(height > 0) {
3999 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
4000 ppem = MulDiv(ft_face->units_per_EM, height,
4001 pHori->Ascender - pHori->Descender);
4002 else
4003 ppem = MulDiv(ft_face->units_per_EM, height,
4004 pOS2->usWinAscent + pOS2->usWinDescent);
4006 else
4007 ppem = -height;
4009 return ppem;
4012 static struct font_mapping *map_font_file( const char *name )
4014 struct font_mapping *mapping;
4015 struct stat st;
4016 int fd;
4018 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4019 if (fstat( fd, &st ) == -1) goto error;
4021 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4023 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4025 mapping->refcount++;
4026 close( fd );
4027 return mapping;
4030 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4031 goto error;
4033 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4034 close( fd );
4036 if (mapping->data == MAP_FAILED)
4038 HeapFree( GetProcessHeap(), 0, mapping );
4039 return NULL;
4041 mapping->refcount = 1;
4042 mapping->dev = st.st_dev;
4043 mapping->ino = st.st_ino;
4044 mapping->size = st.st_size;
4045 list_add_tail( &mappings_list, &mapping->entry );
4046 return mapping;
4048 error:
4049 close( fd );
4050 return NULL;
4053 static void unmap_font_file( struct font_mapping *mapping )
4055 if (!--mapping->refcount)
4057 list_remove( &mapping->entry );
4058 munmap( mapping->data, mapping->size );
4059 HeapFree( GetProcessHeap(), 0, mapping );
4063 static LONG load_VDMX(GdiFont*, LONG);
4065 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4067 FT_Error err;
4068 FT_Face ft_face;
4069 void *data_ptr;
4070 DWORD data_size;
4072 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4074 if (face->file)
4076 char *filename = strWtoA( CP_UNIXCP, face->file );
4077 font->mapping = map_font_file( filename );
4078 HeapFree( GetProcessHeap(), 0, filename );
4079 if (!font->mapping)
4081 WARN("failed to map %s\n", debugstr_w(face->file));
4082 return 0;
4084 data_ptr = font->mapping->data;
4085 data_size = font->mapping->size;
4087 else
4089 data_ptr = face->font_data_ptr;
4090 data_size = face->font_data_size;
4093 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4094 if(err) {
4095 ERR("FT_New_Face rets %d\n", err);
4096 return 0;
4099 /* set it here, as load_VDMX needs it */
4100 font->ft_face = ft_face;
4102 if(FT_IS_SCALABLE(ft_face)) {
4103 /* load the VDMX table if we have one */
4104 font->ppem = load_VDMX(font, height);
4105 if(font->ppem == 0)
4106 font->ppem = calc_ppem_for_height(ft_face, height);
4107 TRACE("height %d => ppem %d\n", height, font->ppem);
4109 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4110 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4111 } else {
4112 font->ppem = height;
4113 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4114 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4116 return ft_face;
4120 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4122 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4123 a single face with the requested charset. The idea is to check if
4124 the selected font supports the current ANSI codepage, if it does
4125 return the corresponding charset, else return the first charset */
4127 CHARSETINFO csi;
4128 int acp = GetACP(), i;
4129 DWORD fs0;
4131 *cp = acp;
4132 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4134 const SYSTEM_LINKS *font_link;
4136 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4137 return csi.ciCharset;
4139 font_link = find_font_link(family_name);
4140 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4141 return csi.ciCharset;
4144 for(i = 0; i < 32; i++) {
4145 fs0 = 1L << i;
4146 if(face->fs.fsCsb[0] & fs0) {
4147 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4148 *cp = csi.ciACP;
4149 return csi.ciCharset;
4151 else
4152 FIXME("TCI failing on %x\n", fs0);
4156 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4157 face->fs.fsCsb[0], debugstr_w(face->file));
4158 *cp = acp;
4159 return DEFAULT_CHARSET;
4162 static GdiFont *alloc_font(void)
4164 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4165 ret->refcount = 1;
4166 ret->gmsize = 1;
4167 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4168 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4169 ret->potm = NULL;
4170 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4171 ret->total_kern_pairs = (DWORD)-1;
4172 ret->kern_pairs = NULL;
4173 list_init(&ret->child_fonts);
4174 return ret;
4177 static void free_font(GdiFont *font)
4179 CHILD_FONT *child, *child_next;
4180 DWORD i;
4182 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4184 list_remove(&child->entry);
4185 if(child->font)
4186 free_font(child->font);
4187 release_face( child->face );
4188 HeapFree(GetProcessHeap(), 0, child);
4191 if (font->ft_face) pFT_Done_Face(font->ft_face);
4192 if (font->mapping) unmap_font_file( font->mapping );
4193 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4194 HeapFree(GetProcessHeap(), 0, font->potm);
4195 HeapFree(GetProcessHeap(), 0, font->name);
4196 for (i = 0; i < font->gmsize; i++)
4197 HeapFree(GetProcessHeap(),0,font->gm[i]);
4198 HeapFree(GetProcessHeap(), 0, font->gm);
4199 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4200 HeapFree(GetProcessHeap(), 0, font);
4204 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4206 FT_Face ft_face = font->ft_face;
4207 FT_ULong len;
4208 FT_Error err;
4210 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4212 if(!buf)
4213 len = 0;
4214 else
4215 len = cbData;
4217 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4219 /* make sure value of len is the value freetype says it needs */
4220 if (buf && len)
4222 FT_ULong needed = 0;
4223 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4224 if( !err && needed < len) len = needed;
4226 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4227 if (err)
4229 TRACE("Can't find table %c%c%c%c\n",
4230 /* bytes were reversed */
4231 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4232 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4233 return GDI_ERROR;
4235 return len;
4238 /*************************************************************
4239 * load_VDMX
4241 * load the vdmx entry for the specified height
4244 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4245 ( ( (FT_ULong)_x4 << 24 ) | \
4246 ( (FT_ULong)_x3 << 16 ) | \
4247 ( (FT_ULong)_x2 << 8 ) | \
4248 (FT_ULong)_x1 )
4250 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4252 typedef struct {
4253 BYTE bCharSet;
4254 BYTE xRatio;
4255 BYTE yStartRatio;
4256 BYTE yEndRatio;
4257 } Ratios;
4259 typedef struct {
4260 WORD recs;
4261 BYTE startsz;
4262 BYTE endsz;
4263 } VDMX_group;
4265 static LONG load_VDMX(GdiFont *font, LONG height)
4267 WORD hdr[3], tmp;
4268 VDMX_group group;
4269 BYTE devXRatio, devYRatio;
4270 USHORT numRecs, numRatios;
4271 DWORD result, offset = -1;
4272 LONG ppem = 0;
4273 int i;
4275 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4277 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4278 return ppem;
4280 /* FIXME: need the real device aspect ratio */
4281 devXRatio = 1;
4282 devYRatio = 1;
4284 numRecs = GET_BE_WORD(hdr[1]);
4285 numRatios = GET_BE_WORD(hdr[2]);
4287 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4288 for(i = 0; i < numRatios; i++) {
4289 Ratios ratio;
4291 offset = (3 * 2) + (i * sizeof(Ratios));
4292 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4293 offset = -1;
4295 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4297 if((ratio.xRatio == 0 &&
4298 ratio.yStartRatio == 0 &&
4299 ratio.yEndRatio == 0) ||
4300 (devXRatio == ratio.xRatio &&
4301 devYRatio >= ratio.yStartRatio &&
4302 devYRatio <= ratio.yEndRatio))
4304 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4305 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4306 offset = GET_BE_WORD(tmp);
4307 break;
4311 if(offset == -1) {
4312 FIXME("No suitable ratio found\n");
4313 return ppem;
4316 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4317 USHORT recs;
4318 BYTE startsz, endsz;
4319 WORD *vTable;
4321 recs = GET_BE_WORD(group.recs);
4322 startsz = group.startsz;
4323 endsz = group.endsz;
4325 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4327 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4328 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4329 if(result == GDI_ERROR) {
4330 FIXME("Failed to retrieve vTable\n");
4331 goto end;
4334 if(height > 0) {
4335 for(i = 0; i < recs; i++) {
4336 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4337 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4338 ppem = GET_BE_WORD(vTable[i * 3]);
4340 if(yMax + -yMin == height) {
4341 font->yMax = yMax;
4342 font->yMin = yMin;
4343 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4344 break;
4346 if(yMax + -yMin > height) {
4347 if(--i < 0) {
4348 ppem = 0;
4349 goto end; /* failed */
4351 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4352 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4353 ppem = GET_BE_WORD(vTable[i * 3]);
4354 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4355 break;
4358 if(!font->yMax) {
4359 ppem = 0;
4360 TRACE("ppem not found for height %d\n", height);
4363 end:
4364 HeapFree(GetProcessHeap(), 0, vTable);
4367 return ppem;
4370 static void dump_gdi_font_list(void)
4372 GdiFont *font;
4374 TRACE("---------- Font Cache ----------\n");
4375 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4376 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4377 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4380 static void grab_font( GdiFont *font )
4382 if (!font->refcount++)
4384 list_remove( &font->unused_entry );
4385 unused_font_count--;
4389 static void release_font( GdiFont *font )
4391 if (!font) return;
4392 if (!--font->refcount)
4394 TRACE( "font %p\n", font );
4396 /* add it to the unused list */
4397 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4398 if (unused_font_count > UNUSED_CACHE_SIZE)
4400 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4401 TRACE( "freeing %p\n", font );
4402 list_remove( &font->entry );
4403 list_remove( &font->unused_entry );
4404 free_font( font );
4406 else unused_font_count++;
4408 if (TRACE_ON(font)) dump_gdi_font_list();
4412 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4414 if(font->font_desc.hash != fd->hash) return TRUE;
4415 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4416 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4417 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4418 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4421 static void calc_hash(FONT_DESC *pfd)
4423 DWORD hash = 0, *ptr, two_chars;
4424 WORD *pwc;
4425 unsigned int i;
4427 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4428 hash ^= *ptr;
4429 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4430 hash ^= *ptr;
4431 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4432 two_chars = *ptr;
4433 pwc = (WCHAR *)&two_chars;
4434 if(!*pwc) break;
4435 *pwc = toupperW(*pwc);
4436 pwc++;
4437 *pwc = toupperW(*pwc);
4438 hash ^= two_chars;
4439 if(!*pwc) break;
4441 hash ^= !pfd->can_use_bitmap;
4442 pfd->hash = hash;
4443 return;
4446 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4448 GdiFont *ret;
4449 FONT_DESC fd;
4451 fd.lf = *plf;
4452 fd.matrix = *pmat;
4453 fd.can_use_bitmap = can_use_bitmap;
4454 calc_hash(&fd);
4456 /* try the in-use list */
4457 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4459 if(fontcmp(ret, &fd)) continue;
4460 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4461 list_remove( &ret->entry );
4462 list_add_head( &gdi_font_list, &ret->entry );
4463 grab_font( ret );
4464 return ret;
4466 return NULL;
4469 static void add_to_cache(GdiFont *font)
4471 static DWORD cache_num = 1;
4473 font->cache_num = cache_num++;
4474 list_add_head(&gdi_font_list, &font->entry);
4475 TRACE( "font %p\n", font );
4478 /*************************************************************
4479 * create_child_font_list
4481 static BOOL create_child_font_list(GdiFont *font)
4483 BOOL ret = FALSE;
4484 SYSTEM_LINKS *font_link;
4485 CHILD_FONT *font_link_entry, *new_child;
4486 FontSubst *psub;
4487 WCHAR* font_name;
4489 psub = get_font_subst(&font_subst_list, font->name, -1);
4490 font_name = psub ? psub->to.name : font->name;
4491 font_link = find_font_link(font_name);
4492 if (font_link != NULL)
4494 TRACE("found entry in system list\n");
4495 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4497 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4498 new_child->face = font_link_entry->face;
4499 new_child->font = NULL;
4500 new_child->face->refcount++;
4501 list_add_tail(&font->child_fonts, &new_child->entry);
4502 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4504 ret = TRUE;
4507 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4508 * Sans Serif. This is how asian windows get default fallbacks for fonts
4510 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4511 font->charset != OEM_CHARSET &&
4512 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4514 font_link = find_font_link(szDefaultFallbackLink);
4515 if (font_link != NULL)
4517 TRACE("found entry in default fallback list\n");
4518 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4520 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4521 new_child->face = font_link_entry->face;
4522 new_child->font = NULL;
4523 new_child->face->refcount++;
4524 list_add_tail(&font->child_fonts, &new_child->entry);
4525 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4527 ret = TRUE;
4531 return ret;
4534 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4536 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4538 if (pFT_Set_Charmap)
4540 FT_Int i;
4541 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4543 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4545 for (i = 0; i < ft_face->num_charmaps; i++)
4547 if (ft_face->charmaps[i]->encoding == encoding)
4549 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4550 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4552 switch (ft_face->charmaps[i]->platform_id)
4554 default:
4555 cmap_def = ft_face->charmaps[i];
4556 break;
4557 case 0: /* Apple Unicode */
4558 cmap0 = ft_face->charmaps[i];
4559 break;
4560 case 1: /* Macintosh */
4561 cmap1 = ft_face->charmaps[i];
4562 break;
4563 case 2: /* ISO */
4564 cmap2 = ft_face->charmaps[i];
4565 break;
4566 case 3: /* Microsoft */
4567 cmap3 = ft_face->charmaps[i];
4568 break;
4572 if (cmap3) /* prefer Microsoft cmap table */
4573 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4574 else if (cmap1)
4575 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4576 else if (cmap2)
4577 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4578 else if (cmap0)
4579 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4580 else if (cmap_def)
4581 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4583 return ft_err == FT_Err_Ok;
4586 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4590 /*************************************************************
4591 * freetype_CreateDC
4593 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4594 LPCWSTR output, const DEVMODEW *devmode )
4596 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4598 if (!physdev) return FALSE;
4599 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4600 return TRUE;
4604 /*************************************************************
4605 * freetype_DeleteDC
4607 static BOOL freetype_DeleteDC( PHYSDEV dev )
4609 struct freetype_physdev *physdev = get_freetype_dev( dev );
4610 release_font( physdev->font );
4611 HeapFree( GetProcessHeap(), 0, physdev );
4612 return TRUE;
4615 static FT_Encoding pick_charmap( FT_Face face, int charset )
4617 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4618 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4619 const FT_Encoding *encs = regular_order;
4621 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4623 while (*encs != 0)
4625 if (select_charmap( face, *encs )) break;
4626 encs++;
4628 return *encs;
4631 #define GASP_GRIDFIT 0x01
4632 #define GASP_DOGRAY 0x02
4633 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4635 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4637 DWORD size;
4638 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4639 WORD *alloced = NULL, *ptr = buf;
4640 WORD num_recs, version;
4641 BOOL ret = FALSE;
4643 *flags = 0;
4644 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4645 if (size == GDI_ERROR) return FALSE;
4646 if (size < 4 * sizeof(WORD)) return FALSE;
4647 if (size > sizeof(buf))
4649 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4650 if (!ptr) return FALSE;
4653 get_font_data( font, GASP_TAG, 0, ptr, size );
4655 version = GET_BE_WORD( *ptr++ );
4656 num_recs = GET_BE_WORD( *ptr++ );
4658 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4660 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4661 goto done;
4664 while (num_recs--)
4666 *flags = GET_BE_WORD( *(ptr + 1) );
4667 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4668 ptr += 2;
4670 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4671 ret = TRUE;
4673 done:
4674 HeapFree( GetProcessHeap(), 0, alloced );
4675 return ret;
4678 /*************************************************************
4679 * freetype_SelectFont
4681 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4683 struct freetype_physdev *physdev = get_freetype_dev( dev );
4684 GdiFont *ret;
4685 Face *face, *best, *best_bitmap;
4686 Family *family, *last_resort_family;
4687 const struct list *face_list;
4688 INT height, width = 0;
4689 unsigned int score = 0, new_score;
4690 signed int diff = 0, newdiff;
4691 BOOL bd, it, can_use_bitmap, want_vertical;
4692 LOGFONTW lf;
4693 CHARSETINFO csi;
4694 FMAT2 dcmat;
4695 FontSubst *psub = NULL;
4696 DC *dc = get_dc_ptr( dev->hdc );
4697 const SYSTEM_LINKS *font_link;
4699 if (!hfont) /* notification that the font has been changed by another driver */
4701 release_font( physdev->font );
4702 physdev->font = NULL;
4703 release_dc_ptr( dc );
4704 return 0;
4707 GetObjectW( hfont, sizeof(lf), &lf );
4708 lf.lfWidth = abs(lf.lfWidth);
4710 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4712 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4713 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4714 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4715 lf.lfEscapement);
4717 if(dc->GraphicsMode == GM_ADVANCED)
4719 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4720 /* Try to avoid not necessary glyph transformations */
4721 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4723 lf.lfHeight *= fabs(dcmat.eM11);
4724 lf.lfWidth *= fabs(dcmat.eM11);
4725 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4728 else
4730 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4731 font scaling abilities. */
4732 dcmat.eM11 = dcmat.eM22 = 1.0;
4733 dcmat.eM21 = dcmat.eM12 = 0;
4734 lf.lfOrientation = lf.lfEscapement;
4735 if (dc->vport2WorldValid)
4737 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4738 lf.lfOrientation = -lf.lfOrientation;
4739 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4740 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4744 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4745 dcmat.eM21, dcmat.eM22);
4747 GDI_CheckNotLock();
4748 EnterCriticalSection( &freetype_cs );
4750 /* check the cache first */
4751 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4752 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4753 goto done;
4756 TRACE("not in cache\n");
4757 ret = alloc_font();
4759 ret->font_desc.matrix = dcmat;
4760 ret->font_desc.lf = lf;
4761 ret->font_desc.can_use_bitmap = can_use_bitmap;
4762 calc_hash(&ret->font_desc);
4764 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4765 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4766 original value lfCharSet. Note this is a special case for
4767 Symbol and doesn't happen at least for "Wingdings*" */
4769 if(!strcmpiW(lf.lfFaceName, SymbolW))
4770 lf.lfCharSet = SYMBOL_CHARSET;
4772 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4773 switch(lf.lfCharSet) {
4774 case DEFAULT_CHARSET:
4775 csi.fs.fsCsb[0] = 0;
4776 break;
4777 default:
4778 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4779 csi.fs.fsCsb[0] = 0;
4780 break;
4784 family = NULL;
4785 if(lf.lfFaceName[0] != '\0') {
4786 CHILD_FONT *font_link_entry;
4787 LPWSTR FaceName = lf.lfFaceName;
4789 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4791 if(psub) {
4792 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4793 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4794 if (psub->to.charset != -1)
4795 lf.lfCharSet = psub->to.charset;
4798 /* We want a match on name and charset or just name if
4799 charset was DEFAULT_CHARSET. If the latter then
4800 we fixup the returned charset later in get_nearest_charset
4801 where we'll either use the charset of the current ansi codepage
4802 or if that's unavailable the first charset that the font supports.
4804 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4805 if (!strcmpiW(family->FamilyName, FaceName) ||
4806 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4808 font_link = find_font_link(family->FamilyName);
4809 face_list = get_face_list_from_family(family);
4810 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4811 if (!(face->scalable || can_use_bitmap))
4812 continue;
4813 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4814 goto found;
4815 if (font_link != NULL &&
4816 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4817 goto found;
4818 if (!csi.fs.fsCsb[0])
4819 goto found;
4824 /* Search by full face name. */
4825 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4826 face_list = get_face_list_from_family(family);
4827 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4828 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4829 (face->scalable || can_use_bitmap))
4831 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4832 goto found_face;
4833 font_link = find_font_link(family->FamilyName);
4834 if (font_link != NULL &&
4835 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4836 goto found_face;
4842 * Try check the SystemLink list first for a replacement font.
4843 * We may find good replacements there.
4845 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4847 if(!strcmpiW(font_link->font_name, FaceName) ||
4848 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4850 TRACE("found entry in system list\n");
4851 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4853 const SYSTEM_LINKS *links;
4855 face = font_link_entry->face;
4856 if (!(face->scalable || can_use_bitmap))
4857 continue;
4858 family = face->family;
4859 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4860 goto found;
4861 links = find_font_link(family->FamilyName);
4862 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4863 goto found;
4869 psub = NULL; /* substitution is no more relevant */
4871 /* If requested charset was DEFAULT_CHARSET then try using charset
4872 corresponding to the current ansi codepage */
4873 if (!csi.fs.fsCsb[0])
4875 INT acp = GetACP();
4876 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4877 FIXME("TCI failed on codepage %d\n", acp);
4878 csi.fs.fsCsb[0] = 0;
4879 } else
4880 lf.lfCharSet = csi.ciCharset;
4883 want_vertical = (lf.lfFaceName[0] == '@');
4885 /* Face families are in the top 4 bits of lfPitchAndFamily,
4886 so mask with 0xF0 before testing */
4888 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4889 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4890 strcpyW(lf.lfFaceName, defFixed);
4891 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4892 strcpyW(lf.lfFaceName, defSerif);
4893 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4894 strcpyW(lf.lfFaceName, defSans);
4895 else
4896 strcpyW(lf.lfFaceName, defSans);
4897 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4898 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4899 font_link = find_font_link(family->FamilyName);
4900 face_list = get_face_list_from_family(family);
4901 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4902 if (!(face->scalable || can_use_bitmap))
4903 continue;
4904 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4905 goto found;
4906 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4907 goto found;
4912 last_resort_family = NULL;
4913 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4914 font_link = find_font_link(family->FamilyName);
4915 face_list = get_face_list_from_family(family);
4916 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4917 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
4918 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4919 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4920 if(face->scalable)
4921 goto found;
4922 if(can_use_bitmap && !last_resort_family)
4923 last_resort_family = family;
4928 if(last_resort_family) {
4929 family = last_resort_family;
4930 csi.fs.fsCsb[0] = 0;
4931 goto found;
4934 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4935 face_list = get_face_list_from_family(family);
4936 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4937 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
4938 csi.fs.fsCsb[0] = 0;
4939 WARN("just using first face for now\n");
4940 goto found;
4942 if(can_use_bitmap && !last_resort_family)
4943 last_resort_family = family;
4946 if(!last_resort_family) {
4947 FIXME("can't find a single appropriate font - bailing\n");
4948 free_font(ret);
4949 ret = NULL;
4950 goto done;
4953 WARN("could only find a bitmap font - this will probably look awful!\n");
4954 family = last_resort_family;
4955 csi.fs.fsCsb[0] = 0;
4957 found:
4958 it = lf.lfItalic ? 1 : 0;
4959 bd = lf.lfWeight > 550 ? 1 : 0;
4961 height = lf.lfHeight;
4963 face = best = best_bitmap = NULL;
4964 font_link = find_font_link(family->FamilyName);
4965 face_list = get_face_list_from_family(family);
4966 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4968 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4969 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4970 !csi.fs.fsCsb[0])
4972 BOOL italic, bold;
4974 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4975 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4976 new_score = (italic ^ it) + (bold ^ bd);
4977 if(!best || new_score <= score)
4979 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4980 italic, bold, it, bd);
4981 score = new_score;
4982 best = face;
4983 if(best->scalable && score == 0) break;
4984 if(!best->scalable)
4986 if(height > 0)
4987 newdiff = height - (signed int)(best->size.height);
4988 else
4989 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4990 if(!best_bitmap || new_score < score ||
4991 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4993 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4994 diff = newdiff;
4995 best_bitmap = best;
4996 if(score == 0 && diff == 0) break;
5002 if(best)
5003 face = best->scalable ? best : best_bitmap;
5004 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5005 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5007 found_face:
5008 height = lf.lfHeight;
5010 ret->fs = face->fs;
5012 if(csi.fs.fsCsb[0]) {
5013 ret->charset = lf.lfCharSet;
5014 ret->codepage = csi.ciACP;
5016 else
5017 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5019 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5020 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5022 ret->aveWidth = height ? lf.lfWidth : 0;
5024 if(!face->scalable) {
5025 /* Windows uses integer scaling factors for bitmap fonts */
5026 INT scale, scaled_height;
5027 GdiFont *cachedfont;
5029 /* FIXME: rotation of bitmap fonts is ignored */
5030 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5031 if (ret->aveWidth)
5032 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5033 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5034 dcmat.eM11 = dcmat.eM22 = 1.0;
5035 /* As we changed the matrix, we need to search the cache for the font again,
5036 * otherwise we might explode the cache. */
5037 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5038 TRACE("Found cached font after non-scalable matrix rescale!\n");
5039 free_font( ret );
5040 ret = cachedfont;
5041 goto done;
5043 calc_hash(&ret->font_desc);
5045 if (height != 0) height = diff;
5046 height += face->size.height;
5048 scale = (height + face->size.height - 1) / face->size.height;
5049 scaled_height = scale * face->size.height;
5050 /* Only jump to the next height if the difference <= 25% original height */
5051 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5052 /* The jump between unscaled and doubled is delayed by 1 */
5053 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5054 ret->scale_y = scale;
5056 width = face->size.x_ppem >> 6;
5057 height = face->size.y_ppem >> 6;
5059 else
5060 ret->scale_y = 1.0;
5061 TRACE("font scale y: %f\n", ret->scale_y);
5063 ret->ft_face = OpenFontFace(ret, face, width, height);
5065 if (!ret->ft_face)
5067 free_font( ret );
5068 ret = NULL;
5069 goto done;
5072 ret->ntmFlags = face->ntmFlags;
5074 pick_charmap( ret->ft_face, ret->charset );
5076 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5077 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5078 ret->underline = lf.lfUnderline ? 0xff : 0;
5079 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5080 create_child_font_list(ret);
5082 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5084 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5085 if (length != GDI_ERROR)
5087 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5088 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5089 TRACE("Loaded GSUB table of %i bytes\n",length);
5092 ret->aa_flags = HIWORD( face->flags );
5094 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5096 add_to_cache(ret);
5097 done:
5098 if (ret)
5100 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5102 switch (lf.lfQuality)
5104 case NONANTIALIASED_QUALITY:
5105 case ANTIALIASED_QUALITY:
5106 next->funcs->pSelectFont( dev, hfont, aa_flags );
5107 break;
5108 case CLEARTYPE_QUALITY:
5109 case CLEARTYPE_NATURAL_QUALITY:
5110 default:
5111 if (!*aa_flags) *aa_flags = ret->aa_flags;
5112 next->funcs->pSelectFont( dev, hfont, aa_flags );
5114 /* fixup the antialiasing flags for that font */
5115 switch (*aa_flags)
5117 case WINE_GGO_HRGB_BITMAP:
5118 case WINE_GGO_HBGR_BITMAP:
5119 case WINE_GGO_VRGB_BITMAP:
5120 case WINE_GGO_VBGR_BITMAP:
5121 if (is_subpixel_rendering_enabled()) break;
5122 *aa_flags = GGO_GRAY4_BITMAP;
5123 /* fall through */
5124 case GGO_GRAY2_BITMAP:
5125 case GGO_GRAY4_BITMAP:
5126 case GGO_GRAY8_BITMAP:
5127 case WINE_GGO_GRAY16_BITMAP:
5128 if (is_hinting_enabled())
5130 WORD gasp_flags;
5131 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5133 TRACE( "font %s %d aa disabled by GASP\n",
5134 debugstr_w(lf.lfFaceName), lf.lfHeight );
5135 *aa_flags = GGO_BITMAP;
5140 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5141 release_font( physdev->font );
5142 physdev->font = ret;
5144 LeaveCriticalSection( &freetype_cs );
5145 release_dc_ptr( dc );
5146 return ret ? hfont : 0;
5149 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5151 HRSRC rsrc;
5152 HGLOBAL hMem;
5153 WCHAR *p;
5154 int i;
5156 id += IDS_FIRST_SCRIPT;
5157 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5158 if (!rsrc) return 0;
5159 hMem = LoadResource( gdi32_module, rsrc );
5160 if (!hMem) return 0;
5162 p = LockResource( hMem );
5163 id &= 0x000f;
5164 while (id--) p += *p + 1;
5166 i = min(LF_FACESIZE - 1, *p);
5167 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5168 buffer[i] = 0;
5169 return i;
5173 /***************************************************
5174 * create_enum_charset_list
5176 * This function creates charset enumeration list because in DEFAULT_CHARSET
5177 * case, the ANSI codepage's charset takes precedence over other charsets.
5178 * This function works as a filter other than DEFAULT_CHARSET case.
5180 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5182 CHARSETINFO csi;
5183 DWORD n = 0;
5185 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5186 csi.fs.fsCsb[0] != 0) {
5187 list->element[n].mask = csi.fs.fsCsb[0];
5188 list->element[n].charset = csi.ciCharset;
5189 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5190 n++;
5192 else { /* charset is DEFAULT_CHARSET or invalid. */
5193 INT acp, i;
5194 DWORD mask = 0;
5196 /* Set the current codepage's charset as the first element. */
5197 acp = GetACP();
5198 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5199 csi.fs.fsCsb[0] != 0) {
5200 list->element[n].mask = csi.fs.fsCsb[0];
5201 list->element[n].charset = csi.ciCharset;
5202 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5203 mask |= csi.fs.fsCsb[0];
5204 n++;
5207 /* Fill out left elements. */
5208 for (i = 0; i < 32; i++) {
5209 FONTSIGNATURE fs;
5210 fs.fsCsb[0] = 1L << i;
5211 fs.fsCsb[1] = 0;
5212 if (fs.fsCsb[0] & mask)
5213 continue; /* skip, already added. */
5214 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5215 continue; /* skip, this is an invalid fsCsb bit. */
5217 list->element[n].mask = fs.fsCsb[0];
5218 list->element[n].charset = csi.ciCharset;
5219 load_script_name( i, list->element[n].name );
5220 mask |= fs.fsCsb[0];
5221 n++;
5224 /* add catch all mask for remaining bits */
5225 if (~mask)
5227 list->element[n].mask = ~mask;
5228 list->element[n].charset = DEFAULT_CHARSET;
5229 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5230 n++;
5233 list->total = n;
5235 return n;
5238 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5239 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5241 GdiFont *font;
5242 LONG width, height;
5244 if (face->cached_enum_data)
5246 TRACE("Cached\n");
5247 *pelf = face->cached_enum_data->elf;
5248 *pntm = face->cached_enum_data->ntm;
5249 *ptype = face->cached_enum_data->type;
5250 return;
5253 font = alloc_font();
5255 if(face->scalable) {
5256 height = 100;
5257 width = 0;
5258 } else {
5259 height = face->size.y_ppem >> 6;
5260 width = face->size.x_ppem >> 6;
5262 font->scale_y = 1.0;
5264 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5266 free_font(font);
5267 return;
5270 font->name = strdupW( family_name );
5271 font->ntmFlags = face->ntmFlags;
5273 if (get_outline_text_metrics(font))
5275 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5277 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5278 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5279 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5281 lstrcpynW(pelf->elfLogFont.lfFaceName,
5282 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5283 LF_FACESIZE);
5284 lstrcpynW(pelf->elfFullName,
5285 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5286 LF_FULLFACESIZE);
5287 lstrcpynW(pelf->elfStyle,
5288 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5289 LF_FACESIZE);
5291 else
5293 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5295 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5296 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5297 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5299 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5300 if (face->FullName)
5301 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5302 else
5303 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5304 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5307 pntm->ntmTm.ntmFlags = face->ntmFlags;
5308 pntm->ntmFontSig = face->fs;
5310 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5312 pelf->elfLogFont.lfEscapement = 0;
5313 pelf->elfLogFont.lfOrientation = 0;
5314 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5315 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5316 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5317 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5318 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5319 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5320 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5321 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5322 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5323 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5324 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5326 *ptype = 0;
5327 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5328 *ptype |= TRUETYPE_FONTTYPE;
5329 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5330 *ptype |= DEVICE_FONTTYPE;
5331 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5332 *ptype |= RASTER_FONTTYPE;
5334 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5335 if (face->cached_enum_data)
5337 face->cached_enum_data->elf = *pelf;
5338 face->cached_enum_data->ntm = *pntm;
5339 face->cached_enum_data->type = *ptype;
5342 free_font(font);
5345 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5347 Face *face;
5348 const struct list *face_list;
5350 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5352 face_list = get_face_list_from_family(family);
5353 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5354 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5356 return FALSE;
5359 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5361 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5363 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5366 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5367 FONTENUMPROCW proc, LPARAM lparam)
5369 ENUMLOGFONTEXW elf;
5370 NEWTEXTMETRICEXW ntm;
5371 DWORD type = 0;
5372 DWORD i;
5374 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5375 for(i = 0; i < list->total; i++) {
5376 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5377 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5378 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5379 i = list->total; /* break out of loop after enumeration */
5381 else
5383 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5384 /* use the DEFAULT_CHARSET case only if no other charset is present */
5385 if (list->element[i].charset == DEFAULT_CHARSET &&
5386 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5387 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5388 strcpyW(elf.elfScript, list->element[i].name);
5389 if (!elf.elfScript[0])
5390 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5392 /* Font Replacement */
5393 if (family != face->family)
5395 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5396 if (face->FullName)
5397 strcpyW(elf.elfFullName, face->FullName);
5398 else
5399 strcpyW(elf.elfFullName, family->FamilyName);
5401 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5402 debugstr_w(elf.elfLogFont.lfFaceName),
5403 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5404 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5405 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5406 ntm.ntmTm.ntmFlags);
5407 /* release section before callback (FIXME) */
5408 LeaveCriticalSection( &freetype_cs );
5409 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5410 EnterCriticalSection( &freetype_cs );
5412 return TRUE;
5415 /*************************************************************
5416 * freetype_EnumFonts
5418 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5420 Family *family;
5421 Face *face;
5422 const struct list *face_list;
5423 LOGFONTW lf;
5424 struct enum_charset_list enum_charsets;
5426 if (!plf)
5428 lf.lfCharSet = DEFAULT_CHARSET;
5429 lf.lfPitchAndFamily = 0;
5430 lf.lfFaceName[0] = 0;
5431 plf = &lf;
5434 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5436 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5438 GDI_CheckNotLock();
5439 EnterCriticalSection( &freetype_cs );
5440 if(plf->lfFaceName[0]) {
5441 FontSubst *psub;
5442 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5444 if(psub) {
5445 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5446 debugstr_w(psub->to.name));
5447 lf = *plf;
5448 strcpyW(lf.lfFaceName, psub->to.name);
5449 plf = &lf;
5452 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5453 if (!family_matches(family, plf)) continue;
5454 face_list = get_face_list_from_family(family);
5455 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5456 if (!face_matches(family->FamilyName, face, plf)) continue;
5457 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5460 } else {
5461 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5462 face_list = get_face_list_from_family(family);
5463 face = LIST_ENTRY(list_head(face_list), Face, entry);
5464 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5467 LeaveCriticalSection( &freetype_cs );
5468 return TRUE;
5471 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5473 pt->x.value = vec->x >> 6;
5474 pt->x.fract = (vec->x & 0x3f) << 10;
5475 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5476 pt->y.value = vec->y >> 6;
5477 pt->y.fract = (vec->y & 0x3f) << 10;
5478 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5479 return;
5482 /***************************************************
5483 * According to the MSDN documentation on WideCharToMultiByte,
5484 * certain codepages cannot set the default_used parameter.
5485 * This returns TRUE if the codepage can set that parameter, false else
5486 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5488 static BOOL codepage_sets_default_used(UINT codepage)
5490 switch (codepage)
5492 case CP_UTF7:
5493 case CP_UTF8:
5494 case CP_SYMBOL:
5495 return FALSE;
5496 default:
5497 return TRUE;
5502 * GSUB Table handling functions
5505 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5507 const GSUB_CoverageFormat1* cf1;
5509 cf1 = table;
5511 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5513 int count = GET_BE_WORD(cf1->GlyphCount);
5514 int i;
5515 TRACE("Coverage Format 1, %i glyphs\n",count);
5516 for (i = 0; i < count; i++)
5517 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5518 return i;
5519 return -1;
5521 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5523 const GSUB_CoverageFormat2* cf2;
5524 int i;
5525 int count;
5526 cf2 = (const GSUB_CoverageFormat2*)cf1;
5528 count = GET_BE_WORD(cf2->RangeCount);
5529 TRACE("Coverage Format 2, %i ranges\n",count);
5530 for (i = 0; i < count; i++)
5532 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5533 return -1;
5534 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5535 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5537 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5538 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5541 return -1;
5543 else
5544 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5546 return -1;
5549 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5551 const GSUB_ScriptList *script;
5552 const GSUB_Script *deflt = NULL;
5553 int i;
5554 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5556 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5557 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5559 const GSUB_Script *scr;
5560 int offset;
5562 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5563 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5565 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5566 return scr;
5567 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5568 deflt = scr;
5570 return deflt;
5573 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5575 int i;
5576 int offset;
5577 const GSUB_LangSys *Lang;
5579 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5581 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5583 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5584 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5586 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5587 return Lang;
5589 offset = GET_BE_WORD(script->DefaultLangSys);
5590 if (offset)
5592 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5593 return Lang;
5595 return NULL;
5598 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5600 int i;
5601 const GSUB_FeatureList *feature;
5602 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5604 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5605 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5607 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5608 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5610 const GSUB_Feature *feat;
5611 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5612 return feat;
5615 return NULL;
5618 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5620 int i;
5621 int offset;
5622 const GSUB_LookupList *lookup;
5623 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5625 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5626 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5628 const GSUB_LookupTable *look;
5629 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5630 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5631 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5632 if (GET_BE_WORD(look->LookupType) != 1)
5633 FIXME("We only handle SubType 1\n");
5634 else
5636 int j;
5638 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5640 const GSUB_SingleSubstFormat1 *ssf1;
5641 offset = GET_BE_WORD(look->SubTable[j]);
5642 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5643 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5645 int offset = GET_BE_WORD(ssf1->Coverage);
5646 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5647 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5649 TRACE(" Glyph 0x%x ->",glyph);
5650 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5651 TRACE(" 0x%x\n",glyph);
5654 else
5656 const GSUB_SingleSubstFormat2 *ssf2;
5657 INT index;
5658 INT offset;
5660 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5661 offset = GET_BE_WORD(ssf1->Coverage);
5662 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5663 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5664 TRACE(" Coverage index %i\n",index);
5665 if (index != -1)
5667 TRACE(" Glyph is 0x%x ->",glyph);
5668 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5669 TRACE("0x%x\n",glyph);
5675 return glyph;
5678 static const char* get_opentype_script(const GdiFont *font)
5681 * I am not sure if this is the correct way to generate our script tag
5684 switch (font->charset)
5686 case ANSI_CHARSET: return "latn";
5687 case BALTIC_CHARSET: return "latn"; /* ?? */
5688 case CHINESEBIG5_CHARSET: return "hani";
5689 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5690 case GB2312_CHARSET: return "hani";
5691 case GREEK_CHARSET: return "grek";
5692 case HANGUL_CHARSET: return "hang";
5693 case RUSSIAN_CHARSET: return "cyrl";
5694 case SHIFTJIS_CHARSET: return "kana";
5695 case TURKISH_CHARSET: return "latn"; /* ?? */
5696 case VIETNAMESE_CHARSET: return "latn";
5697 case JOHAB_CHARSET: return "latn"; /* ?? */
5698 case ARABIC_CHARSET: return "arab";
5699 case HEBREW_CHARSET: return "hebr";
5700 case THAI_CHARSET: return "thai";
5701 default: return "latn";
5705 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5707 const GSUB_Header *header;
5708 const GSUB_Script *script;
5709 const GSUB_LangSys *language;
5710 const GSUB_Feature *feature;
5712 if (!font->GSUB_Table)
5713 return glyph;
5715 header = font->GSUB_Table;
5717 script = GSUB_get_script_table(header, get_opentype_script(font));
5718 if (!script)
5720 TRACE("Script not found\n");
5721 return glyph;
5723 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5724 if (!language)
5726 TRACE("Language not found\n");
5727 return glyph;
5729 feature = GSUB_get_feature(header, language, "vrt2");
5730 if (!feature)
5731 feature = GSUB_get_feature(header, language, "vert");
5732 if (!feature)
5734 TRACE("vrt2/vert feature not found\n");
5735 return glyph;
5737 return GSUB_apply_feature(header, feature, glyph);
5740 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5742 FT_UInt glyphId;
5744 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5745 WCHAR wc = (WCHAR)glyph;
5746 BOOL default_used;
5747 BOOL *default_used_pointer;
5748 FT_UInt ret;
5749 char buf;
5750 default_used_pointer = NULL;
5751 default_used = FALSE;
5752 if (codepage_sets_default_used(font->codepage))
5753 default_used_pointer = &default_used;
5754 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5756 if (font->codepage == CP_SYMBOL && wc < 0x100)
5757 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5758 else
5759 ret = 0;
5761 else
5762 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5763 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5764 return ret;
5767 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5769 if (glyph < 0x100) glyph += 0xf000;
5770 /* there is a number of old pre-Unicode "broken" TTFs, which
5771 do have symbols at U+00XX instead of U+f0XX */
5772 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5773 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5775 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5777 return glyphId;
5780 /*************************************************************
5781 * freetype_GetGlyphIndices
5783 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5785 struct freetype_physdev *physdev = get_freetype_dev( dev );
5786 int i;
5787 WORD default_char;
5788 BOOL got_default = FALSE;
5790 if (!physdev->font)
5792 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5793 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5796 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5798 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5799 got_default = TRUE;
5802 GDI_CheckNotLock();
5803 EnterCriticalSection( &freetype_cs );
5805 for(i = 0; i < count; i++)
5807 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5808 if (pgi[i] == 0)
5810 if (!got_default)
5812 if (FT_IS_SFNT(physdev->font->ft_face))
5814 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5815 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5817 else
5819 TEXTMETRICW textm;
5820 get_text_metrics(physdev->font, &textm);
5821 default_char = textm.tmDefaultChar;
5823 got_default = TRUE;
5825 pgi[i] = default_char;
5828 LeaveCriticalSection( &freetype_cs );
5829 return count;
5832 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5834 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5835 return !memcmp(matrix, &identity, sizeof(FMAT2));
5838 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5840 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5841 return !memcmp(matrix, &identity, sizeof(MAT2));
5844 static inline BYTE get_max_level( UINT format )
5846 switch( format )
5848 case GGO_GRAY2_BITMAP: return 4;
5849 case GGO_GRAY4_BITMAP: return 16;
5850 case GGO_GRAY8_BITMAP: return 64;
5852 return 255;
5855 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5857 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5858 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5859 const MAT2* lpmat)
5861 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5862 FT_Face ft_face = incoming_font->ft_face;
5863 GdiFont *font = incoming_font;
5864 FT_UInt glyph_index;
5865 DWORD width, height, pitch, needed = 0;
5866 FT_Bitmap ft_bitmap;
5867 FT_Error err;
5868 INT left, right, top = 0, bottom = 0, adv;
5869 FT_Angle angle = 0;
5870 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5871 double widthRatio = 1.0;
5872 FT_Matrix transMat = identityMat;
5873 FT_Matrix transMatUnrotated;
5874 BOOL needsTransform = FALSE;
5875 BOOL tategaki = (font->GSUB_Table != NULL);
5876 UINT original_index;
5877 FT_Fixed avgAdvance = 0;
5879 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5880 buflen, buf, lpmat);
5882 TRACE("font transform %f %f %f %f\n",
5883 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5884 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5886 if(format & GGO_GLYPH_INDEX) {
5887 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5888 original_index = glyph;
5889 format &= ~GGO_GLYPH_INDEX;
5890 } else {
5891 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5892 ft_face = font->ft_face;
5893 original_index = glyph_index;
5896 if(format & GGO_UNHINTED) {
5897 load_flags |= FT_LOAD_NO_HINTING;
5898 format &= ~GGO_UNHINTED;
5901 /* tategaki never appears to happen to lower glyph index */
5902 if (glyph_index < TATEGAKI_LOWER_BOUND )
5903 tategaki = FALSE;
5905 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5906 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5907 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5908 font->gmsize * sizeof(GM*));
5909 } else {
5910 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5911 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5913 *lpgm = FONT_GM(font,original_index)->gm;
5914 *abc = FONT_GM(font,original_index)->abc;
5915 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5916 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5917 lpgm->gmCellIncX, lpgm->gmCellIncY);
5918 return 1; /* FIXME */
5922 if (!font->gm[original_index / GM_BLOCK_SIZE])
5923 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5925 /* Scaling factor */
5926 if (font->aveWidth)
5928 TEXTMETRICW tm;
5930 get_text_metrics(font, &tm);
5932 widthRatio = (double)font->aveWidth;
5933 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5935 else
5936 widthRatio = font->scale_y;
5938 /* Scaling transform */
5939 if (widthRatio != 1.0 || font->scale_y != 1.0)
5941 FT_Matrix scaleMat;
5942 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5943 scaleMat.xy = 0;
5944 scaleMat.yx = 0;
5945 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5947 pFT_Matrix_Multiply(&scaleMat, &transMat);
5948 needsTransform = TRUE;
5951 /* Slant transform */
5952 if (font->fake_italic) {
5953 FT_Matrix slantMat;
5955 slantMat.xx = (1 << 16);
5956 slantMat.xy = ((1 << 16) >> 2);
5957 slantMat.yx = 0;
5958 slantMat.yy = (1 << 16);
5959 pFT_Matrix_Multiply(&slantMat, &transMat);
5960 needsTransform = TRUE;
5963 /* Rotation transform */
5964 transMatUnrotated = transMat;
5965 if(font->orientation && !tategaki) {
5966 FT_Matrix rotationMat;
5967 FT_Vector vecAngle;
5968 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5969 pFT_Vector_Unit(&vecAngle, angle);
5970 rotationMat.xx = vecAngle.x;
5971 rotationMat.xy = -vecAngle.y;
5972 rotationMat.yx = -rotationMat.xy;
5973 rotationMat.yy = rotationMat.xx;
5975 pFT_Matrix_Multiply(&rotationMat, &transMat);
5976 needsTransform = TRUE;
5979 /* World transform */
5980 if (!is_identity_FMAT2(&font->font_desc.matrix))
5982 FT_Matrix worldMat;
5983 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5984 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
5985 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
5986 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5987 pFT_Matrix_Multiply(&worldMat, &transMat);
5988 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5989 needsTransform = TRUE;
5992 /* Extra transformation specified by caller */
5993 if (!is_identity_MAT2(lpmat))
5995 FT_Matrix extraMat;
5996 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5997 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
5998 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
5999 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6000 pFT_Matrix_Multiply(&extraMat, &transMat);
6001 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6002 needsTransform = TRUE;
6005 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6007 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6009 if(err) {
6010 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6011 return GDI_ERROR;
6014 if(FT_IS_SCALABLE(incoming_font->ft_face)) {
6015 TEXTMETRICW tm;
6016 if (get_text_metrics(incoming_font, &tm) &&
6017 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6018 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth,
6019 incoming_font->ft_face->size->metrics.x_scale);
6020 if (avgAdvance && (ft_face->glyph->metrics.horiAdvance+63) >> 6 == (avgAdvance*2+63) >> 6)
6021 TRACE("Fixed-pitch full-width character detected\n");
6022 else
6023 avgAdvance = 0; /* cancel this feature */
6027 if(!needsTransform) {
6028 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
6029 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
6030 if (!avgAdvance)
6031 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
6032 else
6033 adv = (INT)((avgAdvance + 32) >> 6) * 2;
6035 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
6036 bottom = (ft_face->glyph->metrics.horiBearingY -
6037 ft_face->glyph->metrics.height) & -64;
6038 lpgm->gmCellIncX = adv;
6039 lpgm->gmCellIncY = 0;
6040 } else {
6041 INT xc, yc;
6042 FT_Vector vec;
6044 left = right = 0;
6046 for(xc = 0; xc < 2; xc++) {
6047 for(yc = 0; yc < 2; yc++) {
6048 vec.x = (ft_face->glyph->metrics.horiBearingX +
6049 xc * ft_face->glyph->metrics.width);
6050 vec.y = ft_face->glyph->metrics.horiBearingY -
6051 yc * ft_face->glyph->metrics.height;
6052 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6053 pFT_Vector_Transform(&vec, &transMat);
6054 if(xc == 0 && yc == 0) {
6055 left = right = vec.x;
6056 top = bottom = vec.y;
6057 } else {
6058 if(vec.x < left) left = vec.x;
6059 else if(vec.x > right) right = vec.x;
6060 if(vec.y < bottom) bottom = vec.y;
6061 else if(vec.y > top) top = vec.y;
6065 left = left & -64;
6066 right = (right + 63) & -64;
6067 bottom = bottom & -64;
6068 top = (top + 63) & -64;
6070 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6071 vec.x = ft_face->glyph->metrics.horiAdvance;
6072 vec.y = 0;
6073 pFT_Vector_Transform(&vec, &transMat);
6074 lpgm->gmCellIncY = -((vec.y+63) >> 6);
6075 if (!avgAdvance || vec.y)
6076 lpgm->gmCellIncX = (vec.x+63) >> 6;
6077 else {
6078 vec.x = avgAdvance;
6079 vec.y = 0;
6080 pFT_Vector_Transform(&vec, &transMat);
6081 lpgm->gmCellIncX = ((vec.x+32) >> 6) * 2;
6084 vec.x = ft_face->glyph->metrics.horiAdvance;
6085 vec.y = 0;
6086 pFT_Vector_Transform(&vec, &transMatUnrotated);
6087 if (!avgAdvance || vec.y)
6088 adv = (vec.x+63) >> 6;
6089 else {
6090 vec.x = avgAdvance;
6091 vec.y = 0;
6092 pFT_Vector_Transform(&vec, &transMatUnrotated);
6093 adv = ((vec.x+32) >> 6) * 2;
6097 lpgm->gmBlackBoxX = (right - left) >> 6;
6098 lpgm->gmBlackBoxY = (top - bottom) >> 6;
6099 lpgm->gmptGlyphOrigin.x = left >> 6;
6100 lpgm->gmptGlyphOrigin.y = top >> 6;
6101 abc->abcA = left >> 6;
6102 abc->abcB = (right - left) >> 6;
6103 abc->abcC = adv - abc->abcA - abc->abcB;
6105 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6106 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6107 lpgm->gmCellIncX, lpgm->gmCellIncY);
6109 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6110 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6112 FONT_GM(font,original_index)->gm = *lpgm;
6113 FONT_GM(font,original_index)->abc = *abc;
6114 FONT_GM(font,original_index)->init = TRUE;
6117 if(format == GGO_METRICS)
6119 return 1; /* FIXME */
6122 if(ft_face->glyph->format != ft_glyph_format_outline &&
6123 (format == GGO_NATIVE || format == GGO_BEZIER))
6125 TRACE("loaded a bitmap\n");
6126 return GDI_ERROR;
6129 switch(format) {
6130 case GGO_BITMAP:
6131 width = lpgm->gmBlackBoxX;
6132 height = lpgm->gmBlackBoxY;
6133 pitch = ((width + 31) >> 5) << 2;
6134 needed = pitch * height;
6136 if(!buf || !buflen) break;
6138 switch(ft_face->glyph->format) {
6139 case ft_glyph_format_bitmap:
6141 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6142 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
6143 INT h = ft_face->glyph->bitmap.rows;
6144 while(h--) {
6145 memcpy(dst, src, w);
6146 src += ft_face->glyph->bitmap.pitch;
6147 dst += pitch;
6149 break;
6152 case ft_glyph_format_outline:
6153 ft_bitmap.width = width;
6154 ft_bitmap.rows = height;
6155 ft_bitmap.pitch = pitch;
6156 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6157 ft_bitmap.buffer = buf;
6159 if(needsTransform)
6160 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6162 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6164 /* Note: FreeType will only set 'black' bits for us. */
6165 memset(buf, 0, needed);
6166 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6167 break;
6169 default:
6170 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6171 return GDI_ERROR;
6173 break;
6175 case GGO_GRAY2_BITMAP:
6176 case GGO_GRAY4_BITMAP:
6177 case GGO_GRAY8_BITMAP:
6178 case WINE_GGO_GRAY16_BITMAP:
6180 unsigned int max_level, row, col;
6181 BYTE *start, *ptr;
6183 width = lpgm->gmBlackBoxX;
6184 height = lpgm->gmBlackBoxY;
6185 pitch = (width + 3) / 4 * 4;
6186 needed = pitch * height;
6188 if(!buf || !buflen) break;
6190 max_level = get_max_level( format );
6192 switch(ft_face->glyph->format) {
6193 case ft_glyph_format_bitmap:
6195 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6196 INT h = ft_face->glyph->bitmap.rows;
6197 INT x;
6198 memset( buf, 0, needed );
6199 while(h--) {
6200 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6201 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6202 src += ft_face->glyph->bitmap.pitch;
6203 dst += pitch;
6205 return needed;
6207 case ft_glyph_format_outline:
6209 ft_bitmap.width = width;
6210 ft_bitmap.rows = height;
6211 ft_bitmap.pitch = pitch;
6212 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6213 ft_bitmap.buffer = buf;
6215 if(needsTransform)
6216 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6218 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6220 memset(ft_bitmap.buffer, 0, buflen);
6222 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6224 if (max_level != 255)
6226 for (row = 0, start = buf; row < height; row++)
6228 for (col = 0, ptr = start; col < width; col++, ptr++)
6229 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6230 start += pitch;
6233 return needed;
6236 default:
6237 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6238 return GDI_ERROR;
6240 break;
6243 case WINE_GGO_HRGB_BITMAP:
6244 case WINE_GGO_HBGR_BITMAP:
6245 case WINE_GGO_VRGB_BITMAP:
6246 case WINE_GGO_VBGR_BITMAP:
6247 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6249 switch (ft_face->glyph->format)
6251 case FT_GLYPH_FORMAT_BITMAP:
6253 BYTE *src, *dst;
6254 INT src_pitch, x;
6256 width = lpgm->gmBlackBoxX;
6257 height = lpgm->gmBlackBoxY;
6258 pitch = width * 4;
6259 needed = pitch * height;
6261 if (!buf || !buflen) break;
6263 memset(buf, 0, buflen);
6264 dst = buf;
6265 src = ft_face->glyph->bitmap.buffer;
6266 src_pitch = ft_face->glyph->bitmap.pitch;
6268 height = min( height, ft_face->glyph->bitmap.rows );
6269 while ( height-- )
6271 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6273 if ( src[x / 8] & masks[x % 8] )
6274 ((unsigned int *)dst)[x] = ~0u;
6276 src += src_pitch;
6277 dst += pitch;
6280 break;
6283 case FT_GLYPH_FORMAT_OUTLINE:
6285 unsigned int *dst;
6286 BYTE *src;
6287 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6288 INT x_shift, y_shift;
6289 BOOL rgb;
6290 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6291 FT_Render_Mode render_mode =
6292 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6293 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6295 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6297 if ( render_mode == FT_RENDER_MODE_LCD)
6299 lpgm->gmBlackBoxX += 2;
6300 lpgm->gmptGlyphOrigin.x -= 1;
6302 else
6304 lpgm->gmBlackBoxY += 2;
6305 lpgm->gmptGlyphOrigin.y += 1;
6309 width = lpgm->gmBlackBoxX;
6310 height = lpgm->gmBlackBoxY;
6311 pitch = width * 4;
6312 needed = pitch * height;
6314 if (!buf || !buflen) break;
6316 memset(buf, 0, buflen);
6317 dst = buf;
6318 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6320 if ( needsTransform )
6321 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6323 if ( pFT_Library_SetLcdFilter )
6324 pFT_Library_SetLcdFilter( library, lcdfilter );
6325 pFT_Render_Glyph (ft_face->glyph, render_mode);
6327 src = ft_face->glyph->bitmap.buffer;
6328 src_pitch = ft_face->glyph->bitmap.pitch;
6329 src_width = ft_face->glyph->bitmap.width;
6330 src_height = ft_face->glyph->bitmap.rows;
6332 if ( render_mode == FT_RENDER_MODE_LCD)
6334 rgb_interval = 1;
6335 hmul = 3;
6336 vmul = 1;
6338 else
6340 rgb_interval = src_pitch;
6341 hmul = 1;
6342 vmul = 3;
6345 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6346 if ( x_shift < 0 ) x_shift = 0;
6347 if ( x_shift + (src_width / hmul) > width )
6348 x_shift = width - (src_width / hmul);
6350 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6351 if ( y_shift < 0 ) y_shift = 0;
6352 if ( y_shift + (src_height / vmul) > height )
6353 y_shift = height - (src_height / vmul);
6355 dst += x_shift + y_shift * ( pitch / 4 );
6356 while ( src_height )
6358 for ( x = 0; x < src_width / hmul; x++ )
6360 if ( rgb )
6362 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6363 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6364 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6365 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6367 else
6369 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6370 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6371 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6372 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6375 src += src_pitch * vmul;
6376 dst += pitch / 4;
6377 src_height -= vmul;
6380 break;
6383 default:
6384 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6385 return GDI_ERROR;
6388 break;
6390 #else
6391 return GDI_ERROR;
6392 #endif
6394 case GGO_NATIVE:
6396 int contour, point = 0, first_pt;
6397 FT_Outline *outline = &ft_face->glyph->outline;
6398 TTPOLYGONHEADER *pph;
6399 TTPOLYCURVE *ppc;
6400 DWORD pph_start, cpfx, type;
6402 if(buflen == 0) buf = NULL;
6404 if (needsTransform && buf) {
6405 pFT_Outline_Transform(outline, &transMat);
6408 for(contour = 0; contour < outline->n_contours; contour++) {
6409 /* Ignore contours containing one point */
6410 if(point == outline->contours[contour]) {
6411 point++;
6412 continue;
6415 pph_start = needed;
6416 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6417 first_pt = point;
6418 if(buf) {
6419 pph->dwType = TT_POLYGON_TYPE;
6420 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6422 needed += sizeof(*pph);
6423 point++;
6424 while(point <= outline->contours[contour]) {
6425 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6426 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6427 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6428 cpfx = 0;
6429 do {
6430 if(buf)
6431 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6432 cpfx++;
6433 point++;
6434 } while(point <= outline->contours[contour] &&
6435 (outline->tags[point] & FT_Curve_Tag_On) ==
6436 (outline->tags[point-1] & FT_Curve_Tag_On));
6437 /* At the end of a contour Windows adds the start point, but
6438 only for Beziers */
6439 if(point > outline->contours[contour] &&
6440 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6441 if(buf)
6442 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6443 cpfx++;
6444 } else if(point <= outline->contours[contour] &&
6445 outline->tags[point] & FT_Curve_Tag_On) {
6446 /* add closing pt for bezier */
6447 if(buf)
6448 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6449 cpfx++;
6450 point++;
6452 if(buf) {
6453 ppc->wType = type;
6454 ppc->cpfx = cpfx;
6456 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6458 if(buf)
6459 pph->cb = needed - pph_start;
6461 break;
6463 case GGO_BEZIER:
6465 /* Convert the quadratic Beziers to cubic Beziers.
6466 The parametric eqn for a cubic Bezier is, from PLRM:
6467 r(t) = at^3 + bt^2 + ct + r0
6468 with the control points:
6469 r1 = r0 + c/3
6470 r2 = r1 + (c + b)/3
6471 r3 = r0 + c + b + a
6473 A quadratic Bezier has the form:
6474 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6476 So equating powers of t leads to:
6477 r1 = 2/3 p1 + 1/3 p0
6478 r2 = 2/3 p1 + 1/3 p2
6479 and of course r0 = p0, r3 = p2
6482 int contour, point = 0, first_pt;
6483 FT_Outline *outline = &ft_face->glyph->outline;
6484 TTPOLYGONHEADER *pph;
6485 TTPOLYCURVE *ppc;
6486 DWORD pph_start, cpfx, type;
6487 FT_Vector cubic_control[4];
6488 if(buflen == 0) buf = NULL;
6490 if (needsTransform && buf) {
6491 pFT_Outline_Transform(outline, &transMat);
6494 for(contour = 0; contour < outline->n_contours; contour++) {
6495 pph_start = needed;
6496 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6497 first_pt = point;
6498 if(buf) {
6499 pph->dwType = TT_POLYGON_TYPE;
6500 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6502 needed += sizeof(*pph);
6503 point++;
6504 while(point <= outline->contours[contour]) {
6505 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6506 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6507 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6508 cpfx = 0;
6509 do {
6510 if(type == TT_PRIM_LINE) {
6511 if(buf)
6512 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6513 cpfx++;
6514 point++;
6515 } else {
6516 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6517 so cpfx = 3n */
6519 /* FIXME: Possible optimization in endpoint calculation
6520 if there are two consecutive curves */
6521 cubic_control[0] = outline->points[point-1];
6522 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6523 cubic_control[0].x += outline->points[point].x + 1;
6524 cubic_control[0].y += outline->points[point].y + 1;
6525 cubic_control[0].x >>= 1;
6526 cubic_control[0].y >>= 1;
6528 if(point+1 > outline->contours[contour])
6529 cubic_control[3] = outline->points[first_pt];
6530 else {
6531 cubic_control[3] = outline->points[point+1];
6532 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6533 cubic_control[3].x += outline->points[point].x + 1;
6534 cubic_control[3].y += outline->points[point].y + 1;
6535 cubic_control[3].x >>= 1;
6536 cubic_control[3].y >>= 1;
6539 /* r1 = 1/3 p0 + 2/3 p1
6540 r2 = 1/3 p2 + 2/3 p1 */
6541 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6542 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6543 cubic_control[2] = cubic_control[1];
6544 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6545 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6546 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6547 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6548 if(buf) {
6549 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6550 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6551 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6553 cpfx += 3;
6554 point++;
6556 } while(point <= outline->contours[contour] &&
6557 (outline->tags[point] & FT_Curve_Tag_On) ==
6558 (outline->tags[point-1] & FT_Curve_Tag_On));
6559 /* At the end of a contour Windows adds the start point,
6560 but only for Beziers and we've already done that.
6562 if(point <= outline->contours[contour] &&
6563 outline->tags[point] & FT_Curve_Tag_On) {
6564 /* This is the closing pt of a bezier, but we've already
6565 added it, so just inc point and carry on */
6566 point++;
6568 if(buf) {
6569 ppc->wType = type;
6570 ppc->cpfx = cpfx;
6572 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6574 if(buf)
6575 pph->cb = needed - pph_start;
6577 break;
6580 default:
6581 FIXME("Unsupported format %d\n", format);
6582 return GDI_ERROR;
6584 return needed;
6587 static BOOL get_bitmap_text_metrics(GdiFont *font)
6589 FT_Face ft_face = font->ft_face;
6590 FT_WinFNT_HeaderRec winfnt_header;
6591 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6592 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6593 font->potm->otmSize = size;
6595 #define TM font->potm->otmTextMetrics
6596 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6598 TM.tmHeight = winfnt_header.pixel_height;
6599 TM.tmAscent = winfnt_header.ascent;
6600 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6601 TM.tmInternalLeading = winfnt_header.internal_leading;
6602 TM.tmExternalLeading = winfnt_header.external_leading;
6603 TM.tmAveCharWidth = winfnt_header.avg_width;
6604 TM.tmMaxCharWidth = winfnt_header.max_width;
6605 TM.tmWeight = winfnt_header.weight;
6606 TM.tmOverhang = 0;
6607 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6608 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6609 TM.tmFirstChar = winfnt_header.first_char;
6610 TM.tmLastChar = winfnt_header.last_char;
6611 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6612 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6613 TM.tmItalic = winfnt_header.italic;
6614 TM.tmUnderlined = font->underline;
6615 TM.tmStruckOut = font->strikeout;
6616 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6617 TM.tmCharSet = winfnt_header.charset;
6619 else
6621 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6622 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6623 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6624 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6625 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6626 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6627 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6628 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6629 TM.tmOverhang = 0;
6630 TM.tmDigitizedAspectX = 96; /* FIXME */
6631 TM.tmDigitizedAspectY = 96; /* FIXME */
6632 TM.tmFirstChar = 1;
6633 TM.tmLastChar = 255;
6634 TM.tmDefaultChar = 32;
6635 TM.tmBreakChar = 32;
6636 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6637 TM.tmUnderlined = font->underline;
6638 TM.tmStruckOut = font->strikeout;
6639 /* NB inverted meaning of TMPF_FIXED_PITCH */
6640 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6641 TM.tmCharSet = font->charset;
6643 #undef TM
6645 return TRUE;
6649 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6651 double scale_x, scale_y;
6653 if (font->aveWidth)
6655 scale_x = (double)font->aveWidth;
6656 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6658 else
6659 scale_x = font->scale_y;
6661 scale_x *= fabs(font->font_desc.matrix.eM11);
6662 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6664 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6665 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6667 SCALE_Y(ptm->tmHeight);
6668 SCALE_Y(ptm->tmAscent);
6669 SCALE_Y(ptm->tmDescent);
6670 SCALE_Y(ptm->tmInternalLeading);
6671 SCALE_Y(ptm->tmExternalLeading);
6672 SCALE_Y(ptm->tmOverhang);
6674 SCALE_X(ptm->tmAveCharWidth);
6675 SCALE_X(ptm->tmMaxCharWidth);
6677 #undef SCALE_X
6678 #undef SCALE_Y
6681 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6683 double scale_x, scale_y;
6685 if (font->aveWidth)
6687 scale_x = (double)font->aveWidth;
6688 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6690 else
6691 scale_x = font->scale_y;
6693 scale_x *= fabs(font->font_desc.matrix.eM11);
6694 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6696 scale_font_metrics(font, &potm->otmTextMetrics);
6698 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6699 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6701 SCALE_Y(potm->otmAscent);
6702 SCALE_Y(potm->otmDescent);
6703 SCALE_Y(potm->otmLineGap);
6704 SCALE_Y(potm->otmsCapEmHeight);
6705 SCALE_Y(potm->otmsXHeight);
6706 SCALE_Y(potm->otmrcFontBox.top);
6707 SCALE_Y(potm->otmrcFontBox.bottom);
6708 SCALE_X(potm->otmrcFontBox.left);
6709 SCALE_X(potm->otmrcFontBox.right);
6710 SCALE_Y(potm->otmMacAscent);
6711 SCALE_Y(potm->otmMacDescent);
6712 SCALE_Y(potm->otmMacLineGap);
6713 SCALE_X(potm->otmptSubscriptSize.x);
6714 SCALE_Y(potm->otmptSubscriptSize.y);
6715 SCALE_X(potm->otmptSubscriptOffset.x);
6716 SCALE_Y(potm->otmptSubscriptOffset.y);
6717 SCALE_X(potm->otmptSuperscriptSize.x);
6718 SCALE_Y(potm->otmptSuperscriptSize.y);
6719 SCALE_X(potm->otmptSuperscriptOffset.x);
6720 SCALE_Y(potm->otmptSuperscriptOffset.y);
6721 SCALE_Y(potm->otmsStrikeoutSize);
6722 SCALE_Y(potm->otmsStrikeoutPosition);
6723 SCALE_Y(potm->otmsUnderscoreSize);
6724 SCALE_Y(potm->otmsUnderscorePosition);
6726 #undef SCALE_X
6727 #undef SCALE_Y
6730 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6732 if(!font->potm)
6734 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6736 /* Make sure that the font has sane width/height ratio */
6737 if (font->aveWidth)
6739 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6741 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6742 font->aveWidth = 0;
6746 *ptm = font->potm->otmTextMetrics;
6747 scale_font_metrics(font, ptm);
6748 return TRUE;
6751 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6753 int i;
6755 for(i = 0; i < ft_face->num_charmaps; i++)
6757 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6758 return TRUE;
6760 return FALSE;
6763 static BOOL get_outline_text_metrics(GdiFont *font)
6765 BOOL ret = FALSE;
6766 FT_Face ft_face = font->ft_face;
6767 UINT needed, lenfam, lensty, lenface, lenfull;
6768 TT_OS2 *pOS2;
6769 TT_HoriHeader *pHori;
6770 TT_Postscript *pPost;
6771 FT_Fixed x_scale, y_scale;
6772 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6773 char *cp;
6774 INT ascent, descent;
6776 TRACE("font=%p\n", font);
6778 if(!FT_IS_SCALABLE(ft_face))
6779 return FALSE;
6781 needed = sizeof(*font->potm);
6783 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6784 family_nameW = strdupW(font->name);
6786 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6787 if (!style_nameW)
6788 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6789 if (!style_nameW)
6791 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6792 style_nameW = towstr( CP_ACP, ft_face->style_name );
6794 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6796 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6797 if (!face_nameW)
6798 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6799 if (!face_nameW)
6801 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6802 face_nameW = strdupW(font->name);
6804 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6805 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6807 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6808 if (!full_nameW)
6809 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6810 if (!full_nameW)
6812 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6813 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6814 full_nameW = strdupW(fake_nameW);
6816 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6818 /* These names should be read from the TT name table */
6820 /* length of otmpFamilyName */
6821 needed += lenfam;
6823 /* length of otmpFaceName */
6824 needed += lenface;
6826 /* length of otmpStyleName */
6827 needed += lensty;
6829 /* length of otmpFullName */
6830 needed += lenfull;
6833 x_scale = ft_face->size->metrics.x_scale;
6834 y_scale = ft_face->size->metrics.y_scale;
6836 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6837 if(!pOS2) {
6838 FIXME("Can't find OS/2 table - not TT font?\n");
6839 goto end;
6842 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6843 if(!pHori) {
6844 FIXME("Can't find HHEA table - not TT font?\n");
6845 goto end;
6848 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6850 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",
6851 pOS2->usWinAscent, pOS2->usWinDescent,
6852 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6853 pOS2->xAvgCharWidth,
6854 ft_face->ascender, ft_face->descender, ft_face->height,
6855 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6856 ft_face->bbox.yMax, ft_face->bbox.yMin);
6858 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6859 font->potm->otmSize = needed;
6861 #define TM font->potm->otmTextMetrics
6863 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6864 ascent = pHori->Ascender;
6865 descent = -pHori->Descender;
6866 } else {
6867 ascent = pOS2->usWinAscent;
6868 descent = pOS2->usWinDescent;
6871 font->ntmCellHeight = ascent + descent;
6872 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6874 if(font->yMax) {
6875 TM.tmAscent = font->yMax;
6876 TM.tmDescent = -font->yMin;
6877 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6878 } else {
6879 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6880 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6881 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6882 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6885 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6887 /* MSDN says:
6888 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6890 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6891 ((ascent + descent) -
6892 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6894 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6895 if (TM.tmAveCharWidth == 0) {
6896 TM.tmAveCharWidth = 1;
6898 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6899 TM.tmWeight = FW_REGULAR;
6900 if (font->fake_bold)
6901 TM.tmWeight = FW_BOLD;
6902 else
6904 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6906 if (pOS2->usWeightClass > FW_MEDIUM)
6907 TM.tmWeight = pOS2->usWeightClass;
6909 else if (pOS2->usWeightClass <= FW_MEDIUM)
6910 TM.tmWeight = pOS2->usWeightClass;
6912 TM.tmOverhang = 0;
6913 TM.tmDigitizedAspectX = 96; /* FIXME */
6914 TM.tmDigitizedAspectY = 96; /* FIXME */
6915 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6916 * symbol range to 0 - f0ff
6919 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6921 TM.tmFirstChar = 0;
6922 switch(GetACP())
6924 case 1257: /* Baltic */
6925 TM.tmLastChar = 0xf8fd;
6926 break;
6927 default:
6928 TM.tmLastChar = 0xf0ff;
6930 TM.tmBreakChar = 0x20;
6931 TM.tmDefaultChar = 0x1f;
6933 else
6935 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6936 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6938 if(pOS2->usFirstCharIndex <= 1)
6939 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6940 else if (pOS2->usFirstCharIndex > 0xff)
6941 TM.tmBreakChar = 0x20;
6942 else
6943 TM.tmBreakChar = pOS2->usFirstCharIndex;
6944 TM.tmDefaultChar = TM.tmBreakChar - 1;
6946 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6947 TM.tmUnderlined = font->underline;
6948 TM.tmStruckOut = font->strikeout;
6950 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6951 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6952 (pOS2->version == 0xFFFFU ||
6953 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6954 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6955 else
6956 TM.tmPitchAndFamily = 0;
6958 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6960 case PAN_FAMILY_SCRIPT:
6961 TM.tmPitchAndFamily |= FF_SCRIPT;
6962 break;
6964 case PAN_FAMILY_DECORATIVE:
6965 TM.tmPitchAndFamily |= FF_DECORATIVE;
6966 break;
6968 case PAN_ANY:
6969 case PAN_NO_FIT:
6970 case PAN_FAMILY_TEXT_DISPLAY:
6971 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6972 /* which is clearly not what the panose spec says. */
6973 default:
6974 if(TM.tmPitchAndFamily == 0 || /* fixed */
6975 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6976 TM.tmPitchAndFamily = FF_MODERN;
6977 else
6979 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6981 case PAN_ANY:
6982 case PAN_NO_FIT:
6983 default:
6984 TM.tmPitchAndFamily |= FF_DONTCARE;
6985 break;
6987 case PAN_SERIF_COVE:
6988 case PAN_SERIF_OBTUSE_COVE:
6989 case PAN_SERIF_SQUARE_COVE:
6990 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6991 case PAN_SERIF_SQUARE:
6992 case PAN_SERIF_THIN:
6993 case PAN_SERIF_BONE:
6994 case PAN_SERIF_EXAGGERATED:
6995 case PAN_SERIF_TRIANGLE:
6996 TM.tmPitchAndFamily |= FF_ROMAN;
6997 break;
6999 case PAN_SERIF_NORMAL_SANS:
7000 case PAN_SERIF_OBTUSE_SANS:
7001 case PAN_SERIF_PERP_SANS:
7002 case PAN_SERIF_FLARED:
7003 case PAN_SERIF_ROUNDED:
7004 TM.tmPitchAndFamily |= FF_SWISS;
7005 break;
7008 break;
7011 if(FT_IS_SCALABLE(ft_face))
7012 TM.tmPitchAndFamily |= TMPF_VECTOR;
7014 if(FT_IS_SFNT(ft_face))
7016 if (font->ntmFlags & NTM_PS_OPENTYPE)
7017 TM.tmPitchAndFamily |= TMPF_DEVICE;
7018 else
7019 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7022 TM.tmCharSet = font->charset;
7024 font->potm->otmFiller = 0;
7025 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7026 font->potm->otmfsSelection = pOS2->fsSelection;
7027 font->potm->otmfsType = pOS2->fsType;
7028 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7029 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7030 font->potm->otmItalicAngle = 0; /* POST table */
7031 font->potm->otmEMSquare = ft_face->units_per_EM;
7032 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
7033 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
7034 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
7035 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
7036 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
7037 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
7038 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
7039 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
7040 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
7041 font->potm->otmMacAscent = TM.tmAscent;
7042 font->potm->otmMacDescent = -TM.tmDescent;
7043 font->potm->otmMacLineGap = font->potm->otmLineGap;
7044 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7045 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
7046 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
7047 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
7048 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
7049 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
7050 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
7051 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
7052 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
7053 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
7054 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
7055 if(!pPost) {
7056 font->potm->otmsUnderscoreSize = 0;
7057 font->potm->otmsUnderscorePosition = 0;
7058 } else {
7059 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
7060 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
7062 #undef TM
7064 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7065 cp = (char*)font->potm + sizeof(*font->potm);
7066 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7067 strcpyW((WCHAR*)cp, family_nameW);
7068 cp += lenfam;
7069 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7070 strcpyW((WCHAR*)cp, style_nameW);
7071 cp += lensty;
7072 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7073 strcpyW((WCHAR*)cp, face_nameW);
7074 cp += lenface;
7075 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7076 strcpyW((WCHAR*)cp, full_nameW);
7077 ret = TRUE;
7079 end:
7080 HeapFree(GetProcessHeap(), 0, style_nameW);
7081 HeapFree(GetProcessHeap(), 0, family_nameW);
7082 HeapFree(GetProcessHeap(), 0, face_nameW);
7083 HeapFree(GetProcessHeap(), 0, full_nameW);
7084 return ret;
7087 /*************************************************************
7088 * freetype_GetGlyphOutline
7090 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7091 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7093 struct freetype_physdev *physdev = get_freetype_dev( dev );
7094 DWORD ret;
7095 ABC abc;
7097 if (!physdev->font)
7099 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7100 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7103 GDI_CheckNotLock();
7104 EnterCriticalSection( &freetype_cs );
7105 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7106 LeaveCriticalSection( &freetype_cs );
7107 return ret;
7110 /*************************************************************
7111 * freetype_GetTextMetrics
7113 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7115 struct freetype_physdev *physdev = get_freetype_dev( dev );
7116 BOOL ret;
7118 if (!physdev->font)
7120 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7121 return dev->funcs->pGetTextMetrics( dev, metrics );
7124 GDI_CheckNotLock();
7125 EnterCriticalSection( &freetype_cs );
7126 ret = get_text_metrics( physdev->font, metrics );
7127 LeaveCriticalSection( &freetype_cs );
7128 return ret;
7131 /*************************************************************
7132 * freetype_GetOutlineTextMetrics
7134 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7136 struct freetype_physdev *physdev = get_freetype_dev( dev );
7137 UINT ret = 0;
7139 if (!physdev->font)
7141 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7142 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7145 TRACE("font=%p\n", physdev->font);
7147 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7149 GDI_CheckNotLock();
7150 EnterCriticalSection( &freetype_cs );
7152 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7154 if(cbSize >= physdev->font->potm->otmSize)
7156 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7157 scale_outline_font_metrics(physdev->font, potm);
7159 ret = physdev->font->potm->otmSize;
7161 LeaveCriticalSection( &freetype_cs );
7162 return ret;
7165 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7167 child->font = alloc_font();
7168 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7169 if(!child->font->ft_face)
7171 free_font(child->font);
7172 child->font = NULL;
7173 return FALSE;
7176 child->font->font_desc = font->font_desc;
7177 child->font->ntmFlags = child->face->ntmFlags;
7178 child->font->orientation = font->orientation;
7179 child->font->scale_y = font->scale_y;
7180 child->font->name = strdupW(child->face->family->FamilyName);
7181 child->font->base_font = font;
7182 TRACE("created child font %p for base %p\n", child->font, font);
7183 return TRUE;
7186 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7188 FT_UInt g;
7189 CHILD_FONT *child_font;
7191 if(font->base_font)
7192 font = font->base_font;
7194 *linked_font = font;
7196 if((*glyph = get_glyph_index(font, c)))
7198 *glyph = get_GSUB_vert_glyph(font, *glyph);
7199 return TRUE;
7202 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7204 if(!child_font->font)
7205 if(!load_child_font(font, child_font))
7206 continue;
7208 if(!child_font->font->ft_face)
7209 continue;
7210 g = get_glyph_index(child_font->font, c);
7211 g = get_GSUB_vert_glyph(child_font->font, g);
7212 if(g)
7214 *glyph = g;
7215 *linked_font = child_font->font;
7216 return TRUE;
7219 return FALSE;
7222 /*************************************************************
7223 * freetype_GetCharWidth
7225 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7227 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7228 UINT c;
7229 GLYPHMETRICS gm;
7230 ABC abc;
7231 struct freetype_physdev *physdev = get_freetype_dev( dev );
7233 if (!physdev->font)
7235 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7236 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7239 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7241 GDI_CheckNotLock();
7242 EnterCriticalSection( &freetype_cs );
7243 for(c = firstChar; c <= lastChar; c++) {
7244 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7245 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7247 LeaveCriticalSection( &freetype_cs );
7248 return TRUE;
7251 /*************************************************************
7252 * freetype_GetCharABCWidths
7254 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7256 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7257 UINT c;
7258 GLYPHMETRICS gm;
7259 struct freetype_physdev *physdev = get_freetype_dev( dev );
7261 if (!physdev->font)
7263 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7264 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7267 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7269 GDI_CheckNotLock();
7270 EnterCriticalSection( &freetype_cs );
7272 for(c = firstChar; c <= lastChar; c++, buffer++)
7273 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7275 LeaveCriticalSection( &freetype_cs );
7276 return TRUE;
7279 /*************************************************************
7280 * freetype_GetCharABCWidthsI
7282 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7284 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7285 UINT c;
7286 GLYPHMETRICS gm;
7287 struct freetype_physdev *physdev = get_freetype_dev( dev );
7289 if (!physdev->font)
7291 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7292 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7295 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7296 return FALSE;
7298 GDI_CheckNotLock();
7299 EnterCriticalSection( &freetype_cs );
7301 for(c = 0; c < count; c++, buffer++)
7302 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7303 &gm, buffer, 0, NULL, &identity );
7305 LeaveCriticalSection( &freetype_cs );
7306 return TRUE;
7309 /*************************************************************
7310 * freetype_GetTextExtentExPoint
7312 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7314 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7315 INT idx, pos;
7316 ABC abc;
7317 GLYPHMETRICS gm;
7318 struct freetype_physdev *physdev = get_freetype_dev( dev );
7320 if (!physdev->font)
7322 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7323 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7326 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7328 GDI_CheckNotLock();
7329 EnterCriticalSection( &freetype_cs );
7331 for (idx = pos = 0; idx < count; idx++)
7333 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7334 pos += abc.abcA + abc.abcB + abc.abcC;
7335 dxs[idx] = pos;
7338 LeaveCriticalSection( &freetype_cs );
7339 return TRUE;
7342 /*************************************************************
7343 * freetype_GetTextExtentExPointI
7345 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7347 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7348 INT idx, pos;
7349 ABC abc;
7350 GLYPHMETRICS gm;
7351 struct freetype_physdev *physdev = get_freetype_dev( dev );
7353 if (!physdev->font)
7355 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7356 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7359 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7361 GDI_CheckNotLock();
7362 EnterCriticalSection( &freetype_cs );
7364 for (idx = pos = 0; idx < count; idx++)
7366 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7367 &gm, &abc, 0, NULL, &identity );
7368 pos += abc.abcA + abc.abcB + abc.abcC;
7369 dxs[idx] = pos;
7372 LeaveCriticalSection( &freetype_cs );
7373 return TRUE;
7376 /*************************************************************
7377 * freetype_GetFontData
7379 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7381 struct freetype_physdev *physdev = get_freetype_dev( dev );
7383 if (!physdev->font)
7385 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7386 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7389 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7390 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7391 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7393 return get_font_data( physdev->font, table, offset, buf, cbData );
7396 /*************************************************************
7397 * freetype_GetTextFace
7399 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7401 INT n;
7402 struct freetype_physdev *physdev = get_freetype_dev( dev );
7404 if (!physdev->font)
7406 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7407 return dev->funcs->pGetTextFace( dev, count, str );
7410 n = strlenW(physdev->font->name) + 1;
7411 if (str)
7413 lstrcpynW(str, physdev->font->name, count);
7414 n = min(count, n);
7416 return n;
7419 /*************************************************************
7420 * freetype_GetTextCharsetInfo
7422 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7424 struct freetype_physdev *physdev = get_freetype_dev( dev );
7426 if (!physdev->font)
7428 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7429 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7431 if (fs) *fs = physdev->font->fs;
7432 return physdev->font->charset;
7435 /* Retrieve a list of supported Unicode ranges for a given font.
7436 * Can be called with NULL gs to calculate the buffer size. Returns
7437 * the number of ranges found.
7439 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7441 DWORD num_ranges = 0;
7443 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7445 FT_UInt glyph_code;
7446 FT_ULong char_code, char_code_prev;
7448 glyph_code = 0;
7449 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7451 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7452 face->num_glyphs, glyph_code, char_code);
7454 if (!glyph_code) return 0;
7456 if (gs)
7458 gs->ranges[0].wcLow = (USHORT)char_code;
7459 gs->ranges[0].cGlyphs = 0;
7460 gs->cGlyphsSupported = 0;
7463 num_ranges = 1;
7464 while (glyph_code)
7466 if (char_code < char_code_prev)
7468 ERR("expected increasing char code from FT_Get_Next_Char\n");
7469 return 0;
7471 if (char_code - char_code_prev > 1)
7473 num_ranges++;
7474 if (gs)
7476 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7477 gs->ranges[num_ranges - 1].cGlyphs = 1;
7478 gs->cGlyphsSupported++;
7481 else if (gs)
7483 gs->ranges[num_ranges - 1].cGlyphs++;
7484 gs->cGlyphsSupported++;
7486 char_code_prev = char_code;
7487 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7490 else
7491 FIXME("encoding %u not supported\n", face->charmap->encoding);
7493 return num_ranges;
7496 /*************************************************************
7497 * freetype_GetFontUnicodeRanges
7499 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7501 struct freetype_physdev *physdev = get_freetype_dev( dev );
7502 DWORD size, num_ranges;
7504 if (!physdev->font)
7506 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7507 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7510 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7511 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7512 if (glyphset)
7514 glyphset->cbThis = size;
7515 glyphset->cRanges = num_ranges;
7516 glyphset->flAccel = 0;
7518 return size;
7521 /*************************************************************
7522 * freetype_FontIsLinked
7524 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7526 struct freetype_physdev *physdev = get_freetype_dev( dev );
7527 BOOL ret;
7529 if (!physdev->font)
7531 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7532 return dev->funcs->pFontIsLinked( dev );
7535 GDI_CheckNotLock();
7536 EnterCriticalSection( &freetype_cs );
7537 ret = !list_empty(&physdev->font->child_fonts);
7538 LeaveCriticalSection( &freetype_cs );
7539 return ret;
7542 /*************************************************************************
7543 * GetRasterizerCaps (GDI32.@)
7545 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7547 lprs->nSize = sizeof(RASTERIZER_STATUS);
7548 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7549 lprs->nLanguageID = 0;
7550 return TRUE;
7553 /*************************************************************
7554 * freetype_GdiRealizationInfo
7556 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7558 struct freetype_physdev *physdev = get_freetype_dev( dev );
7559 realization_info_t *info = ptr;
7561 if (!physdev->font)
7563 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7564 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7567 FIXME("(%p, %p): stub!\n", physdev->font, info);
7569 info->flags = 1;
7570 if(FT_IS_SCALABLE(physdev->font->ft_face))
7571 info->flags |= 2;
7573 info->cache_num = physdev->font->cache_num;
7574 info->unknown2 = -1;
7575 return TRUE;
7578 /*************************************************************************
7579 * Kerning support for TrueType fonts
7581 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7583 struct TT_kern_table
7585 USHORT version;
7586 USHORT nTables;
7589 struct TT_kern_subtable
7591 USHORT version;
7592 USHORT length;
7593 union
7595 USHORT word;
7596 struct
7598 USHORT horizontal : 1;
7599 USHORT minimum : 1;
7600 USHORT cross_stream: 1;
7601 USHORT override : 1;
7602 USHORT reserved1 : 4;
7603 USHORT format : 8;
7604 } bits;
7605 } coverage;
7608 struct TT_format0_kern_subtable
7610 USHORT nPairs;
7611 USHORT searchRange;
7612 USHORT entrySelector;
7613 USHORT rangeShift;
7616 struct TT_kern_pair
7618 USHORT left;
7619 USHORT right;
7620 short value;
7623 static DWORD parse_format0_kern_subtable(GdiFont *font,
7624 const struct TT_format0_kern_subtable *tt_f0_ks,
7625 const USHORT *glyph_to_char,
7626 KERNINGPAIR *kern_pair, DWORD cPairs)
7628 USHORT i, nPairs;
7629 const struct TT_kern_pair *tt_kern_pair;
7631 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7633 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7635 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7636 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7637 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7639 if (!kern_pair || !cPairs)
7640 return nPairs;
7642 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7644 nPairs = min(nPairs, cPairs);
7646 for (i = 0; i < nPairs; i++)
7648 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7649 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7650 /* this algorithm appears to better match what Windows does */
7651 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7652 if (kern_pair->iKernAmount < 0)
7654 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7655 kern_pair->iKernAmount -= font->ppem;
7657 else if (kern_pair->iKernAmount > 0)
7659 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7660 kern_pair->iKernAmount += font->ppem;
7662 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7664 TRACE("left %u right %u value %d\n",
7665 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7667 kern_pair++;
7669 TRACE("copied %u entries\n", nPairs);
7670 return nPairs;
7673 /*************************************************************
7674 * freetype_GetKerningPairs
7676 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7678 DWORD length;
7679 void *buf;
7680 const struct TT_kern_table *tt_kern_table;
7681 const struct TT_kern_subtable *tt_kern_subtable;
7682 USHORT i, nTables;
7683 USHORT *glyph_to_char;
7684 GdiFont *font;
7685 struct freetype_physdev *physdev = get_freetype_dev( dev );
7687 if (!(font = physdev->font))
7689 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7690 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7693 GDI_CheckNotLock();
7694 EnterCriticalSection( &freetype_cs );
7695 if (font->total_kern_pairs != (DWORD)-1)
7697 if (cPairs && kern_pair)
7699 cPairs = min(cPairs, font->total_kern_pairs);
7700 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7702 else cPairs = font->total_kern_pairs;
7704 LeaveCriticalSection( &freetype_cs );
7705 return cPairs;
7708 font->total_kern_pairs = 0;
7710 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7712 if (length == GDI_ERROR)
7714 TRACE("no kerning data in the font\n");
7715 LeaveCriticalSection( &freetype_cs );
7716 return 0;
7719 buf = HeapAlloc(GetProcessHeap(), 0, length);
7720 if (!buf)
7722 WARN("Out of memory\n");
7723 LeaveCriticalSection( &freetype_cs );
7724 return 0;
7727 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7729 /* build a glyph index to char code map */
7730 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7731 if (!glyph_to_char)
7733 WARN("Out of memory allocating a glyph index to char code map\n");
7734 HeapFree(GetProcessHeap(), 0, buf);
7735 LeaveCriticalSection( &freetype_cs );
7736 return 0;
7739 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7741 FT_UInt glyph_code;
7742 FT_ULong char_code;
7744 glyph_code = 0;
7745 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7747 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7748 font->ft_face->num_glyphs, glyph_code, char_code);
7750 while (glyph_code)
7752 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7754 /* FIXME: This doesn't match what Windows does: it does some fancy
7755 * things with duplicate glyph index to char code mappings, while
7756 * we just avoid overriding existing entries.
7758 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7759 glyph_to_char[glyph_code] = (USHORT)char_code;
7761 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7764 else
7766 ULONG n;
7768 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7769 for (n = 0; n <= 65535; n++)
7770 glyph_to_char[n] = (USHORT)n;
7773 tt_kern_table = buf;
7774 nTables = GET_BE_WORD(tt_kern_table->nTables);
7775 TRACE("version %u, nTables %u\n",
7776 GET_BE_WORD(tt_kern_table->version), nTables);
7778 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7780 for (i = 0; i < nTables; i++)
7782 struct TT_kern_subtable tt_kern_subtable_copy;
7784 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7785 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7786 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7788 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7789 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7790 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7792 /* According to the TrueType specification this is the only format
7793 * that will be properly interpreted by Windows and OS/2
7795 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7797 DWORD new_chunk, old_total = font->total_kern_pairs;
7799 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7800 glyph_to_char, NULL, 0);
7801 font->total_kern_pairs += new_chunk;
7803 if (!font->kern_pairs)
7804 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7805 font->total_kern_pairs * sizeof(*font->kern_pairs));
7806 else
7807 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7808 font->total_kern_pairs * sizeof(*font->kern_pairs));
7810 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7811 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7813 else
7814 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7816 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7819 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7820 HeapFree(GetProcessHeap(), 0, buf);
7822 if (cPairs && kern_pair)
7824 cPairs = min(cPairs, font->total_kern_pairs);
7825 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7827 else cPairs = font->total_kern_pairs;
7829 LeaveCriticalSection( &freetype_cs );
7830 return cPairs;
7833 static const struct gdi_dc_funcs freetype_funcs =
7835 NULL, /* pAbortDoc */
7836 NULL, /* pAbortPath */
7837 NULL, /* pAlphaBlend */
7838 NULL, /* pAngleArc */
7839 NULL, /* pArc */
7840 NULL, /* pArcTo */
7841 NULL, /* pBeginPath */
7842 NULL, /* pBlendImage */
7843 NULL, /* pChord */
7844 NULL, /* pCloseFigure */
7845 NULL, /* pCreateCompatibleDC */
7846 freetype_CreateDC, /* pCreateDC */
7847 freetype_DeleteDC, /* pDeleteDC */
7848 NULL, /* pDeleteObject */
7849 NULL, /* pDeviceCapabilities */
7850 NULL, /* pEllipse */
7851 NULL, /* pEndDoc */
7852 NULL, /* pEndPage */
7853 NULL, /* pEndPath */
7854 freetype_EnumFonts, /* pEnumFonts */
7855 NULL, /* pEnumICMProfiles */
7856 NULL, /* pExcludeClipRect */
7857 NULL, /* pExtDeviceMode */
7858 NULL, /* pExtEscape */
7859 NULL, /* pExtFloodFill */
7860 NULL, /* pExtSelectClipRgn */
7861 NULL, /* pExtTextOut */
7862 NULL, /* pFillPath */
7863 NULL, /* pFillRgn */
7864 NULL, /* pFlattenPath */
7865 freetype_FontIsLinked, /* pFontIsLinked */
7866 NULL, /* pFrameRgn */
7867 NULL, /* pGdiComment */
7868 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7869 NULL, /* pGetBoundsRect */
7870 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7871 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7872 freetype_GetCharWidth, /* pGetCharWidth */
7873 NULL, /* pGetDeviceCaps */
7874 NULL, /* pGetDeviceGammaRamp */
7875 freetype_GetFontData, /* pGetFontData */
7876 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7877 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7878 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7879 NULL, /* pGetICMProfile */
7880 NULL, /* pGetImage */
7881 freetype_GetKerningPairs, /* pGetKerningPairs */
7882 NULL, /* pGetNearestColor */
7883 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7884 NULL, /* pGetPixel */
7885 NULL, /* pGetSystemPaletteEntries */
7886 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7887 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7888 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7889 freetype_GetTextFace, /* pGetTextFace */
7890 freetype_GetTextMetrics, /* pGetTextMetrics */
7891 NULL, /* pGradientFill */
7892 NULL, /* pIntersectClipRect */
7893 NULL, /* pInvertRgn */
7894 NULL, /* pLineTo */
7895 NULL, /* pModifyWorldTransform */
7896 NULL, /* pMoveTo */
7897 NULL, /* pOffsetClipRgn */
7898 NULL, /* pOffsetViewportOrg */
7899 NULL, /* pOffsetWindowOrg */
7900 NULL, /* pPaintRgn */
7901 NULL, /* pPatBlt */
7902 NULL, /* pPie */
7903 NULL, /* pPolyBezier */
7904 NULL, /* pPolyBezierTo */
7905 NULL, /* pPolyDraw */
7906 NULL, /* pPolyPolygon */
7907 NULL, /* pPolyPolyline */
7908 NULL, /* pPolygon */
7909 NULL, /* pPolyline */
7910 NULL, /* pPolylineTo */
7911 NULL, /* pPutImage */
7912 NULL, /* pRealizeDefaultPalette */
7913 NULL, /* pRealizePalette */
7914 NULL, /* pRectangle */
7915 NULL, /* pResetDC */
7916 NULL, /* pRestoreDC */
7917 NULL, /* pRoundRect */
7918 NULL, /* pSaveDC */
7919 NULL, /* pScaleViewportExt */
7920 NULL, /* pScaleWindowExt */
7921 NULL, /* pSelectBitmap */
7922 NULL, /* pSelectBrush */
7923 NULL, /* pSelectClipPath */
7924 freetype_SelectFont, /* pSelectFont */
7925 NULL, /* pSelectPalette */
7926 NULL, /* pSelectPen */
7927 NULL, /* pSetArcDirection */
7928 NULL, /* pSetBkColor */
7929 NULL, /* pSetBkMode */
7930 NULL, /* pSetDCBrushColor */
7931 NULL, /* pSetDCPenColor */
7932 NULL, /* pSetDIBColorTable */
7933 NULL, /* pSetDIBitsToDevice */
7934 NULL, /* pSetDeviceClipping */
7935 NULL, /* pSetDeviceGammaRamp */
7936 NULL, /* pSetLayout */
7937 NULL, /* pSetMapMode */
7938 NULL, /* pSetMapperFlags */
7939 NULL, /* pSetPixel */
7940 NULL, /* pSetPolyFillMode */
7941 NULL, /* pSetROP2 */
7942 NULL, /* pSetRelAbs */
7943 NULL, /* pSetStretchBltMode */
7944 NULL, /* pSetTextAlign */
7945 NULL, /* pSetTextCharacterExtra */
7946 NULL, /* pSetTextColor */
7947 NULL, /* pSetTextJustification */
7948 NULL, /* pSetViewportExt */
7949 NULL, /* pSetViewportOrg */
7950 NULL, /* pSetWindowExt */
7951 NULL, /* pSetWindowOrg */
7952 NULL, /* pSetWorldTransform */
7953 NULL, /* pStartDoc */
7954 NULL, /* pStartPage */
7955 NULL, /* pStretchBlt */
7956 NULL, /* pStretchDIBits */
7957 NULL, /* pStrokeAndFillPath */
7958 NULL, /* pStrokePath */
7959 NULL, /* pUnrealizePalette */
7960 NULL, /* pWidenPath */
7961 NULL, /* wine_get_wgl_driver */
7962 GDI_PRIORITY_FONT_DRV /* priority */
7965 #else /* HAVE_FREETYPE */
7967 /*************************************************************************/
7969 BOOL WineEngInit(void)
7971 return FALSE;
7974 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7976 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7977 return 1;
7980 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7982 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7983 return TRUE;
7986 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7988 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7989 return NULL;
7992 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7993 LPCWSTR font_file, LPCWSTR font_path )
7995 FIXME("stub\n");
7996 return FALSE;
7999 /*************************************************************************
8000 * GetRasterizerCaps (GDI32.@)
8002 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8004 lprs->nSize = sizeof(RASTERIZER_STATUS);
8005 lprs->wFlags = 0;
8006 lprs->nLanguageID = 0;
8007 return TRUE;
8010 #endif /* HAVE_FREETYPE */