gdi32: Prevent possible buffer overflows in get_glyph_outline.
[wine.git] / dlls / gdi32 / freetype.c
blobfec752aa91dca540359f1f9d4538bcf2b9f6cd73
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->file && face->dev == cursor->dev && face->ino == cursor->ino)
1309 cursor->refcount++;
1310 TRACE("Font %s already in list, refcount now %d\n",
1311 debugstr_w(face->file), cursor->refcount);
1312 return FALSE;
1314 if (face->font_version <= cursor->font_version)
1316 TRACE("Original font %s is newer so skipping %s\n",
1317 debugstr_w(cursor->file), debugstr_w(face->file));
1318 return FALSE;
1320 else
1322 TRACE("Replacing original %s with %s\n",
1323 debugstr_w(cursor->file), debugstr_w(face->file));
1324 list_add_before( &cursor->entry, &face->entry );
1325 face->family = family;
1326 family->refcount++;
1327 face->refcount++;
1328 release_face( cursor );
1329 return TRUE;
1332 else
1333 TRACE("Adding new %s\n", debugstr_w(face->file));
1335 if (style_order( face ) < style_order( cursor )) break;
1338 list_add_before( &cursor->entry, &face->entry );
1339 face->family = family;
1340 family->refcount++;
1341 face->refcount++;
1342 return TRUE;
1345 /****************************************************************
1346 * NB This function stores the ptrs to the strings to save copying.
1347 * Don't free them after calling.
1349 static Family *create_family( WCHAR *name, WCHAR *english_name )
1351 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1352 family->refcount = 1;
1353 family->FamilyName = name;
1354 family->EnglishName = english_name;
1355 list_init( &family->faces );
1356 family->replacement = &family->faces;
1357 list_add_tail( &font_list, &family->entry );
1359 return family;
1362 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1364 DWORD type, size = sizeof(DWORD);
1366 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1367 type != REG_DWORD || size != sizeof(DWORD))
1369 *data = 0;
1370 return ERROR_BAD_CONFIGURATION;
1372 return ERROR_SUCCESS;
1375 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1377 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1380 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1382 DWORD needed, strike_index = 0;
1383 HKEY hkey_strike;
1385 /* If we have a File Name key then this is a real font, not just the parent
1386 key of a bunch of non-scalable strikes */
1387 needed = buffer_size;
1388 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1390 Face *face;
1391 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1392 face->cached_enum_data = NULL;
1393 face->family = NULL;
1395 face->refcount = 1;
1396 face->file = strdupW( buffer );
1397 face->StyleName = strdupW(face_name);
1399 needed = buffer_size;
1400 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1401 face->FullName = strdupW( buffer );
1402 else
1403 face->FullName = NULL;
1405 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1406 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1407 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1408 reg_load_dword(hkey_face, face_flags_value, (DWORD*)&face->flags);
1410 needed = sizeof(face->fs);
1411 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1413 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1415 face->scalable = TRUE;
1416 memset(&face->size, 0, sizeof(face->size));
1418 else
1420 face->scalable = FALSE;
1421 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1422 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1423 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1424 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1425 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1427 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1428 face->size.height, face->size.width, face->size.size >> 6,
1429 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1432 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1433 face->fs.fsCsb[0], face->fs.fsCsb[1],
1434 face->fs.fsUsb[0], face->fs.fsUsb[1],
1435 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1437 if (insert_face_in_family_list(face, family))
1438 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1440 release_face( face );
1443 /* load bitmap strikes */
1445 needed = buffer_size;
1446 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1448 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1450 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1451 RegCloseKey(hkey_strike);
1453 needed = buffer_size;
1457 static void load_font_list_from_cache(HKEY hkey_font_cache)
1459 DWORD size, family_index = 0;
1460 Family *family;
1461 HKEY hkey_family;
1462 WCHAR buffer[4096];
1464 size = sizeof(buffer);
1465 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1467 WCHAR *english_family = NULL;
1468 WCHAR *family_name = strdupW( buffer );
1469 DWORD face_index = 0;
1471 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1472 TRACE("opened family key %s\n", debugstr_w(family_name));
1473 size = sizeof(buffer);
1474 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1475 english_family = strdupW( buffer );
1477 family = create_family(family_name, english_family);
1479 if(english_family)
1481 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1482 subst->from.name = strdupW(english_family);
1483 subst->from.charset = -1;
1484 subst->to.name = strdupW(family_name);
1485 subst->to.charset = -1;
1486 add_font_subst(&font_subst_list, subst, 0);
1489 size = sizeof(buffer);
1490 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1492 WCHAR *face_name = strdupW( buffer );
1493 HKEY hkey_face;
1495 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1497 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1498 RegCloseKey(hkey_face);
1500 HeapFree( GetProcessHeap(), 0, face_name );
1501 size = sizeof(buffer);
1503 RegCloseKey(hkey_family);
1504 release_family( family );
1505 size = sizeof(buffer);
1509 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1511 LONG ret;
1512 HKEY hkey_wine_fonts;
1514 /* We don't want to create the fonts key as volatile, so open this first */
1515 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1516 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1517 if(ret != ERROR_SUCCESS)
1519 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1520 return ret;
1523 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1524 KEY_ALL_ACCESS, NULL, hkey, disposition);
1525 RegCloseKey(hkey_wine_fonts);
1526 return ret;
1529 static void add_face_to_cache(Face *face)
1531 HKEY hkey_family, hkey_face;
1532 WCHAR *face_key_name;
1534 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1535 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1536 if(face->family->EnglishName)
1537 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1538 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1540 if(face->scalable)
1541 face_key_name = face->StyleName;
1542 else
1544 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1545 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1546 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1548 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1549 &hkey_face, NULL);
1550 if(!face->scalable)
1551 HeapFree(GetProcessHeap(), 0, face_key_name);
1553 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1554 (strlenW(face->file) + 1) * sizeof(WCHAR));
1555 if (face->FullName)
1556 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1557 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1559 reg_save_dword(hkey_face, face_index_value, face->face_index);
1560 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1561 reg_save_dword(hkey_face, face_version_value, face->font_version);
1562 if (face->flags) reg_save_dword(hkey_face, face_flags_value, face->flags);
1564 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1566 if(!face->scalable)
1568 reg_save_dword(hkey_face, face_height_value, face->size.height);
1569 reg_save_dword(hkey_face, face_width_value, face->size.width);
1570 reg_save_dword(hkey_face, face_size_value, face->size.size);
1571 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1572 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1573 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1575 RegCloseKey(hkey_face);
1576 RegCloseKey(hkey_family);
1579 static void remove_face_from_cache( Face *face )
1581 HKEY hkey_family;
1583 RegOpenKeyExW( hkey_font_cache, face->family->FamilyName, 0, KEY_ALL_ACCESS, &hkey_family );
1585 if (face->scalable)
1587 RegDeleteKeyW( hkey_family, face->StyleName );
1589 else
1591 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1592 WCHAR *face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1593 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1594 RegDeleteKeyW( hkey_family, face_key_name );
1595 HeapFree(GetProcessHeap(), 0, face_key_name);
1597 RegCloseKey(hkey_family);
1600 static WCHAR *prepend_at(WCHAR *family)
1602 WCHAR *str;
1604 if (!family)
1605 return NULL;
1607 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1608 str[0] = '@';
1609 strcpyW(str + 1, family);
1610 HeapFree(GetProcessHeap(), 0, family);
1611 return str;
1614 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1616 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1617 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1619 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1620 if (!*name)
1622 *name = *english;
1623 *english = NULL;
1625 else if (!strcmpiW( *name, *english ))
1627 HeapFree( GetProcessHeap(), 0, *english );
1628 *english = NULL;
1631 if (vertical)
1633 *name = prepend_at( *name );
1634 *english = prepend_at( *english );
1638 static Family *get_family( FT_Face ft_face, BOOL vertical )
1640 Family *family;
1641 WCHAR *name, *english_name;
1643 get_family_names( ft_face, &name, &english_name, vertical );
1645 family = find_family_from_name( name );
1647 if (!family)
1649 family = create_family( name, english_name );
1650 if (english_name)
1652 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1653 subst->from.name = strdupW( english_name );
1654 subst->from.charset = -1;
1655 subst->to.name = strdupW( name );
1656 subst->to.charset = -1;
1657 add_font_subst( &font_subst_list, subst, 0 );
1660 else
1662 HeapFree( GetProcessHeap(), 0, name );
1663 HeapFree( GetProcessHeap(), 0, english_name );
1664 family->refcount++;
1667 return family;
1670 static inline FT_Fixed get_font_version( FT_Face ft_face )
1672 FT_Fixed version = 0;
1673 TT_Header *header;
1675 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1676 if (header) version = header->Font_Revision;
1678 return version;
1681 static inline DWORD get_ntm_flags( FT_Face ft_face )
1683 DWORD flags = 0;
1684 FT_ULong table_size = 0;
1686 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1687 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1688 if (flags == 0) flags = NTM_REGULAR;
1690 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1691 flags |= NTM_PS_OPENTYPE;
1693 return flags;
1696 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1698 int internal_leading = 0;
1699 FT_WinFNT_HeaderRec winfnt_header;
1701 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1702 internal_leading = winfnt_header.internal_leading;
1704 return internal_leading;
1707 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1709 TT_OS2 *os2;
1710 FT_UInt dummy;
1711 CHARSETINFO csi;
1712 FT_WinFNT_HeaderRec winfnt_header;
1713 int i;
1715 memset( fs, 0, sizeof(*fs) );
1717 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1718 if (os2)
1720 fs->fsUsb[0] = os2->ulUnicodeRange1;
1721 fs->fsUsb[1] = os2->ulUnicodeRange2;
1722 fs->fsUsb[2] = os2->ulUnicodeRange3;
1723 fs->fsUsb[3] = os2->ulUnicodeRange4;
1725 if (os2->version == 0)
1727 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1728 fs->fsCsb[0] = FS_LATIN1;
1729 else
1730 fs->fsCsb[0] = FS_SYMBOL;
1732 else
1734 fs->fsCsb[0] = os2->ulCodePageRange1;
1735 fs->fsCsb[1] = os2->ulCodePageRange2;
1738 else
1740 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1742 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1743 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1744 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1745 *fs = csi.fs;
1749 if (fs->fsCsb[0] == 0)
1751 /* let's see if we can find any interesting cmaps */
1752 for (i = 0; i < ft_face->num_charmaps; i++)
1754 switch (ft_face->charmaps[i]->encoding)
1756 case FT_ENCODING_UNICODE:
1757 case FT_ENCODING_APPLE_ROMAN:
1758 fs->fsCsb[0] |= FS_LATIN1;
1759 break;
1760 case FT_ENCODING_MS_SYMBOL:
1761 fs->fsCsb[0] |= FS_SYMBOL;
1762 break;
1763 default:
1764 break;
1770 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1771 DWORD flags )
1773 struct stat st;
1774 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1775 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1777 face->refcount = 1;
1778 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1779 if (!face->StyleName)
1780 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1781 if (!face->StyleName)
1783 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1786 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1787 if (!face->FullName)
1788 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1789 if (flags & ADDFONT_VERTICAL_FONT)
1790 face->FullName = prepend_at( face->FullName );
1792 face->dev = 0;
1793 face->ino = 0;
1794 if (file)
1796 face->file = towstr( CP_UNIXCP, file );
1797 face->font_data_ptr = NULL;
1798 face->font_data_size = 0;
1799 if (!stat( file, &st ))
1801 face->dev = st.st_dev;
1802 face->ino = st.st_ino;
1805 else
1807 face->file = NULL;
1808 face->font_data_ptr = font_data_ptr;
1809 face->font_data_size = font_data_size;
1812 face->face_index = face_index;
1813 get_fontsig( ft_face, &face->fs );
1814 face->ntmFlags = get_ntm_flags( ft_face );
1815 face->font_version = get_font_version( ft_face );
1817 if (FT_IS_SCALABLE( ft_face ))
1819 memset( &face->size, 0, sizeof(face->size) );
1820 face->scalable = TRUE;
1822 else
1824 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1825 size->height, size->width, size->size >> 6,
1826 size->x_ppem >> 6, size->y_ppem >> 6);
1827 face->size.height = size->height;
1828 face->size.width = size->width;
1829 face->size.size = size->size;
1830 face->size.x_ppem = size->x_ppem;
1831 face->size.y_ppem = size->y_ppem;
1832 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1833 face->scalable = FALSE;
1836 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1837 face->flags = flags;
1838 face->family = NULL;
1839 face->cached_enum_data = NULL;
1841 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1842 face->fs.fsCsb[0], face->fs.fsCsb[1],
1843 face->fs.fsUsb[0], face->fs.fsUsb[1],
1844 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1846 return face;
1849 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1850 FT_Long face_index, DWORD flags )
1852 Face *face;
1853 Family *family;
1855 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags );
1856 family = get_family( ft_face, flags & ADDFONT_VERTICAL_FONT );
1857 if (insert_face_in_family_list( face, family ))
1859 if (flags & ADDFONT_ADD_TO_CACHE)
1860 add_face_to_cache( face );
1862 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1863 debugstr_w(face->StyleName));
1865 release_face( face );
1866 release_family( family );
1869 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1870 FT_Long face_index, BOOL allow_bitmap )
1872 FT_Error err;
1873 TT_OS2 *pOS2;
1874 FT_Face ft_face;
1876 if (file)
1878 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1879 err = pFT_New_Face(library, file, face_index, &ft_face);
1881 else
1883 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1884 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1887 if (err != 0)
1889 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1890 return NULL;
1893 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1894 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1896 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1897 goto fail;
1900 if (!FT_IS_SFNT( ft_face ))
1902 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1904 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1905 goto fail;
1908 else
1910 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1911 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1912 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1914 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1915 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1916 goto fail;
1919 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1920 we don't want to load these. */
1921 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1923 FT_ULong len = 0;
1925 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1927 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1928 goto fail;
1933 if (!ft_face->family_name || !ft_face->style_name)
1935 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1936 goto fail;
1939 return ft_face;
1940 fail:
1941 pFT_Done_Face( ft_face );
1942 return NULL;
1945 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1947 FT_Face ft_face;
1948 FT_Long face_index = 0, num_faces;
1949 INT ret = 0;
1951 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1952 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1954 #ifdef HAVE_CARBON_CARBON_H
1955 if(file)
1957 char **mac_list = expand_mac_font(file);
1958 if(mac_list)
1960 BOOL had_one = FALSE;
1961 char **cursor;
1962 for(cursor = mac_list; *cursor; cursor++)
1964 had_one = TRUE;
1965 AddFontToList(*cursor, NULL, 0, flags);
1966 HeapFree(GetProcessHeap(), 0, *cursor);
1968 HeapFree(GetProcessHeap(), 0, mac_list);
1969 if(had_one)
1970 return 1;
1973 #endif /* HAVE_CARBON_CARBON_H */
1975 do {
1976 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
1977 if (!ft_face) return 0;
1979 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1981 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1982 pFT_Done_Face(ft_face);
1983 return 0;
1986 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags);
1987 ++ret;
1989 if (FT_HAS_VERTICAL(ft_face))
1991 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index,
1992 flags | ADDFONT_VERTICAL_FONT);
1993 ++ret;
1996 num_faces = ft_face->num_faces;
1997 pFT_Done_Face(ft_face);
1998 } while(num_faces > ++face_index);
1999 return ret;
2002 static int remove_font_resource( const char *file, DWORD flags )
2004 Family *family, *family_next;
2005 Face *face, *face_next;
2006 struct stat st;
2007 int count = 0;
2009 if (stat( file, &st ) == -1) return 0;
2010 LIST_FOR_EACH_ENTRY_SAFE( family, family_next, &font_list, Family, entry )
2012 family->refcount++;
2013 LIST_FOR_EACH_ENTRY_SAFE( face, face_next, &family->faces, Face, entry )
2015 if (!face->file) continue;
2016 if (LOWORD(face->flags) != LOWORD(flags)) continue;
2017 if (st.st_dev == face->dev && st.st_ino == face->ino)
2019 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face->file), face->refcount );
2020 release_face( face );
2021 count++;
2024 release_family( family );
2026 return count;
2029 static void DumpFontList(void)
2031 Family *family;
2032 Face *face;
2034 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2035 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
2036 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2037 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
2038 if(!face->scalable)
2039 TRACE(" %d", face->size.height);
2040 TRACE("\n");
2043 return;
2046 /***********************************************************
2047 * The replacement list is a way to map an entire font
2048 * family onto another family. For example adding
2050 * [HKCU\Software\Wine\Fonts\Replacements]
2051 * "Wingdings"="Winedings"
2053 * would enumerate the Winedings font both as Winedings and
2054 * Wingdings. However if a real Wingdings font is present the
2055 * replacement does not take place.
2058 static void LoadReplaceList(void)
2060 HKEY hkey;
2061 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2062 LPWSTR value;
2063 LPVOID data;
2065 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2066 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2068 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2069 &valuelen, &datalen, NULL, NULL);
2071 valuelen++; /* returned value doesn't include room for '\0' */
2072 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2073 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2075 dlen = datalen;
2076 vlen = valuelen;
2077 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2078 &dlen) == ERROR_SUCCESS) {
2079 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2080 /* "NewName"="Oldname" */
2081 if(!find_family_from_any_name(value))
2083 Family * const family = find_family_from_any_name(data);
2084 if (family != NULL)
2086 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2087 if (new_family != NULL)
2089 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2090 new_family->FamilyName = strdupW(value);
2091 new_family->EnglishName = NULL;
2092 list_init(&new_family->faces);
2093 new_family->replacement = &family->faces;
2094 list_add_tail(&font_list, &new_family->entry);
2097 else
2099 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2102 else
2104 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2106 /* reset dlen and vlen */
2107 dlen = datalen;
2108 vlen = valuelen;
2110 HeapFree(GetProcessHeap(), 0, data);
2111 HeapFree(GetProcessHeap(), 0, value);
2112 RegCloseKey(hkey);
2116 static const WCHAR *font_links_list[] =
2118 Lucida_Sans_Unicode,
2119 Microsoft_Sans_Serif,
2120 Tahoma
2123 static const struct font_links_defaults_list
2125 /* Keyed off substitution for "MS Shell Dlg" */
2126 const WCHAR *shelldlg;
2127 /* Maximum of four substitutes, plus terminating NULL pointer */
2128 const WCHAR *substitutes[5];
2129 } font_links_defaults_list[] =
2131 /* Non East-Asian */
2132 { Tahoma, /* FIXME unverified ordering */
2133 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2135 /* Below lists are courtesy of
2136 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2138 /* Japanese */
2139 { MS_UI_Gothic,
2140 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2142 /* Chinese Simplified */
2143 { SimSun,
2144 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2146 /* Korean */
2147 { Gulim,
2148 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2150 /* Chinese Traditional */
2151 { PMingLiU,
2152 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2157 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2159 SYSTEM_LINKS *font_link;
2161 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2163 if(!strcmpiW(font_link->font_name, name))
2164 return font_link;
2167 return NULL;
2170 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2172 const WCHAR *value;
2173 int i;
2174 FontSubst *psub;
2175 Family *family;
2176 Face *face;
2177 const WCHAR *file;
2179 if (values)
2181 SYSTEM_LINKS *font_link;
2183 psub = get_font_subst(&font_subst_list, name, -1);
2184 /* Don't store fonts that are only substitutes for other fonts */
2185 if(psub)
2187 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2188 return;
2191 font_link = find_font_link(name);
2192 if (font_link == NULL)
2194 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2195 font_link->font_name = strdupW(name);
2196 list_init(&font_link->links);
2197 list_add_tail(&system_links, &font_link->entry);
2200 memset(&font_link->fs, 0, sizeof font_link->fs);
2201 for (i = 0; values[i] != NULL; i++)
2203 const struct list *face_list;
2204 CHILD_FONT *child_font;
2206 value = values[i];
2207 if (!strcmpiW(name,value))
2208 continue;
2209 psub = get_font_subst(&font_subst_list, value, -1);
2210 if(psub)
2211 value = psub->to.name;
2212 family = find_family_from_name(value);
2213 if (!family)
2214 continue;
2215 file = NULL;
2216 /* Use first extant filename for this Family */
2217 face_list = get_face_list_from_family(family);
2218 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2220 if (!face->file)
2221 continue;
2222 file = strrchrW(face->file, '/');
2223 if (!file)
2224 file = face->file;
2225 else
2226 file++;
2227 break;
2229 if (!file)
2230 continue;
2231 face = find_face_from_filename(file, value);
2232 if(!face)
2234 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2235 continue;
2238 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2239 child_font->face = face;
2240 child_font->font = NULL;
2241 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2242 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2243 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2244 child_font->face->face_index);
2245 list_add_tail(&font_link->links, &child_font->entry);
2247 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2253 /*************************************************************
2254 * init_system_links
2256 static BOOL init_system_links(void)
2258 HKEY hkey;
2259 BOOL ret = FALSE;
2260 DWORD type, max_val, max_data, val_len, data_len, index;
2261 WCHAR *value, *data;
2262 WCHAR *entry, *next;
2263 SYSTEM_LINKS *font_link, *system_font_link;
2264 CHILD_FONT *child_font;
2265 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2266 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2267 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2268 Face *face;
2269 FontSubst *psub;
2270 UINT i, j;
2272 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2274 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2275 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2276 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2277 val_len = max_val + 1;
2278 data_len = max_data;
2279 index = 0;
2280 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2282 psub = get_font_subst(&font_subst_list, value, -1);
2283 /* Don't store fonts that are only substitutes for other fonts */
2284 if(psub)
2286 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2287 goto next;
2289 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2290 font_link->font_name = strdupW(value);
2291 memset(&font_link->fs, 0, sizeof font_link->fs);
2292 list_init(&font_link->links);
2293 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2295 WCHAR *face_name;
2296 CHILD_FONT *child_font;
2298 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2300 next = entry + strlenW(entry) + 1;
2302 face_name = strchrW(entry, ',');
2303 if(face_name)
2305 *face_name++ = 0;
2306 while(isspaceW(*face_name))
2307 face_name++;
2309 psub = get_font_subst(&font_subst_list, face_name, -1);
2310 if(psub)
2311 face_name = psub->to.name;
2313 face = find_face_from_filename(entry, face_name);
2314 if(!face)
2316 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2317 continue;
2320 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2321 child_font->face = face;
2322 child_font->font = NULL;
2323 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2324 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2325 TRACE("Adding file %s index %ld\n",
2326 debugstr_w(child_font->face->file), child_font->face->face_index);
2327 list_add_tail(&font_link->links, &child_font->entry);
2329 list_add_tail(&system_links, &font_link->entry);
2330 next:
2331 val_len = max_val + 1;
2332 data_len = max_data;
2335 HeapFree(GetProcessHeap(), 0, value);
2336 HeapFree(GetProcessHeap(), 0, data);
2337 RegCloseKey(hkey);
2341 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2342 if (!psub) {
2343 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2344 goto skip_internal;
2347 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2349 const FontSubst *psub2;
2350 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2352 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2354 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2355 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2357 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2358 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2360 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2362 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2366 skip_internal:
2368 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2369 that Tahoma has */
2371 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2372 system_font_link->font_name = strdupW(System);
2373 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2374 list_init(&system_font_link->links);
2376 face = find_face_from_filename(tahoma_ttf, Tahoma);
2377 if(face)
2379 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2380 child_font->face = face;
2381 child_font->font = NULL;
2382 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2383 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2384 TRACE("Found Tahoma in %s index %ld\n",
2385 debugstr_w(child_font->face->file), child_font->face->face_index);
2386 list_add_tail(&system_font_link->links, &child_font->entry);
2388 font_link = find_font_link(Tahoma);
2389 if (font_link != NULL)
2391 CHILD_FONT *font_link_entry;
2392 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2394 CHILD_FONT *new_child;
2395 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2396 new_child->face = font_link_entry->face;
2397 new_child->font = NULL;
2398 new_child->face->refcount++;
2399 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2400 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2401 list_add_tail(&system_font_link->links, &new_child->entry);
2404 list_add_tail(&system_links, &system_font_link->entry);
2405 return ret;
2408 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2410 DIR *dir;
2411 struct dirent *dent;
2412 char path[MAX_PATH];
2414 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2416 dir = opendir(dirname);
2417 if(!dir) {
2418 WARN("Can't open directory %s\n", debugstr_a(dirname));
2419 return FALSE;
2421 while((dent = readdir(dir)) != NULL) {
2422 struct stat statbuf;
2424 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2425 continue;
2427 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2429 sprintf(path, "%s/%s", dirname, dent->d_name);
2431 if(stat(path, &statbuf) == -1)
2433 WARN("Can't stat %s\n", debugstr_a(path));
2434 continue;
2436 if(S_ISDIR(statbuf.st_mode))
2437 ReadFontDir(path, external_fonts);
2438 else
2440 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2441 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2442 AddFontToList(path, NULL, 0, addfont_flags);
2445 closedir(dir);
2446 return TRUE;
2449 #ifdef SONAME_LIBFONTCONFIG
2451 static BOOL fontconfig_enabled;
2453 static UINT parse_aa_pattern( FcPattern *pattern )
2455 FcBool antialias;
2456 int rgba;
2457 UINT aa_flags = 0;
2459 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2460 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2462 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2464 switch (rgba)
2466 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2467 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2468 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2469 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2470 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2473 return aa_flags;
2476 static void init_fontconfig(void)
2478 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2480 if (!fc_handle)
2482 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2483 return;
2486 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2487 LOAD_FUNCPTR(FcConfigSubstitute);
2488 LOAD_FUNCPTR(FcFontList);
2489 LOAD_FUNCPTR(FcFontSetDestroy);
2490 LOAD_FUNCPTR(FcInit);
2491 LOAD_FUNCPTR(FcObjectSetAdd);
2492 LOAD_FUNCPTR(FcObjectSetCreate);
2493 LOAD_FUNCPTR(FcObjectSetDestroy);
2494 LOAD_FUNCPTR(FcPatternCreate);
2495 LOAD_FUNCPTR(FcPatternDestroy);
2496 LOAD_FUNCPTR(FcPatternGetBool);
2497 LOAD_FUNCPTR(FcPatternGetInteger);
2498 LOAD_FUNCPTR(FcPatternGetString);
2499 #undef LOAD_FUNCPTR
2501 if (pFcInit())
2503 FcPattern *pattern = pFcPatternCreate();
2504 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2505 default_aa_flags = parse_aa_pattern( pattern );
2506 pFcPatternDestroy( pattern );
2507 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2508 fontconfig_enabled = TRUE;
2512 static void load_fontconfig_fonts(void)
2514 FcPattern *pat;
2515 FcObjectSet *os;
2516 FcFontSet *fontset;
2517 int i, len;
2518 char *file;
2519 const char *ext;
2521 if (!fontconfig_enabled) return;
2523 pat = pFcPatternCreate();
2524 os = pFcObjectSetCreate();
2525 pFcObjectSetAdd(os, FC_FILE);
2526 pFcObjectSetAdd(os, FC_SCALABLE);
2527 pFcObjectSetAdd(os, FC_ANTIALIAS);
2528 pFcObjectSetAdd(os, FC_RGBA);
2529 fontset = pFcFontList(NULL, pat, os);
2530 if(!fontset) return;
2531 for(i = 0; i < fontset->nfont; i++) {
2532 FcBool scalable;
2533 DWORD aa_flags;
2535 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2536 continue;
2538 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2540 /* We're just interested in OT/TT fonts for now, so this hack just
2541 picks up the scalable fonts without extensions .pf[ab] to save time
2542 loading every other font */
2544 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2546 TRACE("not scalable\n");
2547 continue;
2550 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2551 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2553 len = strlen( file );
2554 if(len < 4) continue;
2555 ext = &file[ len - 3 ];
2556 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2557 AddFontToList(file, NULL, 0,
2558 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2560 pFcFontSetDestroy(fontset);
2561 pFcObjectSetDestroy(os);
2562 pFcPatternDestroy(pat);
2565 #elif defined(HAVE_CARBON_CARBON_H)
2567 static void load_mac_font_callback(const void *value, void *context)
2569 CFStringRef pathStr = value;
2570 CFIndex len;
2571 char* path;
2573 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2574 path = HeapAlloc(GetProcessHeap(), 0, len);
2575 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2577 TRACE("font file %s\n", path);
2578 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2580 HeapFree(GetProcessHeap(), 0, path);
2583 static void load_mac_fonts(void)
2585 CFStringRef removeDupesKey;
2586 CFBooleanRef removeDupesValue;
2587 CFDictionaryRef options;
2588 CTFontCollectionRef col;
2589 CFArrayRef descs;
2590 CFMutableSetRef paths;
2591 CFIndex i;
2593 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2594 removeDupesValue = kCFBooleanTrue;
2595 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2596 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2597 col = CTFontCollectionCreateFromAvailableFonts(options);
2598 if (options) CFRelease(options);
2599 if (!col)
2601 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2602 return;
2605 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2606 CFRelease(col);
2607 if (!descs)
2609 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2610 return;
2613 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2614 if (!paths)
2616 WARN("CFSetCreateMutable failed\n");
2617 CFRelease(descs);
2618 return;
2621 for (i = 0; i < CFArrayGetCount(descs); i++)
2623 CTFontDescriptorRef desc;
2624 CTFontRef font;
2625 ATSFontRef atsFont;
2626 OSStatus status;
2627 FSRef fsref;
2628 CFURLRef url;
2629 CFStringRef ext;
2630 CFStringRef path;
2632 desc = CFArrayGetValueAtIndex(descs, i);
2634 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2635 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2636 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2637 if (!font) continue;
2639 atsFont = CTFontGetPlatformFont(font, NULL);
2640 if (!atsFont)
2642 CFRelease(font);
2643 continue;
2646 status = ATSFontGetFileReference(atsFont, &fsref);
2647 CFRelease(font);
2648 if (status != noErr) continue;
2650 url = CFURLCreateFromFSRef(NULL, &fsref);
2651 if (!url) continue;
2653 ext = CFURLCopyPathExtension(url);
2654 if (ext)
2656 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2657 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2658 CFRelease(ext);
2659 if (skip)
2661 CFRelease(url);
2662 continue;
2666 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2667 CFRelease(url);
2668 if (!path) continue;
2670 CFSetAddValue(paths, path);
2671 CFRelease(path);
2674 CFRelease(descs);
2676 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2677 CFRelease(paths);
2680 #endif
2682 static char *get_data_dir_path( LPCWSTR file )
2684 char *unix_name = NULL;
2685 const char *data_dir = wine_get_data_dir();
2687 if (!data_dir) data_dir = wine_get_build_dir();
2689 if (data_dir)
2691 INT len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2693 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2694 strcpy(unix_name, data_dir);
2695 strcat(unix_name, "/fonts/");
2697 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2699 return unix_name;
2702 static BOOL load_font_from_data_dir(LPCWSTR file)
2704 BOOL ret = FALSE;
2705 char *unix_name = get_data_dir_path( file );
2707 if (unix_name)
2709 EnterCriticalSection( &freetype_cs );
2710 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2711 LeaveCriticalSection( &freetype_cs );
2712 HeapFree(GetProcessHeap(), 0, unix_name);
2714 return ret;
2717 static char *get_winfonts_dir_path(LPCWSTR file)
2719 static const WCHAR slashW[] = {'\\','\0'};
2720 WCHAR windowsdir[MAX_PATH];
2722 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2723 strcatW(windowsdir, fontsW);
2724 strcatW(windowsdir, slashW);
2725 strcatW(windowsdir, file);
2726 return wine_get_unix_file_name( windowsdir );
2729 static void load_system_fonts(void)
2731 HKEY hkey;
2732 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2733 const WCHAR * const *value;
2734 DWORD dlen, type;
2735 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2736 char *unixname;
2738 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2739 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2740 strcatW(windowsdir, fontsW);
2741 for(value = SystemFontValues; *value; value++) {
2742 dlen = sizeof(data);
2743 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2744 type == REG_SZ) {
2745 BOOL added = FALSE;
2747 sprintfW(pathW, fmtW, windowsdir, data);
2748 if((unixname = wine_get_unix_file_name(pathW))) {
2749 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
2750 HeapFree(GetProcessHeap(), 0, unixname);
2752 if (!added)
2753 load_font_from_data_dir(data);
2756 RegCloseKey(hkey);
2760 /*************************************************************
2762 * This adds registry entries for any externally loaded fonts
2763 * (fonts from fontconfig or FontDirs). It also deletes entries
2764 * of no longer existing fonts.
2767 static void update_reg_entries(void)
2769 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2770 LPWSTR valueW;
2771 DWORD len;
2772 Family *family;
2773 Face *face;
2774 WCHAR *file, *path;
2775 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2777 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2778 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2779 ERR("Can't create Windows font reg key\n");
2780 goto end;
2783 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2784 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2785 ERR("Can't create Windows font reg key\n");
2786 goto end;
2789 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2790 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2791 ERR("Can't create external font reg key\n");
2792 goto end;
2795 /* enumerate the fonts and add external ones to the two keys */
2797 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2798 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2799 char *buffer;
2800 if (!(face->flags & ADDFONT_EXTERNAL_FONT)) continue;
2802 if(face->FullName)
2804 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2805 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2806 strcpyW(valueW, face->FullName);
2808 else
2810 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2811 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2812 strcpyW(valueW, family->FamilyName);
2815 buffer = strWtoA( CP_UNIXCP, face->file );
2816 path = wine_get_dos_file_name( buffer );
2817 HeapFree( GetProcessHeap(), 0, buffer );
2819 if (path)
2820 file = path;
2821 else if ((file = strrchrW(face->file, '/')))
2822 file++;
2823 else
2824 file = face->file;
2826 len = strlenW(file) + 1;
2827 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2828 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2829 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2831 HeapFree(GetProcessHeap(), 0, path);
2832 HeapFree(GetProcessHeap(), 0, valueW);
2835 end:
2836 if(external_key) RegCloseKey(external_key);
2837 if(win9x_key) RegCloseKey(win9x_key);
2838 if(winnt_key) RegCloseKey(winnt_key);
2839 return;
2842 static void delete_external_font_keys(void)
2844 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2845 DWORD dlen, vlen, datalen, valuelen, i, type;
2846 LPWSTR valueW;
2847 LPVOID data;
2849 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2850 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2851 ERR("Can't create Windows font reg key\n");
2852 goto end;
2855 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2856 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2857 ERR("Can't create Windows font reg key\n");
2858 goto end;
2861 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2862 ERR("Can't create external font reg key\n");
2863 goto end;
2866 /* Delete all external fonts added last time */
2868 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2869 &valuelen, &datalen, NULL, NULL);
2870 valuelen++; /* returned value doesn't include room for '\0' */
2871 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2872 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2874 dlen = datalen * sizeof(WCHAR);
2875 vlen = valuelen;
2876 i = 0;
2877 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2878 &dlen) == ERROR_SUCCESS) {
2880 RegDeleteValueW(winnt_key, valueW);
2881 RegDeleteValueW(win9x_key, valueW);
2882 /* reset dlen and vlen */
2883 dlen = datalen;
2884 vlen = valuelen;
2886 HeapFree(GetProcessHeap(), 0, data);
2887 HeapFree(GetProcessHeap(), 0, valueW);
2889 /* Delete the old external fonts key */
2890 RegCloseKey(external_key);
2891 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2893 end:
2894 if(win9x_key) RegCloseKey(win9x_key);
2895 if(winnt_key) RegCloseKey(winnt_key);
2898 /*************************************************************
2899 * WineEngAddFontResourceEx
2902 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2904 INT ret = 0;
2906 GDI_CheckNotLock();
2908 if (ft_handle) /* do it only if we have freetype up and running */
2910 char *unixname;
2912 EnterCriticalSection( &freetype_cs );
2914 if((unixname = wine_get_unix_file_name(file)))
2916 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
2918 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2919 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2920 HeapFree(GetProcessHeap(), 0, unixname);
2922 if (!ret && !strchrW(file, '\\')) {
2923 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2924 if ((unixname = get_winfonts_dir_path( file )))
2926 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2927 HeapFree(GetProcessHeap(), 0, unixname);
2929 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
2930 if (!ret && (unixname = get_data_dir_path( file )))
2932 ret = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2933 HeapFree(GetProcessHeap(), 0, unixname);
2937 LeaveCriticalSection( &freetype_cs );
2939 return ret;
2942 /*************************************************************
2943 * WineEngAddFontMemResourceEx
2946 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2948 GDI_CheckNotLock();
2950 if (ft_handle) /* do it only if we have freetype up and running */
2952 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2954 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2955 memcpy(pFontCopy, pbFont, cbFont);
2957 EnterCriticalSection( &freetype_cs );
2958 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE);
2959 LeaveCriticalSection( &freetype_cs );
2961 if (*pcFonts == 0)
2963 TRACE("AddFontToList failed\n");
2964 HeapFree(GetProcessHeap(), 0, pFontCopy);
2965 return 0;
2967 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2968 * For now return something unique but quite random
2970 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2971 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2974 *pcFonts = 0;
2975 return 0;
2978 /*************************************************************
2979 * WineEngRemoveFontResourceEx
2982 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2984 INT ret = 0;
2986 GDI_CheckNotLock();
2988 if (ft_handle) /* do it only if we have freetype up and running */
2990 char *unixname;
2992 EnterCriticalSection( &freetype_cs );
2994 if ((unixname = wine_get_unix_file_name(file)))
2996 DWORD addfont_flags = ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE;
2998 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2999 ret = remove_font_resource( unixname, addfont_flags );
3000 HeapFree(GetProcessHeap(), 0, unixname);
3002 if (!ret && !strchrW(file, '\\'))
3004 if ((unixname = get_winfonts_dir_path( file )))
3006 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3007 HeapFree(GetProcessHeap(), 0, unixname);
3009 if (!ret && (unixname = get_data_dir_path( file )))
3011 ret = remove_font_resource( unixname, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_RESOURCE );
3012 HeapFree(GetProcessHeap(), 0, unixname);
3016 LeaveCriticalSection( &freetype_cs );
3018 return ret;
3021 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
3023 WCHAR *fullname;
3024 char *unix_name;
3025 int file_len;
3027 if (!font_file) return NULL;
3029 file_len = strlenW( font_file );
3031 if (font_path && font_path[0])
3033 int path_len = strlenW( font_path );
3034 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
3035 if (!fullname) return NULL;
3036 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
3037 fullname[path_len] = '\\';
3038 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
3040 else
3042 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
3043 if (!len) return NULL;
3044 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
3045 if (!fullname) return NULL;
3046 GetFullPathNameW( font_file, len, fullname, NULL );
3049 unix_name = wine_get_unix_file_name( fullname );
3050 HeapFree( GetProcessHeap(), 0, fullname );
3051 return unix_name;
3054 #include <pshpack1.h>
3055 struct fontdir
3057 WORD num_of_resources;
3058 WORD res_id;
3059 WORD dfVersion;
3060 DWORD dfSize;
3061 CHAR dfCopyright[60];
3062 WORD dfType;
3063 WORD dfPoints;
3064 WORD dfVertRes;
3065 WORD dfHorizRes;
3066 WORD dfAscent;
3067 WORD dfInternalLeading;
3068 WORD dfExternalLeading;
3069 BYTE dfItalic;
3070 BYTE dfUnderline;
3071 BYTE dfStrikeOut;
3072 WORD dfWeight;
3073 BYTE dfCharSet;
3074 WORD dfPixWidth;
3075 WORD dfPixHeight;
3076 BYTE dfPitchAndFamily;
3077 WORD dfAvgWidth;
3078 WORD dfMaxWidth;
3079 BYTE dfFirstChar;
3080 BYTE dfLastChar;
3081 BYTE dfDefaultChar;
3082 BYTE dfBreakChar;
3083 WORD dfWidthBytes;
3084 DWORD dfDevice;
3085 DWORD dfFace;
3086 DWORD dfReserved;
3087 CHAR szFaceName[LF_FACESIZE];
3090 #include <poppack.h>
3092 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3093 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3095 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3097 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3098 Face *face;
3099 WCHAR *name, *english_name;
3100 ENUMLOGFONTEXW elf;
3101 NEWTEXTMETRICEXW ntm;
3102 DWORD type;
3104 if (!ft_face) return FALSE;
3105 face = create_face( ft_face, 0, unix_name, NULL, 0, 0 );
3106 get_family_names( ft_face, &name, &english_name, FALSE );
3107 pFT_Done_Face( ft_face );
3109 GetEnumStructs( face, name, &elf, &ntm, &type );
3110 release_face( face );
3111 HeapFree( GetProcessHeap(), 0, name );
3112 HeapFree( GetProcessHeap(), 0, english_name );
3114 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3116 memset( fd, 0, sizeof(*fd) );
3118 fd->num_of_resources = 1;
3119 fd->res_id = 0;
3120 fd->dfVersion = 0x200;
3121 fd->dfSize = sizeof(*fd);
3122 strcpy( fd->dfCopyright, "Wine fontdir" );
3123 fd->dfType = 0x4003; /* 0x0080 set if private */
3124 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3125 fd->dfVertRes = 72;
3126 fd->dfHorizRes = 72;
3127 fd->dfAscent = ntm.ntmTm.tmAscent;
3128 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3129 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3130 fd->dfItalic = ntm.ntmTm.tmItalic;
3131 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3132 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3133 fd->dfWeight = ntm.ntmTm.tmWeight;
3134 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3135 fd->dfPixWidth = 0;
3136 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3137 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3138 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3139 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3140 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3141 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3142 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3143 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3144 fd->dfWidthBytes = 0;
3145 fd->dfDevice = 0;
3146 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3147 fd->dfReserved = 0;
3148 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3150 return TRUE;
3153 #define NE_FFLAGS_LIBMODULE 0x8000
3154 #define NE_OSFLAGS_WINDOWS 0x02
3156 static const char dos_string[0x40] = "This is a TrueType resource file";
3157 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3159 #include <pshpack2.h>
3161 struct ne_typeinfo
3163 WORD type_id;
3164 WORD count;
3165 DWORD res;
3168 struct ne_nameinfo
3170 WORD off;
3171 WORD len;
3172 WORD flags;
3173 WORD id;
3174 DWORD res;
3177 struct rsrc_tab
3179 WORD align;
3180 struct ne_typeinfo fontdir_type;
3181 struct ne_nameinfo fontdir_name;
3182 struct ne_typeinfo scalable_type;
3183 struct ne_nameinfo scalable_name;
3184 WORD end_of_rsrc;
3185 BYTE fontdir_res_name[8];
3188 #include <poppack.h>
3190 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3192 BOOL ret = FALSE;
3193 HANDLE file;
3194 DWORD size, written;
3195 BYTE *ptr, *start;
3196 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3197 char *font_fileA, *last_part, *ext;
3198 IMAGE_DOS_HEADER dos;
3199 IMAGE_OS2_HEADER ne =
3201 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3202 0, 0, 0, 0, 0, 0,
3203 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3204 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3206 struct rsrc_tab rsrc_tab =
3209 { 0x8007, 1, 0 },
3210 { 0, 0, 0x0c50, 0x2c, 0 },
3211 { 0x80cc, 1, 0 },
3212 { 0, 0, 0x0c50, 0x8001, 0 },
3214 { 7,'F','O','N','T','D','I','R'}
3217 memset( &dos, 0, sizeof(dos) );
3218 dos.e_magic = IMAGE_DOS_SIGNATURE;
3219 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3221 /* import name is last part\0, resident name is last part without extension
3222 non-resident name is "FONTRES:" + lfFaceName */
3224 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3225 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3226 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3228 last_part = strrchr( font_fileA, '\\' );
3229 if (last_part) last_part++;
3230 else last_part = font_fileA;
3231 import_name_len = strlen( last_part ) + 1;
3233 ext = strchr( last_part, '.' );
3234 if (ext) res_name_len = ext - last_part;
3235 else res_name_len = import_name_len - 1;
3237 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3239 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3240 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3241 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3242 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3243 ne.ne_cbenttab = 2;
3244 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3246 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3247 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3248 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3249 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3251 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3252 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3254 if (!ptr)
3256 HeapFree( GetProcessHeap(), 0, font_fileA );
3257 return FALSE;
3260 memcpy( ptr, &dos, sizeof(dos) );
3261 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3262 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3264 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3265 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3267 ptr = start + dos.e_lfanew + ne.ne_restab;
3268 *ptr++ = res_name_len;
3269 memcpy( ptr, last_part, res_name_len );
3271 ptr = start + dos.e_lfanew + ne.ne_imptab;
3272 *ptr++ = import_name_len;
3273 memcpy( ptr, last_part, import_name_len );
3275 ptr = start + ne.ne_nrestab;
3276 *ptr++ = non_res_name_len;
3277 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3278 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3280 ptr = start + (rsrc_tab.scalable_name.off << 4);
3281 memcpy( ptr, font_fileA, font_file_len );
3283 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3284 memcpy( ptr, fontdir, fontdir->dfSize );
3286 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3287 if (file != INVALID_HANDLE_VALUE)
3289 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3290 ret = TRUE;
3291 CloseHandle( file );
3294 HeapFree( GetProcessHeap(), 0, start );
3295 HeapFree( GetProcessHeap(), 0, font_fileA );
3297 return ret;
3300 /*************************************************************
3301 * WineEngCreateScalableFontResource
3304 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3305 LPCWSTR font_file, LPCWSTR font_path )
3307 char *unix_name = get_ttf_file_name( font_file, font_path );
3308 struct fontdir fontdir;
3309 BOOL ret = FALSE;
3311 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3312 SetLastError( ERROR_INVALID_PARAMETER );
3313 else
3315 if (hidden) fontdir.dfType |= 0x80;
3316 ret = create_fot( resource, font_file, &fontdir );
3319 HeapFree( GetProcessHeap(), 0, unix_name );
3320 return ret;
3323 static const struct nls_update_font_list
3325 UINT ansi_cp, oem_cp;
3326 const char *oem, *fixed, *system;
3327 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3328 /* these are for font substitutes */
3329 const char *shelldlg, *tmsrmn;
3330 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3331 *helv_0, *tmsrmn_0;
3332 const struct subst
3334 const char *from, *to;
3335 } arial_0, courier_new_0, times_new_roman_0;
3336 } nls_update_font_list[] =
3338 /* Latin 1 (United States) */
3339 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3340 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3341 "Tahoma","Times New Roman",
3342 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3343 { 0 }, { 0 }, { 0 }
3345 /* Latin 1 (Multilingual) */
3346 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3347 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3348 "Tahoma","Times New Roman", /* FIXME unverified */
3349 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3350 { 0 }, { 0 }, { 0 }
3352 /* Eastern Europe */
3353 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3354 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3355 "Tahoma","Times New Roman", /* FIXME unverified */
3356 "Fixedsys,238", "System,238",
3357 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3358 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3359 { "Arial CE,0", "Arial,238" },
3360 { "Courier New CE,0", "Courier New,238" },
3361 { "Times New Roman CE,0", "Times New Roman,238" }
3363 /* Cyrillic */
3364 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3365 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3366 "Tahoma","Times New Roman", /* FIXME unverified */
3367 "Fixedsys,204", "System,204",
3368 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3369 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3370 { "Arial Cyr,0", "Arial,204" },
3371 { "Courier New Cyr,0", "Courier New,204" },
3372 { "Times New Roman Cyr,0", "Times New Roman,204" }
3374 /* Greek */
3375 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3376 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3377 "Tahoma","Times New Roman", /* FIXME unverified */
3378 "Fixedsys,161", "System,161",
3379 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3380 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3381 { "Arial Greek,0", "Arial,161" },
3382 { "Courier New Greek,0", "Courier New,161" },
3383 { "Times New Roman Greek,0", "Times New Roman,161" }
3385 /* Turkish */
3386 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3387 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3388 "Tahoma","Times New Roman", /* FIXME unverified */
3389 "Fixedsys,162", "System,162",
3390 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3391 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3392 { "Arial Tur,0", "Arial,162" },
3393 { "Courier New Tur,0", "Courier New,162" },
3394 { "Times New Roman Tur,0", "Times New Roman,162" }
3396 /* Hebrew */
3397 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3398 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3399 "Tahoma","Times New Roman", /* FIXME unverified */
3400 "Fixedsys,177", "System,177",
3401 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3402 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3403 { 0 }, { 0 }, { 0 }
3405 /* Arabic */
3406 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3407 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3408 "Tahoma","Times New Roman", /* FIXME unverified */
3409 "Fixedsys,178", "System,178",
3410 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3411 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3412 { 0 }, { 0 }, { 0 }
3414 /* Baltic */
3415 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3416 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3417 "Tahoma","Times New Roman", /* FIXME unverified */
3418 "Fixedsys,186", "System,186",
3419 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3420 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3421 { "Arial Baltic,0", "Arial,186" },
3422 { "Courier New Baltic,0", "Courier New,186" },
3423 { "Times New Roman Baltic,0", "Times New Roman,186" }
3425 /* Vietnamese */
3426 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3427 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3428 "Tahoma","Times New Roman", /* FIXME unverified */
3429 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3430 { 0 }, { 0 }, { 0 }
3432 /* Thai */
3433 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3434 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3435 "Tahoma","Times New Roman", /* FIXME unverified */
3436 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3437 { 0 }, { 0 }, { 0 }
3439 /* Japanese */
3440 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3441 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3442 "MS UI Gothic","MS Serif",
3443 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3444 { 0 }, { 0 }, { 0 }
3446 /* Chinese Simplified */
3447 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3448 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3449 "SimSun", "NSimSun",
3450 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3451 { 0 }, { 0 }, { 0 }
3453 /* Korean */
3454 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3455 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3456 "Gulim", "Batang",
3457 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3458 { 0 }, { 0 }, { 0 }
3460 /* Chinese Traditional */
3461 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3462 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3463 "PMingLiU", "MingLiU",
3464 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3465 { 0 }, { 0 }, { 0 }
3469 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3471 return ( ansi_cp == 932 /* CP932 for Japanese */
3472 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3473 || ansi_cp == 949 /* CP949 for Korean */
3474 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3477 static inline HKEY create_fonts_NT_registry_key(void)
3479 HKEY hkey = 0;
3481 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3482 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3483 return hkey;
3486 static inline HKEY create_fonts_9x_registry_key(void)
3488 HKEY hkey = 0;
3490 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3491 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3492 return hkey;
3495 static inline HKEY create_config_fonts_registry_key(void)
3497 HKEY hkey = 0;
3499 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3500 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3501 return hkey;
3504 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3506 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3508 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3509 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3510 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3511 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3514 static void set_value_key(HKEY hkey, const char *name, const char *value)
3516 if (value)
3517 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3518 else if (name)
3519 RegDeleteValueA(hkey, name);
3522 static void update_font_association_info(UINT current_ansi_codepage)
3524 static const char *font_assoc_reg_key = "System\\CurrentControlSet\\Control\\FontAssoc";
3525 static const char *assoc_charset_subkey = "Associated Charset";
3527 if (is_dbcs_ansi_cp(current_ansi_codepage))
3529 HKEY hkey;
3530 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
3532 HKEY hsubkey;
3533 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
3535 switch (current_ansi_codepage)
3537 case 932:
3538 set_value_key(hsubkey, "ANSI(00)", "NO");
3539 set_value_key(hsubkey, "OEM(FF)", "NO");
3540 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3541 break;
3542 case 936:
3543 case 949:
3544 case 950:
3545 set_value_key(hsubkey, "ANSI(00)", "YES");
3546 set_value_key(hsubkey, "OEM(FF)", "YES");
3547 set_value_key(hsubkey, "SYMBOL(02)", "NO");
3548 break;
3550 RegCloseKey(hsubkey);
3553 /* TODO: Associated DefaultFonts */
3555 RegCloseKey(hkey);
3558 else
3559 RegDeleteTreeA(HKEY_LOCAL_MACHINE, font_assoc_reg_key);
3562 static void update_font_info(void)
3564 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3565 char buf[40], cpbuf[40];
3566 DWORD len, type;
3567 HKEY hkey = 0;
3568 UINT i, ansi_cp = 0, oem_cp = 0;
3569 DWORD screen_dpi = 96, font_dpi = 0;
3570 BOOL done = FALSE;
3572 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3573 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3574 &hkey) == ERROR_SUCCESS)
3576 reg_load_dword(hkey, logpixels, &screen_dpi);
3577 RegCloseKey(hkey);
3580 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3581 return;
3583 reg_load_dword(hkey, logpixels, &font_dpi);
3585 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3586 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3587 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3588 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3589 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3591 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3592 if (is_dbcs_ansi_cp(ansi_cp))
3593 use_default_fallback = TRUE;
3595 buf[0] = 0;
3596 len = sizeof(buf);
3597 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3599 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3601 RegCloseKey(hkey);
3602 return;
3604 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3605 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3607 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3608 ansi_cp, oem_cp, screen_dpi);
3610 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3611 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3612 RegCloseKey(hkey);
3614 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3616 HKEY hkey;
3618 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3619 nls_update_font_list[i].oem_cp == oem_cp)
3621 hkey = create_config_fonts_registry_key();
3622 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3623 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3624 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3625 RegCloseKey(hkey);
3627 hkey = create_fonts_NT_registry_key();
3628 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3629 RegCloseKey(hkey);
3631 hkey = create_fonts_9x_registry_key();
3632 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3633 RegCloseKey(hkey);
3635 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3637 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3638 strlen(nls_update_font_list[i].shelldlg)+1);
3639 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3640 strlen(nls_update_font_list[i].tmsrmn)+1);
3642 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3643 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3644 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3645 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3646 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3647 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3648 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3649 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3651 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3652 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3653 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3655 RegCloseKey(hkey);
3657 done = TRUE;
3659 else
3661 /* Delete the FontSubstitutes from other locales */
3662 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3664 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3665 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3666 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3667 RegCloseKey(hkey);
3671 if (!done)
3672 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3674 /* update locale dependent font association info in registry.
3675 update only when codepages changed, not logpixels. */
3676 if (strcmp(buf, cpbuf) != 0)
3677 update_font_association_info(ansi_cp);
3680 static BOOL init_freetype(void)
3682 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3683 if(!ft_handle) {
3684 WINE_MESSAGE(
3685 "Wine cannot find the FreeType font library. To enable Wine to\n"
3686 "use TrueType fonts please install a version of FreeType greater than\n"
3687 "or equal to 2.0.5.\n"
3688 "http://www.freetype.org\n");
3689 return FALSE;
3692 #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;}
3694 LOAD_FUNCPTR(FT_Done_Face)
3695 LOAD_FUNCPTR(FT_Get_Char_Index)
3696 LOAD_FUNCPTR(FT_Get_First_Char)
3697 LOAD_FUNCPTR(FT_Get_Module)
3698 LOAD_FUNCPTR(FT_Get_Next_Char)
3699 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3700 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3701 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3702 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3703 LOAD_FUNCPTR(FT_Init_FreeType)
3704 LOAD_FUNCPTR(FT_Library_Version)
3705 LOAD_FUNCPTR(FT_Load_Glyph)
3706 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3707 LOAD_FUNCPTR(FT_Matrix_Multiply)
3708 #ifndef FT_MULFIX_INLINED
3709 LOAD_FUNCPTR(FT_MulFix)
3710 #endif
3711 LOAD_FUNCPTR(FT_New_Face)
3712 LOAD_FUNCPTR(FT_New_Memory_Face)
3713 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3714 LOAD_FUNCPTR(FT_Outline_Transform)
3715 LOAD_FUNCPTR(FT_Outline_Translate)
3716 LOAD_FUNCPTR(FT_Render_Glyph)
3717 LOAD_FUNCPTR(FT_Select_Charmap)
3718 LOAD_FUNCPTR(FT_Set_Charmap)
3719 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3720 LOAD_FUNCPTR(FT_Vector_Transform)
3721 LOAD_FUNCPTR(FT_Vector_Unit)
3722 #undef LOAD_FUNCPTR
3723 /* Don't warn if these ones are missing */
3724 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3725 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3726 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3727 #endif
3729 if(pFT_Init_FreeType(&library) != 0) {
3730 ERR("Can't init FreeType library\n");
3731 wine_dlclose(ft_handle, NULL, 0);
3732 ft_handle = NULL;
3733 return FALSE;
3735 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3737 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3738 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3739 ((FT_Version.minor << 8) & 0x00ff00) |
3740 ((FT_Version.patch ) & 0x0000ff);
3742 font_driver = &freetype_funcs;
3743 return TRUE;
3745 sym_not_found:
3746 WINE_MESSAGE(
3747 "Wine cannot find certain functions that it needs inside the FreeType\n"
3748 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3749 "FreeType to at least version 2.1.4.\n"
3750 "http://www.freetype.org\n");
3751 wine_dlclose(ft_handle, NULL, 0);
3752 ft_handle = NULL;
3753 return FALSE;
3756 static void init_font_list(void)
3758 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3759 static const WCHAR pathW[] = {'P','a','t','h',0};
3760 HKEY hkey;
3761 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3762 WCHAR windowsdir[MAX_PATH];
3763 char *unixname;
3764 const char *data_dir;
3766 delete_external_font_keys();
3768 /* load the system bitmap fonts */
3769 load_system_fonts();
3771 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3772 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3773 strcatW(windowsdir, fontsW);
3774 if((unixname = wine_get_unix_file_name(windowsdir)))
3776 ReadFontDir(unixname, FALSE);
3777 HeapFree(GetProcessHeap(), 0, unixname);
3780 /* load the system truetype fonts */
3781 data_dir = wine_get_data_dir();
3782 if (!data_dir) data_dir = wine_get_build_dir();
3783 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3785 strcpy(unixname, data_dir);
3786 strcat(unixname, "/fonts/");
3787 ReadFontDir(unixname, TRUE);
3788 HeapFree(GetProcessHeap(), 0, unixname);
3791 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3792 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3793 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3794 will skip these. */
3795 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3796 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3797 &hkey) == ERROR_SUCCESS)
3799 LPWSTR data, valueW;
3800 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3801 &valuelen, &datalen, NULL, NULL);
3803 valuelen++; /* returned value doesn't include room for '\0' */
3804 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3805 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3806 if (valueW && data)
3808 dlen = datalen * sizeof(WCHAR);
3809 vlen = valuelen;
3810 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3811 &dlen) == ERROR_SUCCESS)
3813 if(data[0] && (data[1] == ':'))
3815 if((unixname = wine_get_unix_file_name(data)))
3817 AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3818 HeapFree(GetProcessHeap(), 0, unixname);
3821 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3823 WCHAR pathW[MAX_PATH];
3824 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3825 BOOL added = FALSE;
3827 sprintfW(pathW, fmtW, windowsdir, data);
3828 if((unixname = wine_get_unix_file_name(pathW)))
3830 added = AddFontToList(unixname, NULL, 0, ADDFONT_ALLOW_BITMAP | ADDFONT_ADD_TO_CACHE);
3831 HeapFree(GetProcessHeap(), 0, unixname);
3833 if (!added)
3834 load_font_from_data_dir(data);
3836 /* reset dlen and vlen */
3837 dlen = datalen;
3838 vlen = valuelen;
3841 HeapFree(GetProcessHeap(), 0, data);
3842 HeapFree(GetProcessHeap(), 0, valueW);
3843 RegCloseKey(hkey);
3846 #ifdef SONAME_LIBFONTCONFIG
3847 load_fontconfig_fonts();
3848 #elif defined(HAVE_CARBON_CARBON_H)
3849 load_mac_fonts();
3850 #endif
3852 /* then look in any directories that we've specified in the config file */
3853 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3854 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3856 DWORD len;
3857 LPWSTR valueW;
3858 LPSTR valueA, ptr;
3860 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3862 len += sizeof(WCHAR);
3863 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3864 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3866 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3867 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3868 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3869 TRACE( "got font path %s\n", debugstr_a(valueA) );
3870 ptr = valueA;
3871 while (ptr)
3873 const char* home;
3874 LPSTR next = strchr( ptr, ':' );
3875 if (next) *next++ = 0;
3876 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3877 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3879 strcpy( unixname, home );
3880 strcat( unixname, ptr + 1 );
3881 ReadFontDir( unixname, TRUE );
3882 HeapFree( GetProcessHeap(), 0, unixname );
3884 else
3885 ReadFontDir( ptr, TRUE );
3886 ptr = next;
3888 HeapFree( GetProcessHeap(), 0, valueA );
3890 HeapFree( GetProcessHeap(), 0, valueW );
3892 RegCloseKey(hkey);
3896 static BOOL move_to_front(const WCHAR *name)
3898 Family *family, *cursor2;
3899 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3901 if(!strcmpiW(family->FamilyName, name))
3903 list_remove(&family->entry);
3904 list_add_head(&font_list, &family->entry);
3905 return TRUE;
3908 return FALSE;
3911 static BOOL set_default(const WCHAR **name_list)
3913 while (*name_list)
3915 if (move_to_front(*name_list)) return TRUE;
3916 name_list++;
3919 return FALSE;
3922 static void reorder_font_list(void)
3924 set_default( default_serif_list );
3925 set_default( default_fixed_list );
3926 set_default( default_sans_list );
3929 /*************************************************************
3930 * WineEngInit
3932 * Initialize FreeType library and create a list of available faces
3934 BOOL WineEngInit(void)
3936 DWORD disposition;
3937 HANDLE font_mutex;
3939 /* update locale dependent font info in registry */
3940 update_font_info();
3942 if(!init_freetype()) return FALSE;
3944 #ifdef SONAME_LIBFONTCONFIG
3945 init_fontconfig();
3946 #endif
3948 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3950 ERR("Failed to create font mutex\n");
3951 return FALSE;
3953 WaitForSingleObject(font_mutex, INFINITE);
3955 create_font_cache_key(&hkey_font_cache, &disposition);
3957 if(disposition == REG_CREATED_NEW_KEY)
3958 init_font_list();
3959 else
3960 load_font_list_from_cache(hkey_font_cache);
3962 reorder_font_list();
3964 DumpFontList();
3965 LoadSubstList();
3966 DumpSubstList();
3967 LoadReplaceList();
3969 if(disposition == REG_CREATED_NEW_KEY)
3970 update_reg_entries();
3972 init_system_links();
3974 ReleaseMutex(font_mutex);
3975 return TRUE;
3979 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3981 TT_OS2 *pOS2;
3982 TT_HoriHeader *pHori;
3984 LONG ppem;
3986 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3987 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3989 if(height == 0) height = 16;
3991 /* Calc. height of EM square:
3993 * For +ve lfHeight we have
3994 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3995 * Re-arranging gives:
3996 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3998 * For -ve lfHeight we have
3999 * |lfHeight| = ppem
4000 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4001 * with il = winAscent + winDescent - units_per_em]
4005 if(height > 0) {
4006 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
4007 ppem = MulDiv(ft_face->units_per_EM, height,
4008 pHori->Ascender - pHori->Descender);
4009 else
4010 ppem = MulDiv(ft_face->units_per_EM, height,
4011 pOS2->usWinAscent + pOS2->usWinDescent);
4013 else
4014 ppem = -height;
4016 return ppem;
4019 static struct font_mapping *map_font_file( const char *name )
4021 struct font_mapping *mapping;
4022 struct stat st;
4023 int fd;
4025 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
4026 if (fstat( fd, &st ) == -1) goto error;
4028 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
4030 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
4032 mapping->refcount++;
4033 close( fd );
4034 return mapping;
4037 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
4038 goto error;
4040 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
4041 close( fd );
4043 if (mapping->data == MAP_FAILED)
4045 HeapFree( GetProcessHeap(), 0, mapping );
4046 return NULL;
4048 mapping->refcount = 1;
4049 mapping->dev = st.st_dev;
4050 mapping->ino = st.st_ino;
4051 mapping->size = st.st_size;
4052 list_add_tail( &mappings_list, &mapping->entry );
4053 return mapping;
4055 error:
4056 close( fd );
4057 return NULL;
4060 static void unmap_font_file( struct font_mapping *mapping )
4062 if (!--mapping->refcount)
4064 list_remove( &mapping->entry );
4065 munmap( mapping->data, mapping->size );
4066 HeapFree( GetProcessHeap(), 0, mapping );
4070 static LONG load_VDMX(GdiFont*, LONG);
4072 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
4074 FT_Error err;
4075 FT_Face ft_face;
4076 void *data_ptr;
4077 DWORD data_size;
4079 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
4081 if (face->file)
4083 char *filename = strWtoA( CP_UNIXCP, face->file );
4084 font->mapping = map_font_file( filename );
4085 HeapFree( GetProcessHeap(), 0, filename );
4086 if (!font->mapping)
4088 WARN("failed to map %s\n", debugstr_w(face->file));
4089 return 0;
4091 data_ptr = font->mapping->data;
4092 data_size = font->mapping->size;
4094 else
4096 data_ptr = face->font_data_ptr;
4097 data_size = face->font_data_size;
4100 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
4101 if(err) {
4102 ERR("FT_New_Face rets %d\n", err);
4103 return 0;
4106 /* set it here, as load_VDMX needs it */
4107 font->ft_face = ft_face;
4109 if(FT_IS_SCALABLE(ft_face)) {
4110 /* load the VDMX table if we have one */
4111 font->ppem = load_VDMX(font, height);
4112 if(font->ppem == 0)
4113 font->ppem = calc_ppem_for_height(ft_face, height);
4114 TRACE("height %d => ppem %d\n", height, font->ppem);
4116 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
4117 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
4118 } else {
4119 font->ppem = height;
4120 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
4121 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
4123 return ft_face;
4127 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
4129 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4130 a single face with the requested charset. The idea is to check if
4131 the selected font supports the current ANSI codepage, if it does
4132 return the corresponding charset, else return the first charset */
4134 CHARSETINFO csi;
4135 int acp = GetACP(), i;
4136 DWORD fs0;
4138 *cp = acp;
4139 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4141 const SYSTEM_LINKS *font_link;
4143 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4144 return csi.ciCharset;
4146 font_link = find_font_link(family_name);
4147 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4148 return csi.ciCharset;
4151 for(i = 0; i < 32; i++) {
4152 fs0 = 1L << i;
4153 if(face->fs.fsCsb[0] & fs0) {
4154 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4155 *cp = csi.ciACP;
4156 return csi.ciCharset;
4158 else
4159 FIXME("TCI failing on %x\n", fs0);
4163 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4164 face->fs.fsCsb[0], debugstr_w(face->file));
4165 *cp = acp;
4166 return DEFAULT_CHARSET;
4169 static GdiFont *alloc_font(void)
4171 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4172 ret->refcount = 1;
4173 ret->gmsize = 1;
4174 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4175 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4176 ret->potm = NULL;
4177 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4178 ret->total_kern_pairs = (DWORD)-1;
4179 ret->kern_pairs = NULL;
4180 list_init(&ret->child_fonts);
4181 return ret;
4184 static void free_font(GdiFont *font)
4186 CHILD_FONT *child, *child_next;
4187 DWORD i;
4189 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4191 list_remove(&child->entry);
4192 if(child->font)
4193 free_font(child->font);
4194 release_face( child->face );
4195 HeapFree(GetProcessHeap(), 0, child);
4198 if (font->ft_face) pFT_Done_Face(font->ft_face);
4199 if (font->mapping) unmap_font_file( font->mapping );
4200 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4201 HeapFree(GetProcessHeap(), 0, font->potm);
4202 HeapFree(GetProcessHeap(), 0, font->name);
4203 for (i = 0; i < font->gmsize; i++)
4204 HeapFree(GetProcessHeap(),0,font->gm[i]);
4205 HeapFree(GetProcessHeap(), 0, font->gm);
4206 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4207 HeapFree(GetProcessHeap(), 0, font);
4211 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4213 FT_Face ft_face = font->ft_face;
4214 FT_ULong len;
4215 FT_Error err;
4217 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4219 if(!buf)
4220 len = 0;
4221 else
4222 len = cbData;
4224 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4226 /* make sure value of len is the value freetype says it needs */
4227 if (buf && len)
4229 FT_ULong needed = 0;
4230 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4231 if( !err && needed < len) len = needed;
4233 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4234 if (err)
4236 TRACE("Can't find table %c%c%c%c\n",
4237 /* bytes were reversed */
4238 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4239 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4240 return GDI_ERROR;
4242 return len;
4245 /*************************************************************
4246 * load_VDMX
4248 * load the vdmx entry for the specified height
4251 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4252 ( ( (FT_ULong)_x4 << 24 ) | \
4253 ( (FT_ULong)_x3 << 16 ) | \
4254 ( (FT_ULong)_x2 << 8 ) | \
4255 (FT_ULong)_x1 )
4257 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4259 typedef struct {
4260 BYTE bCharSet;
4261 BYTE xRatio;
4262 BYTE yStartRatio;
4263 BYTE yEndRatio;
4264 } Ratios;
4266 typedef struct {
4267 WORD recs;
4268 BYTE startsz;
4269 BYTE endsz;
4270 } VDMX_group;
4272 static LONG load_VDMX(GdiFont *font, LONG height)
4274 WORD hdr[3], tmp;
4275 VDMX_group group;
4276 BYTE devXRatio, devYRatio;
4277 USHORT numRecs, numRatios;
4278 DWORD result, offset = -1;
4279 LONG ppem = 0;
4280 int i;
4282 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4284 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4285 return ppem;
4287 /* FIXME: need the real device aspect ratio */
4288 devXRatio = 1;
4289 devYRatio = 1;
4291 numRecs = GET_BE_WORD(hdr[1]);
4292 numRatios = GET_BE_WORD(hdr[2]);
4294 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4295 for(i = 0; i < numRatios; i++) {
4296 Ratios ratio;
4298 offset = (3 * 2) + (i * sizeof(Ratios));
4299 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4300 offset = -1;
4302 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4304 if((ratio.xRatio == 0 &&
4305 ratio.yStartRatio == 0 &&
4306 ratio.yEndRatio == 0) ||
4307 (devXRatio == ratio.xRatio &&
4308 devYRatio >= ratio.yStartRatio &&
4309 devYRatio <= ratio.yEndRatio))
4311 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4312 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4313 offset = GET_BE_WORD(tmp);
4314 break;
4318 if(offset == -1) {
4319 FIXME("No suitable ratio found\n");
4320 return ppem;
4323 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4324 USHORT recs;
4325 BYTE startsz, endsz;
4326 WORD *vTable;
4328 recs = GET_BE_WORD(group.recs);
4329 startsz = group.startsz;
4330 endsz = group.endsz;
4332 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4334 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4335 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4336 if(result == GDI_ERROR) {
4337 FIXME("Failed to retrieve vTable\n");
4338 goto end;
4341 if(height > 0) {
4342 for(i = 0; i < recs; i++) {
4343 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4344 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4345 ppem = GET_BE_WORD(vTable[i * 3]);
4347 if(yMax + -yMin == height) {
4348 font->yMax = yMax;
4349 font->yMin = yMin;
4350 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4351 break;
4353 if(yMax + -yMin > height) {
4354 if(--i < 0) {
4355 ppem = 0;
4356 goto end; /* failed */
4358 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4359 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4360 ppem = GET_BE_WORD(vTable[i * 3]);
4361 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4362 break;
4365 if(!font->yMax) {
4366 ppem = 0;
4367 TRACE("ppem not found for height %d\n", height);
4370 end:
4371 HeapFree(GetProcessHeap(), 0, vTable);
4374 return ppem;
4377 static void dump_gdi_font_list(void)
4379 GdiFont *font;
4381 TRACE("---------- Font Cache ----------\n");
4382 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4383 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4384 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4387 static void grab_font( GdiFont *font )
4389 if (!font->refcount++)
4391 list_remove( &font->unused_entry );
4392 unused_font_count--;
4396 static void release_font( GdiFont *font )
4398 if (!font) return;
4399 if (!--font->refcount)
4401 TRACE( "font %p\n", font );
4403 /* add it to the unused list */
4404 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4405 if (unused_font_count > UNUSED_CACHE_SIZE)
4407 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4408 TRACE( "freeing %p\n", font );
4409 list_remove( &font->entry );
4410 list_remove( &font->unused_entry );
4411 free_font( font );
4413 else unused_font_count++;
4415 if (TRACE_ON(font)) dump_gdi_font_list();
4419 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4421 if(font->font_desc.hash != fd->hash) return TRUE;
4422 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4423 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4424 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4425 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4428 static void calc_hash(FONT_DESC *pfd)
4430 DWORD hash = 0, *ptr, two_chars;
4431 WORD *pwc;
4432 unsigned int i;
4434 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4435 hash ^= *ptr;
4436 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4437 hash ^= *ptr;
4438 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4439 two_chars = *ptr;
4440 pwc = (WCHAR *)&two_chars;
4441 if(!*pwc) break;
4442 *pwc = toupperW(*pwc);
4443 pwc++;
4444 *pwc = toupperW(*pwc);
4445 hash ^= two_chars;
4446 if(!*pwc) break;
4448 hash ^= !pfd->can_use_bitmap;
4449 pfd->hash = hash;
4450 return;
4453 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4455 GdiFont *ret;
4456 FONT_DESC fd;
4458 fd.lf = *plf;
4459 fd.matrix = *pmat;
4460 fd.can_use_bitmap = can_use_bitmap;
4461 calc_hash(&fd);
4463 /* try the in-use list */
4464 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4466 if(fontcmp(ret, &fd)) continue;
4467 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4468 list_remove( &ret->entry );
4469 list_add_head( &gdi_font_list, &ret->entry );
4470 grab_font( ret );
4471 return ret;
4473 return NULL;
4476 static void add_to_cache(GdiFont *font)
4478 static DWORD cache_num = 1;
4480 font->cache_num = cache_num++;
4481 list_add_head(&gdi_font_list, &font->entry);
4482 TRACE( "font %p\n", font );
4485 /*************************************************************
4486 * create_child_font_list
4488 static BOOL create_child_font_list(GdiFont *font)
4490 BOOL ret = FALSE;
4491 SYSTEM_LINKS *font_link;
4492 CHILD_FONT *font_link_entry, *new_child;
4493 FontSubst *psub;
4494 WCHAR* font_name;
4496 psub = get_font_subst(&font_subst_list, font->name, -1);
4497 font_name = psub ? psub->to.name : font->name;
4498 font_link = find_font_link(font_name);
4499 if (font_link != NULL)
4501 TRACE("found entry in system list\n");
4502 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4504 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4505 new_child->face = font_link_entry->face;
4506 new_child->font = NULL;
4507 new_child->face->refcount++;
4508 list_add_tail(&font->child_fonts, &new_child->entry);
4509 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4511 ret = TRUE;
4514 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4515 * Sans Serif. This is how asian windows get default fallbacks for fonts
4517 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4518 font->charset != OEM_CHARSET &&
4519 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4521 font_link = find_font_link(szDefaultFallbackLink);
4522 if (font_link != NULL)
4524 TRACE("found entry in default fallback list\n");
4525 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4527 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4528 new_child->face = font_link_entry->face;
4529 new_child->font = NULL;
4530 new_child->face->refcount++;
4531 list_add_tail(&font->child_fonts, &new_child->entry);
4532 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4534 ret = TRUE;
4538 return ret;
4541 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4543 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4545 if (pFT_Set_Charmap)
4547 FT_Int i;
4548 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4550 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4552 for (i = 0; i < ft_face->num_charmaps; i++)
4554 if (ft_face->charmaps[i]->encoding == encoding)
4556 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4557 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4559 switch (ft_face->charmaps[i]->platform_id)
4561 default:
4562 cmap_def = ft_face->charmaps[i];
4563 break;
4564 case 0: /* Apple Unicode */
4565 cmap0 = ft_face->charmaps[i];
4566 break;
4567 case 1: /* Macintosh */
4568 cmap1 = ft_face->charmaps[i];
4569 break;
4570 case 2: /* ISO */
4571 cmap2 = ft_face->charmaps[i];
4572 break;
4573 case 3: /* Microsoft */
4574 cmap3 = ft_face->charmaps[i];
4575 break;
4579 if (cmap3) /* prefer Microsoft cmap table */
4580 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4581 else if (cmap1)
4582 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4583 else if (cmap2)
4584 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4585 else if (cmap0)
4586 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4587 else if (cmap_def)
4588 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4590 return ft_err == FT_Err_Ok;
4593 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4597 /*************************************************************
4598 * freetype_CreateDC
4600 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4601 LPCWSTR output, const DEVMODEW *devmode )
4603 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4605 if (!physdev) return FALSE;
4606 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4607 return TRUE;
4611 /*************************************************************
4612 * freetype_DeleteDC
4614 static BOOL freetype_DeleteDC( PHYSDEV dev )
4616 struct freetype_physdev *physdev = get_freetype_dev( dev );
4617 release_font( physdev->font );
4618 HeapFree( GetProcessHeap(), 0, physdev );
4619 return TRUE;
4622 static FT_Encoding pick_charmap( FT_Face face, int charset )
4624 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4625 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4626 const FT_Encoding *encs = regular_order;
4628 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4630 while (*encs != 0)
4632 if (select_charmap( face, *encs )) break;
4633 encs++;
4635 return *encs;
4638 #define GASP_GRIDFIT 0x01
4639 #define GASP_DOGRAY 0x02
4640 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4642 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4644 DWORD size;
4645 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4646 WORD *alloced = NULL, *ptr = buf;
4647 WORD num_recs, version;
4648 BOOL ret = FALSE;
4650 *flags = 0;
4651 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4652 if (size == GDI_ERROR) return FALSE;
4653 if (size < 4 * sizeof(WORD)) return FALSE;
4654 if (size > sizeof(buf))
4656 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4657 if (!ptr) return FALSE;
4660 get_font_data( font, GASP_TAG, 0, ptr, size );
4662 version = GET_BE_WORD( *ptr++ );
4663 num_recs = GET_BE_WORD( *ptr++ );
4665 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4667 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4668 goto done;
4671 while (num_recs--)
4673 *flags = GET_BE_WORD( *(ptr + 1) );
4674 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4675 ptr += 2;
4677 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4678 ret = TRUE;
4680 done:
4681 HeapFree( GetProcessHeap(), 0, alloced );
4682 return ret;
4685 /*************************************************************
4686 * freetype_SelectFont
4688 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4690 struct freetype_physdev *physdev = get_freetype_dev( dev );
4691 GdiFont *ret;
4692 Face *face, *best, *best_bitmap;
4693 Family *family, *last_resort_family;
4694 const struct list *face_list;
4695 INT height, width = 0;
4696 unsigned int score = 0, new_score;
4697 signed int diff = 0, newdiff;
4698 BOOL bd, it, can_use_bitmap, want_vertical;
4699 LOGFONTW lf;
4700 CHARSETINFO csi;
4701 FMAT2 dcmat;
4702 FontSubst *psub = NULL;
4703 DC *dc = get_dc_ptr( dev->hdc );
4704 const SYSTEM_LINKS *font_link;
4706 if (!hfont) /* notification that the font has been changed by another driver */
4708 release_font( physdev->font );
4709 physdev->font = NULL;
4710 release_dc_ptr( dc );
4711 return 0;
4714 GetObjectW( hfont, sizeof(lf), &lf );
4715 lf.lfWidth = abs(lf.lfWidth);
4717 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4719 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4720 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4721 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4722 lf.lfEscapement);
4724 if(dc->GraphicsMode == GM_ADVANCED)
4726 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4727 /* Try to avoid not necessary glyph transformations */
4728 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4730 lf.lfHeight *= fabs(dcmat.eM11);
4731 lf.lfWidth *= fabs(dcmat.eM11);
4732 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4735 else
4737 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4738 font scaling abilities. */
4739 dcmat.eM11 = dcmat.eM22 = 1.0;
4740 dcmat.eM21 = dcmat.eM12 = 0;
4741 lf.lfOrientation = lf.lfEscapement;
4742 if (dc->vport2WorldValid)
4744 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4745 lf.lfOrientation = -lf.lfOrientation;
4746 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4747 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4751 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4752 dcmat.eM21, dcmat.eM22);
4754 GDI_CheckNotLock();
4755 EnterCriticalSection( &freetype_cs );
4757 /* check the cache first */
4758 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4759 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4760 goto done;
4763 TRACE("not in cache\n");
4764 ret = alloc_font();
4766 ret->font_desc.matrix = dcmat;
4767 ret->font_desc.lf = lf;
4768 ret->font_desc.can_use_bitmap = can_use_bitmap;
4769 calc_hash(&ret->font_desc);
4771 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4772 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4773 original value lfCharSet. Note this is a special case for
4774 Symbol and doesn't happen at least for "Wingdings*" */
4776 if(!strcmpiW(lf.lfFaceName, SymbolW))
4777 lf.lfCharSet = SYMBOL_CHARSET;
4779 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4780 switch(lf.lfCharSet) {
4781 case DEFAULT_CHARSET:
4782 csi.fs.fsCsb[0] = 0;
4783 break;
4784 default:
4785 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4786 csi.fs.fsCsb[0] = 0;
4787 break;
4791 family = NULL;
4792 if(lf.lfFaceName[0] != '\0') {
4793 CHILD_FONT *font_link_entry;
4794 LPWSTR FaceName = lf.lfFaceName;
4796 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4798 if(psub) {
4799 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4800 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4801 if (psub->to.charset != -1)
4802 lf.lfCharSet = psub->to.charset;
4805 /* We want a match on name and charset or just name if
4806 charset was DEFAULT_CHARSET. If the latter then
4807 we fixup the returned charset later in get_nearest_charset
4808 where we'll either use the charset of the current ansi codepage
4809 or if that's unavailable the first charset that the font supports.
4811 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4812 if (!strcmpiW(family->FamilyName, FaceName) ||
4813 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4815 font_link = find_font_link(family->FamilyName);
4816 face_list = get_face_list_from_family(family);
4817 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4818 if (!(face->scalable || can_use_bitmap))
4819 continue;
4820 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4821 goto found;
4822 if (font_link != NULL &&
4823 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4824 goto found;
4825 if (!csi.fs.fsCsb[0])
4826 goto found;
4831 /* Search by full face name. */
4832 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4833 face_list = get_face_list_from_family(family);
4834 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4835 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4836 (face->scalable || can_use_bitmap))
4838 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4839 goto found_face;
4840 font_link = find_font_link(family->FamilyName);
4841 if (font_link != NULL &&
4842 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4843 goto found_face;
4849 * Try check the SystemLink list first for a replacement font.
4850 * We may find good replacements there.
4852 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4854 if(!strcmpiW(font_link->font_name, FaceName) ||
4855 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4857 TRACE("found entry in system list\n");
4858 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4860 const SYSTEM_LINKS *links;
4862 face = font_link_entry->face;
4863 if (!(face->scalable || can_use_bitmap))
4864 continue;
4865 family = face->family;
4866 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4867 goto found;
4868 links = find_font_link(family->FamilyName);
4869 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4870 goto found;
4876 psub = NULL; /* substitution is no more relevant */
4878 /* If requested charset was DEFAULT_CHARSET then try using charset
4879 corresponding to the current ansi codepage */
4880 if (!csi.fs.fsCsb[0])
4882 INT acp = GetACP();
4883 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4884 FIXME("TCI failed on codepage %d\n", acp);
4885 csi.fs.fsCsb[0] = 0;
4886 } else
4887 lf.lfCharSet = csi.ciCharset;
4890 want_vertical = (lf.lfFaceName[0] == '@');
4892 /* Face families are in the top 4 bits of lfPitchAndFamily,
4893 so mask with 0xF0 before testing */
4895 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4896 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4897 strcpyW(lf.lfFaceName, defFixed);
4898 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4899 strcpyW(lf.lfFaceName, defSerif);
4900 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4901 strcpyW(lf.lfFaceName, defSans);
4902 else
4903 strcpyW(lf.lfFaceName, defSans);
4904 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4905 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4906 font_link = find_font_link(family->FamilyName);
4907 face_list = get_face_list_from_family(family);
4908 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4909 if (!(face->scalable || can_use_bitmap))
4910 continue;
4911 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4912 goto found;
4913 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4914 goto found;
4919 last_resort_family = NULL;
4920 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4921 font_link = find_font_link(family->FamilyName);
4922 face_list = get_face_list_from_family(family);
4923 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4924 if(!(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical &&
4925 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4926 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4927 if(face->scalable)
4928 goto found;
4929 if(can_use_bitmap && !last_resort_family)
4930 last_resort_family = family;
4935 if(last_resort_family) {
4936 family = last_resort_family;
4937 csi.fs.fsCsb[0] = 0;
4938 goto found;
4941 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4942 face_list = get_face_list_from_family(family);
4943 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4944 if(face->scalable && !(face->flags & ADDFONT_VERTICAL_FONT) == !want_vertical) {
4945 csi.fs.fsCsb[0] = 0;
4946 WARN("just using first face for now\n");
4947 goto found;
4949 if(can_use_bitmap && !last_resort_family)
4950 last_resort_family = family;
4953 if(!last_resort_family) {
4954 FIXME("can't find a single appropriate font - bailing\n");
4955 free_font(ret);
4956 ret = NULL;
4957 goto done;
4960 WARN("could only find a bitmap font - this will probably look awful!\n");
4961 family = last_resort_family;
4962 csi.fs.fsCsb[0] = 0;
4964 found:
4965 it = lf.lfItalic ? 1 : 0;
4966 bd = lf.lfWeight > 550 ? 1 : 0;
4968 height = lf.lfHeight;
4970 face = best = best_bitmap = NULL;
4971 font_link = find_font_link(family->FamilyName);
4972 face_list = get_face_list_from_family(family);
4973 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4975 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4976 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4977 !csi.fs.fsCsb[0])
4979 BOOL italic, bold;
4981 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4982 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4983 new_score = (italic ^ it) + (bold ^ bd);
4984 if(!best || new_score <= score)
4986 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4987 italic, bold, it, bd);
4988 score = new_score;
4989 best = face;
4990 if(best->scalable && score == 0) break;
4991 if(!best->scalable)
4993 if(height > 0)
4994 newdiff = height - (signed int)(best->size.height);
4995 else
4996 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4997 if(!best_bitmap || new_score < score ||
4998 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
5000 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
5001 diff = newdiff;
5002 best_bitmap = best;
5003 if(score == 0 && diff == 0) break;
5009 if(best)
5010 face = best->scalable ? best : best_bitmap;
5011 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
5012 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
5014 found_face:
5015 height = lf.lfHeight;
5017 ret->fs = face->fs;
5019 if(csi.fs.fsCsb[0]) {
5020 ret->charset = lf.lfCharSet;
5021 ret->codepage = csi.ciACP;
5023 else
5024 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
5026 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
5027 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
5029 ret->aveWidth = height ? lf.lfWidth : 0;
5031 if(!face->scalable) {
5032 /* Windows uses integer scaling factors for bitmap fonts */
5033 INT scale, scaled_height;
5034 GdiFont *cachedfont;
5036 /* FIXME: rotation of bitmap fonts is ignored */
5037 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
5038 if (ret->aveWidth)
5039 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
5040 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
5041 dcmat.eM11 = dcmat.eM22 = 1.0;
5042 /* As we changed the matrix, we need to search the cache for the font again,
5043 * otherwise we might explode the cache. */
5044 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
5045 TRACE("Found cached font after non-scalable matrix rescale!\n");
5046 free_font( ret );
5047 ret = cachedfont;
5048 goto done;
5050 calc_hash(&ret->font_desc);
5052 if (height != 0) height = diff;
5053 height += face->size.height;
5055 scale = (height + face->size.height - 1) / face->size.height;
5056 scaled_height = scale * face->size.height;
5057 /* Only jump to the next height if the difference <= 25% original height */
5058 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
5059 /* The jump between unscaled and doubled is delayed by 1 */
5060 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
5061 ret->scale_y = scale;
5063 width = face->size.x_ppem >> 6;
5064 height = face->size.y_ppem >> 6;
5066 else
5067 ret->scale_y = 1.0;
5068 TRACE("font scale y: %f\n", ret->scale_y);
5070 ret->ft_face = OpenFontFace(ret, face, width, height);
5072 if (!ret->ft_face)
5074 free_font( ret );
5075 ret = NULL;
5076 goto done;
5079 ret->ntmFlags = face->ntmFlags;
5081 pick_charmap( ret->ft_face, ret->charset );
5083 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
5084 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
5085 ret->underline = lf.lfUnderline ? 0xff : 0;
5086 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
5087 create_child_font_list(ret);
5089 if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */
5091 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
5092 if (length != GDI_ERROR)
5094 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
5095 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
5096 TRACE("Loaded GSUB table of %i bytes\n",length);
5099 ret->aa_flags = HIWORD( face->flags );
5101 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
5103 add_to_cache(ret);
5104 done:
5105 if (ret)
5107 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
5109 switch (lf.lfQuality)
5111 case NONANTIALIASED_QUALITY:
5112 case ANTIALIASED_QUALITY:
5113 next->funcs->pSelectFont( dev, hfont, aa_flags );
5114 break;
5115 case CLEARTYPE_QUALITY:
5116 case CLEARTYPE_NATURAL_QUALITY:
5117 default:
5118 if (!*aa_flags) *aa_flags = ret->aa_flags;
5119 next->funcs->pSelectFont( dev, hfont, aa_flags );
5121 /* fixup the antialiasing flags for that font */
5122 switch (*aa_flags)
5124 case WINE_GGO_HRGB_BITMAP:
5125 case WINE_GGO_HBGR_BITMAP:
5126 case WINE_GGO_VRGB_BITMAP:
5127 case WINE_GGO_VBGR_BITMAP:
5128 if (is_subpixel_rendering_enabled()) break;
5129 *aa_flags = GGO_GRAY4_BITMAP;
5130 /* fall through */
5131 case GGO_GRAY2_BITMAP:
5132 case GGO_GRAY4_BITMAP:
5133 case GGO_GRAY8_BITMAP:
5134 case WINE_GGO_GRAY16_BITMAP:
5135 if (is_hinting_enabled())
5137 WORD gasp_flags;
5138 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5140 TRACE( "font %s %d aa disabled by GASP\n",
5141 debugstr_w(lf.lfFaceName), lf.lfHeight );
5142 *aa_flags = GGO_BITMAP;
5147 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5148 release_font( physdev->font );
5149 physdev->font = ret;
5151 LeaveCriticalSection( &freetype_cs );
5152 release_dc_ptr( dc );
5153 return ret ? hfont : 0;
5156 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5158 HRSRC rsrc;
5159 HGLOBAL hMem;
5160 WCHAR *p;
5161 int i;
5163 id += IDS_FIRST_SCRIPT;
5164 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5165 if (!rsrc) return 0;
5166 hMem = LoadResource( gdi32_module, rsrc );
5167 if (!hMem) return 0;
5169 p = LockResource( hMem );
5170 id &= 0x000f;
5171 while (id--) p += *p + 1;
5173 i = min(LF_FACESIZE - 1, *p);
5174 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5175 buffer[i] = 0;
5176 return i;
5180 /***************************************************
5181 * create_enum_charset_list
5183 * This function creates charset enumeration list because in DEFAULT_CHARSET
5184 * case, the ANSI codepage's charset takes precedence over other charsets.
5185 * This function works as a filter other than DEFAULT_CHARSET case.
5187 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5189 CHARSETINFO csi;
5190 DWORD n = 0;
5192 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5193 csi.fs.fsCsb[0] != 0) {
5194 list->element[n].mask = csi.fs.fsCsb[0];
5195 list->element[n].charset = csi.ciCharset;
5196 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5197 n++;
5199 else { /* charset is DEFAULT_CHARSET or invalid. */
5200 INT acp, i;
5201 DWORD mask = 0;
5203 /* Set the current codepage's charset as the first element. */
5204 acp = GetACP();
5205 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5206 csi.fs.fsCsb[0] != 0) {
5207 list->element[n].mask = csi.fs.fsCsb[0];
5208 list->element[n].charset = csi.ciCharset;
5209 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5210 mask |= csi.fs.fsCsb[0];
5211 n++;
5214 /* Fill out left elements. */
5215 for (i = 0; i < 32; i++) {
5216 FONTSIGNATURE fs;
5217 fs.fsCsb[0] = 1L << i;
5218 fs.fsCsb[1] = 0;
5219 if (fs.fsCsb[0] & mask)
5220 continue; /* skip, already added. */
5221 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5222 continue; /* skip, this is an invalid fsCsb bit. */
5224 list->element[n].mask = fs.fsCsb[0];
5225 list->element[n].charset = csi.ciCharset;
5226 load_script_name( i, list->element[n].name );
5227 mask |= fs.fsCsb[0];
5228 n++;
5231 /* add catch all mask for remaining bits */
5232 if (~mask)
5234 list->element[n].mask = ~mask;
5235 list->element[n].charset = DEFAULT_CHARSET;
5236 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5237 n++;
5240 list->total = n;
5242 return n;
5245 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5246 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5248 GdiFont *font;
5249 LONG width, height;
5251 if (face->cached_enum_data)
5253 TRACE("Cached\n");
5254 *pelf = face->cached_enum_data->elf;
5255 *pntm = face->cached_enum_data->ntm;
5256 *ptype = face->cached_enum_data->type;
5257 return;
5260 font = alloc_font();
5262 if(face->scalable) {
5263 height = 100;
5264 width = 0;
5265 } else {
5266 height = face->size.y_ppem >> 6;
5267 width = face->size.x_ppem >> 6;
5269 font->scale_y = 1.0;
5271 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5273 free_font(font);
5274 return;
5277 font->name = strdupW( family_name );
5278 font->ntmFlags = face->ntmFlags;
5280 if (get_outline_text_metrics(font))
5282 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5284 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5285 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5286 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5288 lstrcpynW(pelf->elfLogFont.lfFaceName,
5289 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5290 LF_FACESIZE);
5291 lstrcpynW(pelf->elfFullName,
5292 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5293 LF_FULLFACESIZE);
5294 lstrcpynW(pelf->elfStyle,
5295 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5296 LF_FACESIZE);
5298 else
5300 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5302 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5303 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5304 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5306 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5307 if (face->FullName)
5308 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5309 else
5310 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5311 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5314 pntm->ntmTm.ntmFlags = face->ntmFlags;
5315 pntm->ntmFontSig = face->fs;
5317 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5319 pelf->elfLogFont.lfEscapement = 0;
5320 pelf->elfLogFont.lfOrientation = 0;
5321 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5322 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5323 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5324 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5325 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5326 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5327 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5328 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5329 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5330 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5331 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5333 *ptype = 0;
5334 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5335 *ptype |= TRUETYPE_FONTTYPE;
5336 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5337 *ptype |= DEVICE_FONTTYPE;
5338 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5339 *ptype |= RASTER_FONTTYPE;
5341 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5342 if (face->cached_enum_data)
5344 face->cached_enum_data->elf = *pelf;
5345 face->cached_enum_data->ntm = *pntm;
5346 face->cached_enum_data->type = *ptype;
5349 free_font(font);
5352 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5354 Face *face;
5355 const struct list *face_list;
5357 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5359 face_list = get_face_list_from_family(family);
5360 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5361 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5363 return FALSE;
5366 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5368 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5370 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5373 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5374 FONTENUMPROCW proc, LPARAM lparam)
5376 ENUMLOGFONTEXW elf;
5377 NEWTEXTMETRICEXW ntm;
5378 DWORD type = 0;
5379 DWORD i;
5381 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5382 for(i = 0; i < list->total; i++) {
5383 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5384 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5385 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5386 i = list->total; /* break out of loop after enumeration */
5388 else
5390 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5391 /* use the DEFAULT_CHARSET case only if no other charset is present */
5392 if (list->element[i].charset == DEFAULT_CHARSET &&
5393 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5394 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5395 strcpyW(elf.elfScript, list->element[i].name);
5396 if (!elf.elfScript[0])
5397 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5399 /* Font Replacement */
5400 if (family != face->family)
5402 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5403 if (face->FullName)
5404 strcpyW(elf.elfFullName, face->FullName);
5405 else
5406 strcpyW(elf.elfFullName, family->FamilyName);
5408 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5409 debugstr_w(elf.elfLogFont.lfFaceName),
5410 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5411 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5412 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5413 ntm.ntmTm.ntmFlags);
5414 /* release section before callback (FIXME) */
5415 LeaveCriticalSection( &freetype_cs );
5416 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5417 EnterCriticalSection( &freetype_cs );
5419 return TRUE;
5422 /*************************************************************
5423 * freetype_EnumFonts
5425 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5427 Family *family;
5428 Face *face;
5429 const struct list *face_list;
5430 LOGFONTW lf;
5431 struct enum_charset_list enum_charsets;
5433 if (!plf)
5435 lf.lfCharSet = DEFAULT_CHARSET;
5436 lf.lfPitchAndFamily = 0;
5437 lf.lfFaceName[0] = 0;
5438 plf = &lf;
5441 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5443 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5445 GDI_CheckNotLock();
5446 EnterCriticalSection( &freetype_cs );
5447 if(plf->lfFaceName[0]) {
5448 FontSubst *psub;
5449 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5451 if(psub) {
5452 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5453 debugstr_w(psub->to.name));
5454 lf = *plf;
5455 strcpyW(lf.lfFaceName, psub->to.name);
5456 plf = &lf;
5459 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5460 if (!family_matches(family, plf)) continue;
5461 face_list = get_face_list_from_family(family);
5462 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5463 if (!face_matches(family->FamilyName, face, plf)) continue;
5464 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5467 } else {
5468 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5469 face_list = get_face_list_from_family(family);
5470 face = LIST_ENTRY(list_head(face_list), Face, entry);
5471 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5474 LeaveCriticalSection( &freetype_cs );
5475 return TRUE;
5478 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5480 pt->x.value = vec->x >> 6;
5481 pt->x.fract = (vec->x & 0x3f) << 10;
5482 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5483 pt->y.value = vec->y >> 6;
5484 pt->y.fract = (vec->y & 0x3f) << 10;
5485 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5486 return;
5489 /***************************************************
5490 * According to the MSDN documentation on WideCharToMultiByte,
5491 * certain codepages cannot set the default_used parameter.
5492 * This returns TRUE if the codepage can set that parameter, false else
5493 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5495 static BOOL codepage_sets_default_used(UINT codepage)
5497 switch (codepage)
5499 case CP_UTF7:
5500 case CP_UTF8:
5501 case CP_SYMBOL:
5502 return FALSE;
5503 default:
5504 return TRUE;
5509 * GSUB Table handling functions
5512 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5514 const GSUB_CoverageFormat1* cf1;
5516 cf1 = table;
5518 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5520 int count = GET_BE_WORD(cf1->GlyphCount);
5521 int i;
5522 TRACE("Coverage Format 1, %i glyphs\n",count);
5523 for (i = 0; i < count; i++)
5524 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5525 return i;
5526 return -1;
5528 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5530 const GSUB_CoverageFormat2* cf2;
5531 int i;
5532 int count;
5533 cf2 = (const GSUB_CoverageFormat2*)cf1;
5535 count = GET_BE_WORD(cf2->RangeCount);
5536 TRACE("Coverage Format 2, %i ranges\n",count);
5537 for (i = 0; i < count; i++)
5539 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5540 return -1;
5541 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5542 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5544 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5545 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5548 return -1;
5550 else
5551 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5553 return -1;
5556 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5558 const GSUB_ScriptList *script;
5559 const GSUB_Script *deflt = NULL;
5560 int i;
5561 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5563 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5564 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5566 const GSUB_Script *scr;
5567 int offset;
5569 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5570 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5572 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5573 return scr;
5574 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5575 deflt = scr;
5577 return deflt;
5580 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5582 int i;
5583 int offset;
5584 const GSUB_LangSys *Lang;
5586 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5588 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5590 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5591 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5593 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5594 return Lang;
5596 offset = GET_BE_WORD(script->DefaultLangSys);
5597 if (offset)
5599 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5600 return Lang;
5602 return NULL;
5605 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5607 int i;
5608 const GSUB_FeatureList *feature;
5609 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5611 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5612 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5614 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5615 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5617 const GSUB_Feature *feat;
5618 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5619 return feat;
5622 return NULL;
5625 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5627 int i;
5628 int offset;
5629 const GSUB_LookupList *lookup;
5630 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5632 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5633 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5635 const GSUB_LookupTable *look;
5636 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5637 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5638 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5639 if (GET_BE_WORD(look->LookupType) != 1)
5640 FIXME("We only handle SubType 1\n");
5641 else
5643 int j;
5645 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5647 const GSUB_SingleSubstFormat1 *ssf1;
5648 offset = GET_BE_WORD(look->SubTable[j]);
5649 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5650 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5652 int offset = GET_BE_WORD(ssf1->Coverage);
5653 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5654 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5656 TRACE(" Glyph 0x%x ->",glyph);
5657 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5658 TRACE(" 0x%x\n",glyph);
5661 else
5663 const GSUB_SingleSubstFormat2 *ssf2;
5664 INT index;
5665 INT offset;
5667 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5668 offset = GET_BE_WORD(ssf1->Coverage);
5669 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5670 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5671 TRACE(" Coverage index %i\n",index);
5672 if (index != -1)
5674 TRACE(" Glyph is 0x%x ->",glyph);
5675 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5676 TRACE("0x%x\n",glyph);
5682 return glyph;
5685 static const char* get_opentype_script(const GdiFont *font)
5688 * I am not sure if this is the correct way to generate our script tag
5691 switch (font->charset)
5693 case ANSI_CHARSET: return "latn";
5694 case BALTIC_CHARSET: return "latn"; /* ?? */
5695 case CHINESEBIG5_CHARSET: return "hani";
5696 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5697 case GB2312_CHARSET: return "hani";
5698 case GREEK_CHARSET: return "grek";
5699 case HANGUL_CHARSET: return "hang";
5700 case RUSSIAN_CHARSET: return "cyrl";
5701 case SHIFTJIS_CHARSET: return "kana";
5702 case TURKISH_CHARSET: return "latn"; /* ?? */
5703 case VIETNAMESE_CHARSET: return "latn";
5704 case JOHAB_CHARSET: return "latn"; /* ?? */
5705 case ARABIC_CHARSET: return "arab";
5706 case HEBREW_CHARSET: return "hebr";
5707 case THAI_CHARSET: return "thai";
5708 default: return "latn";
5712 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5714 const GSUB_Header *header;
5715 const GSUB_Script *script;
5716 const GSUB_LangSys *language;
5717 const GSUB_Feature *feature;
5719 if (!font->GSUB_Table)
5720 return glyph;
5722 header = font->GSUB_Table;
5724 script = GSUB_get_script_table(header, get_opentype_script(font));
5725 if (!script)
5727 TRACE("Script not found\n");
5728 return glyph;
5730 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5731 if (!language)
5733 TRACE("Language not found\n");
5734 return glyph;
5736 feature = GSUB_get_feature(header, language, "vrt2");
5737 if (!feature)
5738 feature = GSUB_get_feature(header, language, "vert");
5739 if (!feature)
5741 TRACE("vrt2/vert feature not found\n");
5742 return glyph;
5744 return GSUB_apply_feature(header, feature, glyph);
5747 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5749 FT_UInt glyphId;
5751 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5752 WCHAR wc = (WCHAR)glyph;
5753 BOOL default_used;
5754 BOOL *default_used_pointer;
5755 FT_UInt ret;
5756 char buf;
5757 default_used_pointer = NULL;
5758 default_used = FALSE;
5759 if (codepage_sets_default_used(font->codepage))
5760 default_used_pointer = &default_used;
5761 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5763 if (font->codepage == CP_SYMBOL && wc < 0x100)
5764 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5765 else
5766 ret = 0;
5768 else
5769 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5770 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5771 return ret;
5774 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5776 if (glyph < 0x100) glyph += 0xf000;
5777 /* there is a number of old pre-Unicode "broken" TTFs, which
5778 do have symbols at U+00XX instead of U+f0XX */
5779 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5780 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5782 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5784 return glyphId;
5787 /*************************************************************
5788 * freetype_GetGlyphIndices
5790 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5792 struct freetype_physdev *physdev = get_freetype_dev( dev );
5793 int i;
5794 WORD default_char;
5795 BOOL got_default = FALSE;
5797 if (!physdev->font)
5799 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5800 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5803 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5805 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5806 got_default = TRUE;
5809 GDI_CheckNotLock();
5810 EnterCriticalSection( &freetype_cs );
5812 for(i = 0; i < count; i++)
5814 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5815 if (pgi[i] == 0)
5817 if (!got_default)
5819 if (FT_IS_SFNT(physdev->font->ft_face))
5821 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5822 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5824 else
5826 TEXTMETRICW textm;
5827 get_text_metrics(physdev->font, &textm);
5828 default_char = textm.tmDefaultChar;
5830 got_default = TRUE;
5832 pgi[i] = default_char;
5835 LeaveCriticalSection( &freetype_cs );
5836 return count;
5839 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5841 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5842 return !memcmp(matrix, &identity, sizeof(FMAT2));
5845 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5847 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5848 return !memcmp(matrix, &identity, sizeof(MAT2));
5851 static inline BYTE get_max_level( UINT format )
5853 switch( format )
5855 case GGO_GRAY2_BITMAP: return 4;
5856 case GGO_GRAY4_BITMAP: return 16;
5857 case GGO_GRAY8_BITMAP: return 64;
5859 return 255;
5862 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5864 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5865 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5866 const MAT2* lpmat)
5868 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5869 FT_Face ft_face = incoming_font->ft_face;
5870 GdiFont *font = incoming_font;
5871 FT_UInt glyph_index;
5872 DWORD width, height, pitch, needed = 0;
5873 FT_Bitmap ft_bitmap;
5874 FT_Error err;
5875 INT left, right, top = 0, bottom = 0, adv;
5876 FT_Angle angle = 0;
5877 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5878 double widthRatio = 1.0;
5879 FT_Matrix transMat = identityMat;
5880 FT_Matrix transMatUnrotated;
5881 BOOL needsTransform = FALSE;
5882 BOOL tategaki = (font->GSUB_Table != NULL);
5883 UINT original_index;
5884 LONG avgAdvance = 0;
5885 FT_Fixed em_scale;
5887 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5888 buflen, buf, lpmat);
5890 TRACE("font transform %f %f %f %f\n",
5891 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5892 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5894 if(format & GGO_GLYPH_INDEX) {
5895 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5896 original_index = glyph;
5897 format &= ~GGO_GLYPH_INDEX;
5898 } else {
5899 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5900 ft_face = font->ft_face;
5901 original_index = glyph_index;
5904 if(format & GGO_UNHINTED) {
5905 load_flags |= FT_LOAD_NO_HINTING;
5906 format &= ~GGO_UNHINTED;
5909 /* tategaki never appears to happen to lower glyph index */
5910 if (glyph_index < TATEGAKI_LOWER_BOUND )
5911 tategaki = FALSE;
5913 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5914 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5915 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5916 font->gmsize * sizeof(GM*));
5917 } else {
5918 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5919 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5921 *lpgm = FONT_GM(font,original_index)->gm;
5922 *abc = FONT_GM(font,original_index)->abc;
5923 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5924 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5925 lpgm->gmCellIncX, lpgm->gmCellIncY);
5926 return 1; /* FIXME */
5930 if (!font->gm[original_index / GM_BLOCK_SIZE])
5931 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5933 /* Scaling factor */
5934 if (font->aveWidth)
5936 TEXTMETRICW tm;
5938 get_text_metrics(font, &tm);
5940 widthRatio = (double)font->aveWidth;
5941 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5943 else
5944 widthRatio = font->scale_y;
5946 /* Scaling transform */
5947 if (widthRatio != 1.0 || font->scale_y != 1.0)
5949 FT_Matrix scaleMat;
5950 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5951 scaleMat.xy = 0;
5952 scaleMat.yx = 0;
5953 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5955 pFT_Matrix_Multiply(&scaleMat, &transMat);
5956 needsTransform = TRUE;
5959 /* Slant transform */
5960 if (font->fake_italic) {
5961 FT_Matrix slantMat;
5963 slantMat.xx = (1 << 16);
5964 slantMat.xy = ((1 << 16) >> 2);
5965 slantMat.yx = 0;
5966 slantMat.yy = (1 << 16);
5967 pFT_Matrix_Multiply(&slantMat, &transMat);
5968 needsTransform = TRUE;
5971 /* Rotation transform */
5972 transMatUnrotated = transMat;
5973 if(font->orientation && !tategaki) {
5974 FT_Matrix rotationMat;
5975 FT_Vector vecAngle;
5976 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5977 pFT_Vector_Unit(&vecAngle, angle);
5978 rotationMat.xx = vecAngle.x;
5979 rotationMat.xy = -vecAngle.y;
5980 rotationMat.yx = -rotationMat.xy;
5981 rotationMat.yy = rotationMat.xx;
5983 pFT_Matrix_Multiply(&rotationMat, &transMat);
5984 needsTransform = TRUE;
5987 /* World transform */
5988 if (!is_identity_FMAT2(&font->font_desc.matrix))
5990 FT_Matrix worldMat;
5991 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5992 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
5993 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
5994 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5995 pFT_Matrix_Multiply(&worldMat, &transMat);
5996 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5997 needsTransform = TRUE;
6000 /* Extra transformation specified by caller */
6001 if (!is_identity_MAT2(lpmat))
6003 FT_Matrix extraMat;
6004 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
6005 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
6006 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
6007 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
6008 pFT_Matrix_Multiply(&extraMat, &transMat);
6009 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
6010 needsTransform = TRUE;
6013 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
6015 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
6017 if(err) {
6018 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
6019 return GDI_ERROR;
6022 if(FT_IS_SCALABLE(incoming_font->ft_face)) {
6023 TEXTMETRICW tm;
6024 if (get_text_metrics(incoming_font, &tm) &&
6025 !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
6026 em_scale = MulDiv(incoming_font->ppem, 1 << 16, incoming_font->ft_face->units_per_EM);
6027 avgAdvance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
6028 if (avgAdvance &&
6029 (ft_face->glyph->metrics.horiAdvance+63) >> 6 == pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale))
6030 TRACE("Fixed-pitch full-width character detected\n");
6031 else
6032 avgAdvance = 0; /* cancel this feature */
6036 if(!needsTransform) {
6037 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
6038 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
6039 if (!avgAdvance)
6040 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
6041 else
6042 adv = (INT)avgAdvance * 2;
6044 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
6045 bottom = (ft_face->glyph->metrics.horiBearingY -
6046 ft_face->glyph->metrics.height) & -64;
6047 lpgm->gmCellIncX = adv;
6048 lpgm->gmCellIncY = 0;
6049 } else {
6050 INT xc, yc;
6051 FT_Vector vec;
6053 left = right = 0;
6055 for(xc = 0; xc < 2; xc++) {
6056 for(yc = 0; yc < 2; yc++) {
6057 vec.x = (ft_face->glyph->metrics.horiBearingX +
6058 xc * ft_face->glyph->metrics.width);
6059 vec.y = ft_face->glyph->metrics.horiBearingY -
6060 yc * ft_face->glyph->metrics.height;
6061 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
6062 pFT_Vector_Transform(&vec, &transMat);
6063 if(xc == 0 && yc == 0) {
6064 left = right = vec.x;
6065 top = bottom = vec.y;
6066 } else {
6067 if(vec.x < left) left = vec.x;
6068 else if(vec.x > right) right = vec.x;
6069 if(vec.y < bottom) bottom = vec.y;
6070 else if(vec.y > top) top = vec.y;
6074 left = left & -64;
6075 right = (right + 63) & -64;
6076 bottom = bottom & -64;
6077 top = (top + 63) & -64;
6079 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
6080 vec.x = ft_face->glyph->metrics.horiAdvance;
6081 vec.y = 0;
6082 pFT_Vector_Transform(&vec, &transMat);
6083 lpgm->gmCellIncY = -((vec.y+63) >> 6);
6084 if (!avgAdvance || vec.y)
6085 lpgm->gmCellIncX = (vec.x+63) >> 6;
6086 else {
6087 vec.x = incoming_font->ntmAvgWidth;
6088 vec.y = 0;
6089 pFT_Vector_Transform(&vec, &transMat);
6090 lpgm->gmCellIncX = pFT_MulFix(vec.x, em_scale) * 2;
6093 vec.x = ft_face->glyph->metrics.horiAdvance;
6094 vec.y = 0;
6095 pFT_Vector_Transform(&vec, &transMatUnrotated);
6096 if (!avgAdvance || vec.y)
6097 adv = (vec.x+63) >> 6;
6098 else {
6099 vec.x = incoming_font->ntmAvgWidth;
6100 vec.y = 0;
6101 pFT_Vector_Transform(&vec, &transMatUnrotated);
6102 adv = pFT_MulFix(vec.x, em_scale) * 2;
6106 lpgm->gmBlackBoxX = (right - left) >> 6;
6107 lpgm->gmBlackBoxY = (top - bottom) >> 6;
6108 lpgm->gmptGlyphOrigin.x = left >> 6;
6109 lpgm->gmptGlyphOrigin.y = top >> 6;
6110 abc->abcA = left >> 6;
6111 abc->abcB = (right - left) >> 6;
6112 abc->abcC = adv - abc->abcA - abc->abcB;
6114 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
6115 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
6116 lpgm->gmCellIncX, lpgm->gmCellIncY);
6118 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
6119 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
6121 FONT_GM(font,original_index)->gm = *lpgm;
6122 FONT_GM(font,original_index)->abc = *abc;
6123 FONT_GM(font,original_index)->init = TRUE;
6126 if(format == GGO_METRICS)
6128 return 1; /* FIXME */
6131 if(ft_face->glyph->format != ft_glyph_format_outline &&
6132 (format == GGO_NATIVE || format == GGO_BEZIER))
6134 TRACE("loaded a bitmap\n");
6135 return GDI_ERROR;
6138 switch(format) {
6139 case GGO_BITMAP:
6140 width = lpgm->gmBlackBoxX;
6141 height = lpgm->gmBlackBoxY;
6142 pitch = ((width + 31) >> 5) << 2;
6143 needed = pitch * height;
6145 if(!buf || !buflen) break;
6147 switch(ft_face->glyph->format) {
6148 case ft_glyph_format_bitmap:
6150 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6151 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
6152 INT h = min( height, ft_face->glyph->bitmap.rows );
6153 while(h--) {
6154 memcpy(dst, src, w);
6155 src += ft_face->glyph->bitmap.pitch;
6156 dst += pitch;
6158 break;
6161 case ft_glyph_format_outline:
6162 ft_bitmap.width = width;
6163 ft_bitmap.rows = height;
6164 ft_bitmap.pitch = pitch;
6165 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
6166 ft_bitmap.buffer = buf;
6168 if(needsTransform)
6169 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6171 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6173 /* Note: FreeType will only set 'black' bits for us. */
6174 memset(buf, 0, needed);
6175 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6176 break;
6178 default:
6179 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6180 return GDI_ERROR;
6182 break;
6184 case GGO_GRAY2_BITMAP:
6185 case GGO_GRAY4_BITMAP:
6186 case GGO_GRAY8_BITMAP:
6187 case WINE_GGO_GRAY16_BITMAP:
6189 unsigned int max_level, row, col;
6190 BYTE *start, *ptr;
6192 width = lpgm->gmBlackBoxX;
6193 height = lpgm->gmBlackBoxY;
6194 pitch = (width + 3) / 4 * 4;
6195 needed = pitch * height;
6197 if(!buf || !buflen) break;
6199 max_level = get_max_level( format );
6201 switch(ft_face->glyph->format) {
6202 case ft_glyph_format_bitmap:
6204 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6205 INT h = min( height, ft_face->glyph->bitmap.rows );
6206 INT x;
6207 memset( buf, 0, needed );
6208 while(h--) {
6209 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6210 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6211 src += ft_face->glyph->bitmap.pitch;
6212 dst += pitch;
6214 return needed;
6216 case ft_glyph_format_outline:
6218 ft_bitmap.width = width;
6219 ft_bitmap.rows = height;
6220 ft_bitmap.pitch = pitch;
6221 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6222 ft_bitmap.buffer = buf;
6224 if(needsTransform)
6225 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6227 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6229 memset(ft_bitmap.buffer, 0, buflen);
6231 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6233 if (max_level != 255)
6235 for (row = 0, start = buf; row < height; row++)
6237 for (col = 0, ptr = start; col < width; col++, ptr++)
6238 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6239 start += pitch;
6242 return needed;
6245 default:
6246 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6247 return GDI_ERROR;
6249 break;
6252 case WINE_GGO_HRGB_BITMAP:
6253 case WINE_GGO_HBGR_BITMAP:
6254 case WINE_GGO_VRGB_BITMAP:
6255 case WINE_GGO_VBGR_BITMAP:
6256 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6258 switch (ft_face->glyph->format)
6260 case FT_GLYPH_FORMAT_BITMAP:
6262 BYTE *src, *dst;
6263 INT src_pitch, x;
6265 width = lpgm->gmBlackBoxX;
6266 height = lpgm->gmBlackBoxY;
6267 pitch = width * 4;
6268 needed = pitch * height;
6270 if (!buf || !buflen) break;
6272 memset(buf, 0, buflen);
6273 dst = buf;
6274 src = ft_face->glyph->bitmap.buffer;
6275 src_pitch = ft_face->glyph->bitmap.pitch;
6277 height = min( height, ft_face->glyph->bitmap.rows );
6278 while ( height-- )
6280 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6282 if ( src[x / 8] & masks[x % 8] )
6283 ((unsigned int *)dst)[x] = ~0u;
6285 src += src_pitch;
6286 dst += pitch;
6289 break;
6292 case FT_GLYPH_FORMAT_OUTLINE:
6294 unsigned int *dst;
6295 BYTE *src;
6296 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6297 INT x_shift, y_shift;
6298 BOOL rgb;
6299 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6300 FT_Render_Mode render_mode =
6301 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6302 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6304 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6306 if ( render_mode == FT_RENDER_MODE_LCD)
6308 lpgm->gmBlackBoxX += 2;
6309 lpgm->gmptGlyphOrigin.x -= 1;
6311 else
6313 lpgm->gmBlackBoxY += 2;
6314 lpgm->gmptGlyphOrigin.y += 1;
6318 width = lpgm->gmBlackBoxX;
6319 height = lpgm->gmBlackBoxY;
6320 pitch = width * 4;
6321 needed = pitch * height;
6323 if (!buf || !buflen) break;
6325 memset(buf, 0, buflen);
6326 dst = buf;
6327 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6329 if ( needsTransform )
6330 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6332 if ( pFT_Library_SetLcdFilter )
6333 pFT_Library_SetLcdFilter( library, lcdfilter );
6334 pFT_Render_Glyph (ft_face->glyph, render_mode);
6336 src = ft_face->glyph->bitmap.buffer;
6337 src_pitch = ft_face->glyph->bitmap.pitch;
6338 src_width = ft_face->glyph->bitmap.width;
6339 src_height = ft_face->glyph->bitmap.rows;
6341 if ( render_mode == FT_RENDER_MODE_LCD)
6343 rgb_interval = 1;
6344 hmul = 3;
6345 vmul = 1;
6347 else
6349 rgb_interval = src_pitch;
6350 hmul = 1;
6351 vmul = 3;
6354 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6355 if ( x_shift < 0 ) x_shift = 0;
6356 if ( x_shift + (src_width / hmul) > width )
6357 x_shift = width - (src_width / hmul);
6359 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6360 if ( y_shift < 0 ) y_shift = 0;
6361 if ( y_shift + (src_height / vmul) > height )
6362 y_shift = height - (src_height / vmul);
6364 dst += x_shift + y_shift * ( pitch / 4 );
6365 while ( src_height )
6367 for ( x = 0; x < src_width / hmul; x++ )
6369 if ( rgb )
6371 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6372 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6373 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6374 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6376 else
6378 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6379 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6380 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6381 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6384 src += src_pitch * vmul;
6385 dst += pitch / 4;
6386 src_height -= vmul;
6389 break;
6392 default:
6393 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6394 return GDI_ERROR;
6397 break;
6399 #else
6400 return GDI_ERROR;
6401 #endif
6403 case GGO_NATIVE:
6405 int contour, point = 0, first_pt;
6406 FT_Outline *outline = &ft_face->glyph->outline;
6407 TTPOLYGONHEADER *pph;
6408 TTPOLYCURVE *ppc;
6409 DWORD pph_start, cpfx, type;
6411 if(buflen == 0) buf = NULL;
6413 if (needsTransform && buf) {
6414 pFT_Outline_Transform(outline, &transMat);
6417 for(contour = 0; contour < outline->n_contours; contour++) {
6418 /* Ignore contours containing one point */
6419 if(point == outline->contours[contour]) {
6420 point++;
6421 continue;
6424 pph_start = needed;
6425 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6426 first_pt = point;
6427 if(buf) {
6428 pph->dwType = TT_POLYGON_TYPE;
6429 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6431 needed += sizeof(*pph);
6432 point++;
6433 while(point <= outline->contours[contour]) {
6434 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6435 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6436 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6437 cpfx = 0;
6438 do {
6439 if(buf)
6440 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6441 cpfx++;
6442 point++;
6443 } while(point <= outline->contours[contour] &&
6444 (outline->tags[point] & FT_Curve_Tag_On) ==
6445 (outline->tags[point-1] & FT_Curve_Tag_On));
6446 /* At the end of a contour Windows adds the start point, but
6447 only for Beziers */
6448 if(point > outline->contours[contour] &&
6449 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6450 if(buf)
6451 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6452 cpfx++;
6453 } else if(point <= outline->contours[contour] &&
6454 outline->tags[point] & FT_Curve_Tag_On) {
6455 /* add closing pt for bezier */
6456 if(buf)
6457 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6458 cpfx++;
6459 point++;
6461 if(buf) {
6462 ppc->wType = type;
6463 ppc->cpfx = cpfx;
6465 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6467 if(buf)
6468 pph->cb = needed - pph_start;
6470 break;
6472 case GGO_BEZIER:
6474 /* Convert the quadratic Beziers to cubic Beziers.
6475 The parametric eqn for a cubic Bezier is, from PLRM:
6476 r(t) = at^3 + bt^2 + ct + r0
6477 with the control points:
6478 r1 = r0 + c/3
6479 r2 = r1 + (c + b)/3
6480 r3 = r0 + c + b + a
6482 A quadratic Bezier has the form:
6483 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6485 So equating powers of t leads to:
6486 r1 = 2/3 p1 + 1/3 p0
6487 r2 = 2/3 p1 + 1/3 p2
6488 and of course r0 = p0, r3 = p2
6491 int contour, point = 0, first_pt;
6492 FT_Outline *outline = &ft_face->glyph->outline;
6493 TTPOLYGONHEADER *pph;
6494 TTPOLYCURVE *ppc;
6495 DWORD pph_start, cpfx, type;
6496 FT_Vector cubic_control[4];
6497 if(buflen == 0) buf = NULL;
6499 if (needsTransform && buf) {
6500 pFT_Outline_Transform(outline, &transMat);
6503 for(contour = 0; contour < outline->n_contours; contour++) {
6504 pph_start = needed;
6505 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6506 first_pt = point;
6507 if(buf) {
6508 pph->dwType = TT_POLYGON_TYPE;
6509 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6511 needed += sizeof(*pph);
6512 point++;
6513 while(point <= outline->contours[contour]) {
6514 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6515 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6516 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6517 cpfx = 0;
6518 do {
6519 if(type == TT_PRIM_LINE) {
6520 if(buf)
6521 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6522 cpfx++;
6523 point++;
6524 } else {
6525 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6526 so cpfx = 3n */
6528 /* FIXME: Possible optimization in endpoint calculation
6529 if there are two consecutive curves */
6530 cubic_control[0] = outline->points[point-1];
6531 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6532 cubic_control[0].x += outline->points[point].x + 1;
6533 cubic_control[0].y += outline->points[point].y + 1;
6534 cubic_control[0].x >>= 1;
6535 cubic_control[0].y >>= 1;
6537 if(point+1 > outline->contours[contour])
6538 cubic_control[3] = outline->points[first_pt];
6539 else {
6540 cubic_control[3] = outline->points[point+1];
6541 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6542 cubic_control[3].x += outline->points[point].x + 1;
6543 cubic_control[3].y += outline->points[point].y + 1;
6544 cubic_control[3].x >>= 1;
6545 cubic_control[3].y >>= 1;
6548 /* r1 = 1/3 p0 + 2/3 p1
6549 r2 = 1/3 p2 + 2/3 p1 */
6550 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6551 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6552 cubic_control[2] = cubic_control[1];
6553 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6554 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6555 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6556 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6557 if(buf) {
6558 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6559 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6560 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6562 cpfx += 3;
6563 point++;
6565 } while(point <= outline->contours[contour] &&
6566 (outline->tags[point] & FT_Curve_Tag_On) ==
6567 (outline->tags[point-1] & FT_Curve_Tag_On));
6568 /* At the end of a contour Windows adds the start point,
6569 but only for Beziers and we've already done that.
6571 if(point <= outline->contours[contour] &&
6572 outline->tags[point] & FT_Curve_Tag_On) {
6573 /* This is the closing pt of a bezier, but we've already
6574 added it, so just inc point and carry on */
6575 point++;
6577 if(buf) {
6578 ppc->wType = type;
6579 ppc->cpfx = cpfx;
6581 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6583 if(buf)
6584 pph->cb = needed - pph_start;
6586 break;
6589 default:
6590 FIXME("Unsupported format %d\n", format);
6591 return GDI_ERROR;
6593 return needed;
6596 static BOOL get_bitmap_text_metrics(GdiFont *font)
6598 FT_Face ft_face = font->ft_face;
6599 FT_WinFNT_HeaderRec winfnt_header;
6600 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6601 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6602 font->potm->otmSize = size;
6604 #define TM font->potm->otmTextMetrics
6605 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6607 TM.tmHeight = winfnt_header.pixel_height;
6608 TM.tmAscent = winfnt_header.ascent;
6609 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6610 TM.tmInternalLeading = winfnt_header.internal_leading;
6611 TM.tmExternalLeading = winfnt_header.external_leading;
6612 TM.tmAveCharWidth = winfnt_header.avg_width;
6613 TM.tmMaxCharWidth = winfnt_header.max_width;
6614 TM.tmWeight = winfnt_header.weight;
6615 TM.tmOverhang = 0;
6616 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6617 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6618 TM.tmFirstChar = winfnt_header.first_char;
6619 TM.tmLastChar = winfnt_header.last_char;
6620 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6621 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6622 TM.tmItalic = winfnt_header.italic;
6623 TM.tmUnderlined = font->underline;
6624 TM.tmStruckOut = font->strikeout;
6625 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6626 TM.tmCharSet = winfnt_header.charset;
6628 else
6630 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6631 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6632 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6633 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6634 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6635 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6636 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6637 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6638 TM.tmOverhang = 0;
6639 TM.tmDigitizedAspectX = 96; /* FIXME */
6640 TM.tmDigitizedAspectY = 96; /* FIXME */
6641 TM.tmFirstChar = 1;
6642 TM.tmLastChar = 255;
6643 TM.tmDefaultChar = 32;
6644 TM.tmBreakChar = 32;
6645 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6646 TM.tmUnderlined = font->underline;
6647 TM.tmStruckOut = font->strikeout;
6648 /* NB inverted meaning of TMPF_FIXED_PITCH */
6649 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6650 TM.tmCharSet = font->charset;
6652 #undef TM
6654 return TRUE;
6658 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6660 double scale_x, scale_y;
6662 if (font->aveWidth)
6664 scale_x = (double)font->aveWidth;
6665 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6667 else
6668 scale_x = font->scale_y;
6670 scale_x *= fabs(font->font_desc.matrix.eM11);
6671 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6673 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6674 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6676 SCALE_Y(ptm->tmHeight);
6677 SCALE_Y(ptm->tmAscent);
6678 SCALE_Y(ptm->tmDescent);
6679 SCALE_Y(ptm->tmInternalLeading);
6680 SCALE_Y(ptm->tmExternalLeading);
6681 SCALE_Y(ptm->tmOverhang);
6683 SCALE_X(ptm->tmAveCharWidth);
6684 SCALE_X(ptm->tmMaxCharWidth);
6686 #undef SCALE_X
6687 #undef SCALE_Y
6690 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6692 double scale_x, scale_y;
6694 if (font->aveWidth)
6696 scale_x = (double)font->aveWidth;
6697 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6699 else
6700 scale_x = font->scale_y;
6702 scale_x *= fabs(font->font_desc.matrix.eM11);
6703 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6705 scale_font_metrics(font, &potm->otmTextMetrics);
6707 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6708 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6710 SCALE_Y(potm->otmAscent);
6711 SCALE_Y(potm->otmDescent);
6712 SCALE_Y(potm->otmLineGap);
6713 SCALE_Y(potm->otmsCapEmHeight);
6714 SCALE_Y(potm->otmsXHeight);
6715 SCALE_Y(potm->otmrcFontBox.top);
6716 SCALE_Y(potm->otmrcFontBox.bottom);
6717 SCALE_X(potm->otmrcFontBox.left);
6718 SCALE_X(potm->otmrcFontBox.right);
6719 SCALE_Y(potm->otmMacAscent);
6720 SCALE_Y(potm->otmMacDescent);
6721 SCALE_Y(potm->otmMacLineGap);
6722 SCALE_X(potm->otmptSubscriptSize.x);
6723 SCALE_Y(potm->otmptSubscriptSize.y);
6724 SCALE_X(potm->otmptSubscriptOffset.x);
6725 SCALE_Y(potm->otmptSubscriptOffset.y);
6726 SCALE_X(potm->otmptSuperscriptSize.x);
6727 SCALE_Y(potm->otmptSuperscriptSize.y);
6728 SCALE_X(potm->otmptSuperscriptOffset.x);
6729 SCALE_Y(potm->otmptSuperscriptOffset.y);
6730 SCALE_Y(potm->otmsStrikeoutSize);
6731 SCALE_Y(potm->otmsStrikeoutPosition);
6732 SCALE_Y(potm->otmsUnderscoreSize);
6733 SCALE_Y(potm->otmsUnderscorePosition);
6735 #undef SCALE_X
6736 #undef SCALE_Y
6739 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6741 if(!font->potm)
6743 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6745 /* Make sure that the font has sane width/height ratio */
6746 if (font->aveWidth)
6748 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6750 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6751 font->aveWidth = 0;
6755 *ptm = font->potm->otmTextMetrics;
6756 scale_font_metrics(font, ptm);
6757 return TRUE;
6760 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6762 int i;
6764 for(i = 0; i < ft_face->num_charmaps; i++)
6766 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6767 return TRUE;
6769 return FALSE;
6772 static BOOL get_outline_text_metrics(GdiFont *font)
6774 BOOL ret = FALSE;
6775 FT_Face ft_face = font->ft_face;
6776 UINT needed, lenfam, lensty, lenface, lenfull;
6777 TT_OS2 *pOS2;
6778 TT_HoriHeader *pHori;
6779 TT_Postscript *pPost;
6780 FT_Fixed em_scale;
6781 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6782 char *cp;
6783 INT ascent, descent;
6785 TRACE("font=%p\n", font);
6787 if(!FT_IS_SCALABLE(ft_face))
6788 return FALSE;
6790 needed = sizeof(*font->potm);
6792 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6793 family_nameW = strdupW(font->name);
6795 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6796 if (!style_nameW)
6797 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6798 if (!style_nameW)
6800 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6801 style_nameW = towstr( CP_ACP, ft_face->style_name );
6803 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6805 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6806 if (!face_nameW)
6807 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6808 if (!face_nameW)
6810 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6811 face_nameW = strdupW(font->name);
6813 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6814 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6816 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6817 if (!full_nameW)
6818 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6819 if (!full_nameW)
6821 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6822 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6823 full_nameW = strdupW(fake_nameW);
6825 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6827 /* These names should be read from the TT name table */
6829 /* length of otmpFamilyName */
6830 needed += lenfam;
6832 /* length of otmpFaceName */
6833 needed += lenface;
6835 /* length of otmpStyleName */
6836 needed += lensty;
6838 /* length of otmpFullName */
6839 needed += lenfull;
6842 em_scale = (FT_Fixed)MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
6844 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6845 if(!pOS2) {
6846 FIXME("Can't find OS/2 table - not TT font?\n");
6847 goto end;
6850 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6851 if(!pHori) {
6852 FIXME("Can't find HHEA table - not TT font?\n");
6853 goto end;
6856 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6858 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",
6859 pOS2->usWinAscent, pOS2->usWinDescent,
6860 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6861 pOS2->xAvgCharWidth,
6862 ft_face->ascender, ft_face->descender, ft_face->height,
6863 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6864 ft_face->bbox.yMax, ft_face->bbox.yMin);
6866 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6867 font->potm->otmSize = needed;
6869 #define TM font->potm->otmTextMetrics
6871 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6872 ascent = pHori->Ascender;
6873 descent = -pHori->Descender;
6874 } else {
6875 ascent = pOS2->usWinAscent;
6876 descent = pOS2->usWinDescent;
6879 font->ntmCellHeight = ascent + descent;
6880 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6882 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
6883 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
6885 if(font->yMax) {
6886 TM.tmAscent = font->yMax;
6887 TM.tmDescent = -font->yMin;
6888 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6889 } else {
6890 TM.tmAscent = SCALE_Y(ascent);
6891 TM.tmDescent = SCALE_Y(descent);
6892 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
6895 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6897 /* MSDN says:
6898 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6900 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
6901 ((ascent + descent) -
6902 (pHori->Ascender - pHori->Descender))));
6904 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
6905 if (TM.tmAveCharWidth == 0) {
6906 TM.tmAveCharWidth = 1;
6908 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
6909 TM.tmWeight = FW_REGULAR;
6910 if (font->fake_bold)
6911 TM.tmWeight = FW_BOLD;
6912 else
6914 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6916 if (pOS2->usWeightClass > FW_MEDIUM)
6917 TM.tmWeight = pOS2->usWeightClass;
6919 else if (pOS2->usWeightClass <= FW_MEDIUM)
6920 TM.tmWeight = pOS2->usWeightClass;
6922 TM.tmOverhang = 0;
6923 TM.tmDigitizedAspectX = 96; /* FIXME */
6924 TM.tmDigitizedAspectY = 96; /* FIXME */
6925 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6926 * symbol range to 0 - f0ff
6929 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6931 TM.tmFirstChar = 0;
6932 switch(GetACP())
6934 case 1257: /* Baltic */
6935 TM.tmLastChar = 0xf8fd;
6936 break;
6937 default:
6938 TM.tmLastChar = 0xf0ff;
6940 TM.tmBreakChar = 0x20;
6941 TM.tmDefaultChar = 0x1f;
6943 else
6945 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6946 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6948 if(pOS2->usFirstCharIndex <= 1)
6949 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6950 else if (pOS2->usFirstCharIndex > 0xff)
6951 TM.tmBreakChar = 0x20;
6952 else
6953 TM.tmBreakChar = pOS2->usFirstCharIndex;
6954 TM.tmDefaultChar = TM.tmBreakChar - 1;
6956 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6957 TM.tmUnderlined = font->underline;
6958 TM.tmStruckOut = font->strikeout;
6960 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6961 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6962 (pOS2->version == 0xFFFFU ||
6963 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6964 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6965 else
6966 TM.tmPitchAndFamily = 0;
6968 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6970 case PAN_FAMILY_SCRIPT:
6971 TM.tmPitchAndFamily |= FF_SCRIPT;
6972 break;
6974 case PAN_FAMILY_DECORATIVE:
6975 TM.tmPitchAndFamily |= FF_DECORATIVE;
6976 break;
6978 case PAN_ANY:
6979 case PAN_NO_FIT:
6980 case PAN_FAMILY_TEXT_DISPLAY:
6981 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6982 /* which is clearly not what the panose spec says. */
6983 default:
6984 if(TM.tmPitchAndFamily == 0 || /* fixed */
6985 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6986 TM.tmPitchAndFamily = FF_MODERN;
6987 else
6989 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6991 case PAN_ANY:
6992 case PAN_NO_FIT:
6993 default:
6994 TM.tmPitchAndFamily |= FF_DONTCARE;
6995 break;
6997 case PAN_SERIF_COVE:
6998 case PAN_SERIF_OBTUSE_COVE:
6999 case PAN_SERIF_SQUARE_COVE:
7000 case PAN_SERIF_OBTUSE_SQUARE_COVE:
7001 case PAN_SERIF_SQUARE:
7002 case PAN_SERIF_THIN:
7003 case PAN_SERIF_BONE:
7004 case PAN_SERIF_EXAGGERATED:
7005 case PAN_SERIF_TRIANGLE:
7006 TM.tmPitchAndFamily |= FF_ROMAN;
7007 break;
7009 case PAN_SERIF_NORMAL_SANS:
7010 case PAN_SERIF_OBTUSE_SANS:
7011 case PAN_SERIF_PERP_SANS:
7012 case PAN_SERIF_FLARED:
7013 case PAN_SERIF_ROUNDED:
7014 TM.tmPitchAndFamily |= FF_SWISS;
7015 break;
7018 break;
7021 if(FT_IS_SCALABLE(ft_face))
7022 TM.tmPitchAndFamily |= TMPF_VECTOR;
7024 if(FT_IS_SFNT(ft_face))
7026 if (font->ntmFlags & NTM_PS_OPENTYPE)
7027 TM.tmPitchAndFamily |= TMPF_DEVICE;
7028 else
7029 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
7032 TM.tmCharSet = font->charset;
7034 font->potm->otmFiller = 0;
7035 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
7036 font->potm->otmfsSelection = pOS2->fsSelection;
7037 font->potm->otmfsType = pOS2->fsType;
7038 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
7039 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
7040 font->potm->otmItalicAngle = 0; /* POST table */
7041 font->potm->otmEMSquare = ft_face->units_per_EM;
7042 font->potm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
7043 font->potm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
7044 font->potm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
7045 font->potm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
7046 font->potm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
7047 font->potm->otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
7048 font->potm->otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
7049 font->potm->otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
7050 font->potm->otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
7051 font->potm->otmMacAscent = TM.tmAscent;
7052 font->potm->otmMacDescent = -TM.tmDescent;
7053 font->potm->otmMacLineGap = font->potm->otmLineGap;
7054 font->potm->otmusMinimumPPEM = 0; /* TT Header */
7055 font->potm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
7056 font->potm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
7057 font->potm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
7058 font->potm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
7059 font->potm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
7060 font->potm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
7061 font->potm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
7062 font->potm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
7063 font->potm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
7064 font->potm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
7065 if(!pPost) {
7066 font->potm->otmsUnderscoreSize = 0;
7067 font->potm->otmsUnderscorePosition = 0;
7068 } else {
7069 font->potm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
7070 font->potm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
7072 #undef SCALE_X
7073 #undef SCALE_Y
7074 #undef TM
7076 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7077 cp = (char*)font->potm + sizeof(*font->potm);
7078 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
7079 strcpyW((WCHAR*)cp, family_nameW);
7080 cp += lenfam;
7081 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
7082 strcpyW((WCHAR*)cp, style_nameW);
7083 cp += lensty;
7084 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
7085 strcpyW((WCHAR*)cp, face_nameW);
7086 cp += lenface;
7087 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
7088 strcpyW((WCHAR*)cp, full_nameW);
7089 ret = TRUE;
7091 end:
7092 HeapFree(GetProcessHeap(), 0, style_nameW);
7093 HeapFree(GetProcessHeap(), 0, family_nameW);
7094 HeapFree(GetProcessHeap(), 0, face_nameW);
7095 HeapFree(GetProcessHeap(), 0, full_nameW);
7096 return ret;
7099 /*************************************************************
7100 * freetype_GetGlyphOutline
7102 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
7103 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
7105 struct freetype_physdev *physdev = get_freetype_dev( dev );
7106 DWORD ret;
7107 ABC abc;
7109 if (!physdev->font)
7111 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
7112 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
7115 GDI_CheckNotLock();
7116 EnterCriticalSection( &freetype_cs );
7117 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
7118 LeaveCriticalSection( &freetype_cs );
7119 return ret;
7122 /*************************************************************
7123 * freetype_GetTextMetrics
7125 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
7127 struct freetype_physdev *physdev = get_freetype_dev( dev );
7128 BOOL ret;
7130 if (!physdev->font)
7132 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
7133 return dev->funcs->pGetTextMetrics( dev, metrics );
7136 GDI_CheckNotLock();
7137 EnterCriticalSection( &freetype_cs );
7138 ret = get_text_metrics( physdev->font, metrics );
7139 LeaveCriticalSection( &freetype_cs );
7140 return ret;
7143 /*************************************************************
7144 * freetype_GetOutlineTextMetrics
7146 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
7148 struct freetype_physdev *physdev = get_freetype_dev( dev );
7149 UINT ret = 0;
7151 if (!physdev->font)
7153 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
7154 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
7157 TRACE("font=%p\n", physdev->font);
7159 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
7161 GDI_CheckNotLock();
7162 EnterCriticalSection( &freetype_cs );
7164 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
7166 if(cbSize >= physdev->font->potm->otmSize)
7168 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
7169 scale_outline_font_metrics(physdev->font, potm);
7171 ret = physdev->font->potm->otmSize;
7173 LeaveCriticalSection( &freetype_cs );
7174 return ret;
7177 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7179 child->font = alloc_font();
7180 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7181 if(!child->font->ft_face)
7183 free_font(child->font);
7184 child->font = NULL;
7185 return FALSE;
7188 child->font->font_desc = font->font_desc;
7189 child->font->ntmFlags = child->face->ntmFlags;
7190 child->font->orientation = font->orientation;
7191 child->font->scale_y = font->scale_y;
7192 child->font->name = strdupW(child->face->family->FamilyName);
7193 child->font->base_font = font;
7194 TRACE("created child font %p for base %p\n", child->font, font);
7195 return TRUE;
7198 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7200 FT_UInt g;
7201 CHILD_FONT *child_font;
7203 if(font->base_font)
7204 font = font->base_font;
7206 *linked_font = font;
7208 if((*glyph = get_glyph_index(font, c)))
7210 *glyph = get_GSUB_vert_glyph(font, *glyph);
7211 return TRUE;
7214 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7216 if(!child_font->font)
7217 if(!load_child_font(font, child_font))
7218 continue;
7220 if(!child_font->font->ft_face)
7221 continue;
7222 g = get_glyph_index(child_font->font, c);
7223 g = get_GSUB_vert_glyph(child_font->font, g);
7224 if(g)
7226 *glyph = g;
7227 *linked_font = child_font->font;
7228 return TRUE;
7231 return FALSE;
7234 /*************************************************************
7235 * freetype_GetCharWidth
7237 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7239 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7240 UINT c;
7241 GLYPHMETRICS gm;
7242 ABC abc;
7243 struct freetype_physdev *physdev = get_freetype_dev( dev );
7245 if (!physdev->font)
7247 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7248 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7251 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7253 GDI_CheckNotLock();
7254 EnterCriticalSection( &freetype_cs );
7255 for(c = firstChar; c <= lastChar; c++) {
7256 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7257 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7259 LeaveCriticalSection( &freetype_cs );
7260 return TRUE;
7263 /*************************************************************
7264 * freetype_GetCharABCWidths
7266 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7268 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7269 UINT c;
7270 GLYPHMETRICS gm;
7271 struct freetype_physdev *physdev = get_freetype_dev( dev );
7273 if (!physdev->font)
7275 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7276 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7279 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7281 GDI_CheckNotLock();
7282 EnterCriticalSection( &freetype_cs );
7284 for(c = firstChar; c <= lastChar; c++, buffer++)
7285 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7287 LeaveCriticalSection( &freetype_cs );
7288 return TRUE;
7291 /*************************************************************
7292 * freetype_GetCharABCWidthsI
7294 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7296 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7297 UINT c;
7298 GLYPHMETRICS gm;
7299 struct freetype_physdev *physdev = get_freetype_dev( dev );
7301 if (!physdev->font)
7303 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7304 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7307 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7308 return FALSE;
7310 GDI_CheckNotLock();
7311 EnterCriticalSection( &freetype_cs );
7313 for(c = 0; c < count; c++, buffer++)
7314 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7315 &gm, buffer, 0, NULL, &identity );
7317 LeaveCriticalSection( &freetype_cs );
7318 return TRUE;
7321 /*************************************************************
7322 * freetype_GetTextExtentExPoint
7324 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7326 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7327 INT idx, pos;
7328 ABC abc;
7329 GLYPHMETRICS gm;
7330 struct freetype_physdev *physdev = get_freetype_dev( dev );
7332 if (!physdev->font)
7334 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7335 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7338 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7340 GDI_CheckNotLock();
7341 EnterCriticalSection( &freetype_cs );
7343 for (idx = pos = 0; idx < count; idx++)
7345 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7346 pos += abc.abcA + abc.abcB + abc.abcC;
7347 dxs[idx] = pos;
7350 LeaveCriticalSection( &freetype_cs );
7351 return TRUE;
7354 /*************************************************************
7355 * freetype_GetTextExtentExPointI
7357 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7359 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7360 INT idx, pos;
7361 ABC abc;
7362 GLYPHMETRICS gm;
7363 struct freetype_physdev *physdev = get_freetype_dev( dev );
7365 if (!physdev->font)
7367 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7368 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7371 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7373 GDI_CheckNotLock();
7374 EnterCriticalSection( &freetype_cs );
7376 for (idx = pos = 0; idx < count; idx++)
7378 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7379 &gm, &abc, 0, NULL, &identity );
7380 pos += abc.abcA + abc.abcB + abc.abcC;
7381 dxs[idx] = pos;
7384 LeaveCriticalSection( &freetype_cs );
7385 return TRUE;
7388 /*************************************************************
7389 * freetype_GetFontData
7391 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7393 struct freetype_physdev *physdev = get_freetype_dev( dev );
7395 if (!physdev->font)
7397 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7398 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7401 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7402 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7403 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7405 return get_font_data( physdev->font, table, offset, buf, cbData );
7408 /*************************************************************
7409 * freetype_GetTextFace
7411 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7413 INT n;
7414 struct freetype_physdev *physdev = get_freetype_dev( dev );
7416 if (!physdev->font)
7418 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7419 return dev->funcs->pGetTextFace( dev, count, str );
7422 n = strlenW(physdev->font->name) + 1;
7423 if (str)
7425 lstrcpynW(str, physdev->font->name, count);
7426 n = min(count, n);
7428 return n;
7431 /*************************************************************
7432 * freetype_GetTextCharsetInfo
7434 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7436 struct freetype_physdev *physdev = get_freetype_dev( dev );
7438 if (!physdev->font)
7440 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7441 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7443 if (fs) *fs = physdev->font->fs;
7444 return physdev->font->charset;
7447 /* Retrieve a list of supported Unicode ranges for a given font.
7448 * Can be called with NULL gs to calculate the buffer size. Returns
7449 * the number of ranges found.
7451 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7453 DWORD num_ranges = 0;
7455 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7457 FT_UInt glyph_code;
7458 FT_ULong char_code, char_code_prev;
7460 glyph_code = 0;
7461 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7463 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7464 face->num_glyphs, glyph_code, char_code);
7466 if (!glyph_code) return 0;
7468 if (gs)
7470 gs->ranges[0].wcLow = (USHORT)char_code;
7471 gs->ranges[0].cGlyphs = 0;
7472 gs->cGlyphsSupported = 0;
7475 num_ranges = 1;
7476 while (glyph_code)
7478 if (char_code < char_code_prev)
7480 ERR("expected increasing char code from FT_Get_Next_Char\n");
7481 return 0;
7483 if (char_code - char_code_prev > 1)
7485 num_ranges++;
7486 if (gs)
7488 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7489 gs->ranges[num_ranges - 1].cGlyphs = 1;
7490 gs->cGlyphsSupported++;
7493 else if (gs)
7495 gs->ranges[num_ranges - 1].cGlyphs++;
7496 gs->cGlyphsSupported++;
7498 char_code_prev = char_code;
7499 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7502 else
7503 FIXME("encoding %u not supported\n", face->charmap->encoding);
7505 return num_ranges;
7508 /*************************************************************
7509 * freetype_GetFontUnicodeRanges
7511 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7513 struct freetype_physdev *physdev = get_freetype_dev( dev );
7514 DWORD size, num_ranges;
7516 if (!physdev->font)
7518 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7519 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7522 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7523 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7524 if (glyphset)
7526 glyphset->cbThis = size;
7527 glyphset->cRanges = num_ranges;
7528 glyphset->flAccel = 0;
7530 return size;
7533 /*************************************************************
7534 * freetype_FontIsLinked
7536 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7538 struct freetype_physdev *physdev = get_freetype_dev( dev );
7539 BOOL ret;
7541 if (!physdev->font)
7543 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7544 return dev->funcs->pFontIsLinked( dev );
7547 GDI_CheckNotLock();
7548 EnterCriticalSection( &freetype_cs );
7549 ret = !list_empty(&physdev->font->child_fonts);
7550 LeaveCriticalSection( &freetype_cs );
7551 return ret;
7554 /*************************************************************************
7555 * GetRasterizerCaps (GDI32.@)
7557 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7559 lprs->nSize = sizeof(RASTERIZER_STATUS);
7560 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7561 lprs->nLanguageID = 0;
7562 return TRUE;
7565 /*************************************************************
7566 * freetype_GdiRealizationInfo
7568 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7570 struct freetype_physdev *physdev = get_freetype_dev( dev );
7571 realization_info_t *info = ptr;
7573 if (!physdev->font)
7575 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7576 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7579 FIXME("(%p, %p): stub!\n", physdev->font, info);
7581 info->flags = 1;
7582 if(FT_IS_SCALABLE(physdev->font->ft_face))
7583 info->flags |= 2;
7585 info->cache_num = physdev->font->cache_num;
7586 info->unknown2 = -1;
7587 return TRUE;
7590 /*************************************************************************
7591 * Kerning support for TrueType fonts
7593 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7595 struct TT_kern_table
7597 USHORT version;
7598 USHORT nTables;
7601 struct TT_kern_subtable
7603 USHORT version;
7604 USHORT length;
7605 union
7607 USHORT word;
7608 struct
7610 USHORT horizontal : 1;
7611 USHORT minimum : 1;
7612 USHORT cross_stream: 1;
7613 USHORT override : 1;
7614 USHORT reserved1 : 4;
7615 USHORT format : 8;
7616 } bits;
7617 } coverage;
7620 struct TT_format0_kern_subtable
7622 USHORT nPairs;
7623 USHORT searchRange;
7624 USHORT entrySelector;
7625 USHORT rangeShift;
7628 struct TT_kern_pair
7630 USHORT left;
7631 USHORT right;
7632 short value;
7635 static DWORD parse_format0_kern_subtable(GdiFont *font,
7636 const struct TT_format0_kern_subtable *tt_f0_ks,
7637 const USHORT *glyph_to_char,
7638 KERNINGPAIR *kern_pair, DWORD cPairs)
7640 USHORT i, nPairs;
7641 const struct TT_kern_pair *tt_kern_pair;
7643 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7645 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7647 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7648 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7649 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7651 if (!kern_pair || !cPairs)
7652 return nPairs;
7654 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7656 nPairs = min(nPairs, cPairs);
7658 for (i = 0; i < nPairs; i++)
7660 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7661 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7662 /* this algorithm appears to better match what Windows does */
7663 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7664 if (kern_pair->iKernAmount < 0)
7666 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7667 kern_pair->iKernAmount -= font->ppem;
7669 else if (kern_pair->iKernAmount > 0)
7671 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7672 kern_pair->iKernAmount += font->ppem;
7674 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7676 TRACE("left %u right %u value %d\n",
7677 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7679 kern_pair++;
7681 TRACE("copied %u entries\n", nPairs);
7682 return nPairs;
7685 /*************************************************************
7686 * freetype_GetKerningPairs
7688 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7690 DWORD length;
7691 void *buf;
7692 const struct TT_kern_table *tt_kern_table;
7693 const struct TT_kern_subtable *tt_kern_subtable;
7694 USHORT i, nTables;
7695 USHORT *glyph_to_char;
7696 GdiFont *font;
7697 struct freetype_physdev *physdev = get_freetype_dev( dev );
7699 if (!(font = physdev->font))
7701 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7702 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7705 GDI_CheckNotLock();
7706 EnterCriticalSection( &freetype_cs );
7707 if (font->total_kern_pairs != (DWORD)-1)
7709 if (cPairs && kern_pair)
7711 cPairs = min(cPairs, font->total_kern_pairs);
7712 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7714 else cPairs = font->total_kern_pairs;
7716 LeaveCriticalSection( &freetype_cs );
7717 return cPairs;
7720 font->total_kern_pairs = 0;
7722 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7724 if (length == GDI_ERROR)
7726 TRACE("no kerning data in the font\n");
7727 LeaveCriticalSection( &freetype_cs );
7728 return 0;
7731 buf = HeapAlloc(GetProcessHeap(), 0, length);
7732 if (!buf)
7734 WARN("Out of memory\n");
7735 LeaveCriticalSection( &freetype_cs );
7736 return 0;
7739 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7741 /* build a glyph index to char code map */
7742 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7743 if (!glyph_to_char)
7745 WARN("Out of memory allocating a glyph index to char code map\n");
7746 HeapFree(GetProcessHeap(), 0, buf);
7747 LeaveCriticalSection( &freetype_cs );
7748 return 0;
7751 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7753 FT_UInt glyph_code;
7754 FT_ULong char_code;
7756 glyph_code = 0;
7757 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7759 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7760 font->ft_face->num_glyphs, glyph_code, char_code);
7762 while (glyph_code)
7764 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7766 /* FIXME: This doesn't match what Windows does: it does some fancy
7767 * things with duplicate glyph index to char code mappings, while
7768 * we just avoid overriding existing entries.
7770 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7771 glyph_to_char[glyph_code] = (USHORT)char_code;
7773 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7776 else
7778 ULONG n;
7780 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7781 for (n = 0; n <= 65535; n++)
7782 glyph_to_char[n] = (USHORT)n;
7785 tt_kern_table = buf;
7786 nTables = GET_BE_WORD(tt_kern_table->nTables);
7787 TRACE("version %u, nTables %u\n",
7788 GET_BE_WORD(tt_kern_table->version), nTables);
7790 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7792 for (i = 0; i < nTables; i++)
7794 struct TT_kern_subtable tt_kern_subtable_copy;
7796 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7797 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7798 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7800 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7801 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7802 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7804 /* According to the TrueType specification this is the only format
7805 * that will be properly interpreted by Windows and OS/2
7807 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7809 DWORD new_chunk, old_total = font->total_kern_pairs;
7811 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7812 glyph_to_char, NULL, 0);
7813 font->total_kern_pairs += new_chunk;
7815 if (!font->kern_pairs)
7816 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7817 font->total_kern_pairs * sizeof(*font->kern_pairs));
7818 else
7819 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7820 font->total_kern_pairs * sizeof(*font->kern_pairs));
7822 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7823 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7825 else
7826 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7828 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7831 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7832 HeapFree(GetProcessHeap(), 0, buf);
7834 if (cPairs && kern_pair)
7836 cPairs = min(cPairs, font->total_kern_pairs);
7837 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7839 else cPairs = font->total_kern_pairs;
7841 LeaveCriticalSection( &freetype_cs );
7842 return cPairs;
7845 static const struct gdi_dc_funcs freetype_funcs =
7847 NULL, /* pAbortDoc */
7848 NULL, /* pAbortPath */
7849 NULL, /* pAlphaBlend */
7850 NULL, /* pAngleArc */
7851 NULL, /* pArc */
7852 NULL, /* pArcTo */
7853 NULL, /* pBeginPath */
7854 NULL, /* pBlendImage */
7855 NULL, /* pChord */
7856 NULL, /* pCloseFigure */
7857 NULL, /* pCreateCompatibleDC */
7858 freetype_CreateDC, /* pCreateDC */
7859 freetype_DeleteDC, /* pDeleteDC */
7860 NULL, /* pDeleteObject */
7861 NULL, /* pDeviceCapabilities */
7862 NULL, /* pEllipse */
7863 NULL, /* pEndDoc */
7864 NULL, /* pEndPage */
7865 NULL, /* pEndPath */
7866 freetype_EnumFonts, /* pEnumFonts */
7867 NULL, /* pEnumICMProfiles */
7868 NULL, /* pExcludeClipRect */
7869 NULL, /* pExtDeviceMode */
7870 NULL, /* pExtEscape */
7871 NULL, /* pExtFloodFill */
7872 NULL, /* pExtSelectClipRgn */
7873 NULL, /* pExtTextOut */
7874 NULL, /* pFillPath */
7875 NULL, /* pFillRgn */
7876 NULL, /* pFlattenPath */
7877 freetype_FontIsLinked, /* pFontIsLinked */
7878 NULL, /* pFrameRgn */
7879 NULL, /* pGdiComment */
7880 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7881 NULL, /* pGetBoundsRect */
7882 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7883 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7884 freetype_GetCharWidth, /* pGetCharWidth */
7885 NULL, /* pGetDeviceCaps */
7886 NULL, /* pGetDeviceGammaRamp */
7887 freetype_GetFontData, /* pGetFontData */
7888 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7889 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7890 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7891 NULL, /* pGetICMProfile */
7892 NULL, /* pGetImage */
7893 freetype_GetKerningPairs, /* pGetKerningPairs */
7894 NULL, /* pGetNearestColor */
7895 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7896 NULL, /* pGetPixel */
7897 NULL, /* pGetSystemPaletteEntries */
7898 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7899 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7900 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7901 freetype_GetTextFace, /* pGetTextFace */
7902 freetype_GetTextMetrics, /* pGetTextMetrics */
7903 NULL, /* pGradientFill */
7904 NULL, /* pIntersectClipRect */
7905 NULL, /* pInvertRgn */
7906 NULL, /* pLineTo */
7907 NULL, /* pModifyWorldTransform */
7908 NULL, /* pMoveTo */
7909 NULL, /* pOffsetClipRgn */
7910 NULL, /* pOffsetViewportOrg */
7911 NULL, /* pOffsetWindowOrg */
7912 NULL, /* pPaintRgn */
7913 NULL, /* pPatBlt */
7914 NULL, /* pPie */
7915 NULL, /* pPolyBezier */
7916 NULL, /* pPolyBezierTo */
7917 NULL, /* pPolyDraw */
7918 NULL, /* pPolyPolygon */
7919 NULL, /* pPolyPolyline */
7920 NULL, /* pPolygon */
7921 NULL, /* pPolyline */
7922 NULL, /* pPolylineTo */
7923 NULL, /* pPutImage */
7924 NULL, /* pRealizeDefaultPalette */
7925 NULL, /* pRealizePalette */
7926 NULL, /* pRectangle */
7927 NULL, /* pResetDC */
7928 NULL, /* pRestoreDC */
7929 NULL, /* pRoundRect */
7930 NULL, /* pSaveDC */
7931 NULL, /* pScaleViewportExt */
7932 NULL, /* pScaleWindowExt */
7933 NULL, /* pSelectBitmap */
7934 NULL, /* pSelectBrush */
7935 NULL, /* pSelectClipPath */
7936 freetype_SelectFont, /* pSelectFont */
7937 NULL, /* pSelectPalette */
7938 NULL, /* pSelectPen */
7939 NULL, /* pSetArcDirection */
7940 NULL, /* pSetBkColor */
7941 NULL, /* pSetBkMode */
7942 NULL, /* pSetDCBrushColor */
7943 NULL, /* pSetDCPenColor */
7944 NULL, /* pSetDIBColorTable */
7945 NULL, /* pSetDIBitsToDevice */
7946 NULL, /* pSetDeviceClipping */
7947 NULL, /* pSetDeviceGammaRamp */
7948 NULL, /* pSetLayout */
7949 NULL, /* pSetMapMode */
7950 NULL, /* pSetMapperFlags */
7951 NULL, /* pSetPixel */
7952 NULL, /* pSetPolyFillMode */
7953 NULL, /* pSetROP2 */
7954 NULL, /* pSetRelAbs */
7955 NULL, /* pSetStretchBltMode */
7956 NULL, /* pSetTextAlign */
7957 NULL, /* pSetTextCharacterExtra */
7958 NULL, /* pSetTextColor */
7959 NULL, /* pSetTextJustification */
7960 NULL, /* pSetViewportExt */
7961 NULL, /* pSetViewportOrg */
7962 NULL, /* pSetWindowExt */
7963 NULL, /* pSetWindowOrg */
7964 NULL, /* pSetWorldTransform */
7965 NULL, /* pStartDoc */
7966 NULL, /* pStartPage */
7967 NULL, /* pStretchBlt */
7968 NULL, /* pStretchDIBits */
7969 NULL, /* pStrokeAndFillPath */
7970 NULL, /* pStrokePath */
7971 NULL, /* pUnrealizePalette */
7972 NULL, /* pWidenPath */
7973 NULL, /* wine_get_wgl_driver */
7974 GDI_PRIORITY_FONT_DRV /* priority */
7977 #else /* HAVE_FREETYPE */
7979 /*************************************************************************/
7981 BOOL WineEngInit(void)
7983 return FALSE;
7986 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7988 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7989 return 1;
7992 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7994 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7995 return TRUE;
7998 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
8000 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
8001 return NULL;
8004 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
8005 LPCWSTR font_file, LPCWSTR font_path )
8007 FIXME("stub\n");
8008 return FALSE;
8011 /*************************************************************************
8012 * GetRasterizerCaps (GDI32.@)
8014 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
8016 lprs->nSize = sizeof(RASTERIZER_STATUS);
8017 lprs->wFlags = 0;
8018 lprs->nLanguageID = 0;
8019 return TRUE;
8022 #endif /* HAVE_FREETYPE */