gdi32: Add a GetBoundsRect driver entry point.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob3875e4fb10db33c0bcb3b01889cb658d556a2956
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(FcConfigGetCurrent);
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(FcPatternGetString);
205 #endif
207 #undef MAKE_FUNCPTR
209 #ifndef FT_MAKE_TAG
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
213 #endif
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
217 #endif
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
220 #endif
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
223 #endif
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
226 #endif
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
230 #else
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
232 #endif
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
235 typedef struct {
236 FT_Short height;
237 FT_Short width;
238 FT_Pos size;
239 FT_Pos x_ppem;
240 FT_Pos y_ppem;
241 FT_Short internal_leading;
242 } Bitmap_Size;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
247 typedef struct {
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
250 } My_FT_Bitmap_Size;
252 struct enum_data
254 ENUMLOGFONTEXW elf;
255 NEWTEXTMETRICEXW ntm;
256 DWORD type;
259 typedef struct tagFace {
260 struct list entry;
261 WCHAR *StyleName;
262 WCHAR *FullName;
263 char *file;
264 void *font_data_ptr;
265 DWORD font_data_size;
266 FT_Long face_index;
267 FONTSIGNATURE fs;
268 DWORD ntmFlags;
269 FT_Fixed font_version;
270 BOOL scalable;
271 BOOL vertical;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
277 } Face;
279 typedef struct tagFamily {
280 struct list entry;
281 WCHAR *FamilyName;
282 WCHAR *EnglishName;
283 struct list faces;
284 struct list *replacement;
285 } Family;
287 typedef struct {
288 GLYPHMETRICS gm;
289 INT adv; /* These three hold to widths of the unrotated chars */
290 INT lsb;
291 INT bbx;
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct {
313 struct list entry;
314 Face *face;
315 GdiFont *font;
316 } CHILD_FONT;
318 struct tagGdiFont {
319 struct list entry;
320 GM **gm;
321 DWORD gmsize;
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
329 FT_Face ft_face;
330 struct font_mapping *mapping;
331 LPWSTR name;
332 int charset;
333 int codepage;
334 BOOL fake_italic;
335 BOOL fake_bold;
336 BYTE underline;
337 BYTE strikeout;
338 INT orientation;
339 FONT_DESC font_desc;
340 LONG aveWidth, ppem;
341 double scale_y;
342 SHORT yMax;
343 SHORT yMin;
344 DWORD ntmFlags;
345 FONTSIGNATURE fs;
346 GdiFont *base_font;
347 VOID *GSUB_Table;
348 DWORD cache_num;
351 typedef struct {
352 struct list entry;
353 const WCHAR *font_name;
354 FONTSIGNATURE fs;
355 struct list links;
356 } SYSTEM_LINKS;
358 struct enum_charset_element {
359 DWORD mask;
360 DWORD charset;
361 WCHAR name[LF_FACESIZE];
364 struct enum_charset_list {
365 DWORD total;
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 struct freetype_physdev
384 struct gdi_physdev dev;
385 GdiFont *font;
388 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
390 return (struct freetype_physdev *)dev;
393 static const struct gdi_dc_funcs freetype_funcs;
395 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR * const SystemFontValues[] = {
416 System_Value,
417 OEMFont_Value,
418 FixedSys_Value,
419 NULL
422 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 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 };
428 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 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};
438 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};
439 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR *default_serif_list[] =
448 times_new_roman,
449 liberation_serif,
450 bitstream_vera_serif,
451 NULL
454 static const WCHAR *default_fixed_list[] =
456 courier_new,
457 liberation_mono,
458 bitstream_vera_sans_mono,
459 NULL
462 static const WCHAR *default_sans_list[] =
464 arial,
465 liberation_sans,
466 bitstream_vera_sans,
467 NULL
470 typedef struct {
471 WCHAR *name;
472 INT charset;
473 } NameCs;
475 typedef struct tagFontSubst {
476 struct list entry;
477 NameCs from;
478 NameCs to;
479 } FontSubst;
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
487 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
488 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
489 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','a','l',0};
490 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
491 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
492 static const WCHAR face_size_value[] = {'S','i','z','e',0};
493 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
494 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
495 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
496 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
497 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
500 struct font_mapping
502 struct list entry;
503 int refcount;
504 dev_t dev;
505 ino_t ino;
506 void *data;
507 size_t size;
510 static struct list mappings_list = LIST_INIT( mappings_list );
512 static CRITICAL_SECTION freetype_cs;
513 static CRITICAL_SECTION_DEBUG critsect_debug =
515 0, 0, &freetype_cs,
516 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
517 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
519 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
521 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
523 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
524 static BOOL use_default_fallback = FALSE;
526 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
527 static BOOL get_outline_text_metrics(GdiFont *font);
528 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
530 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
531 'W','i','n','d','o','w','s',' ','N','T','\\',
532 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
533 'S','y','s','t','e','m','L','i','n','k',0};
535 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
536 'F','o','n','t','L','i','n','k','\\',
537 'S','y','s','t','e','m','L','i','n','k',0};
539 /****************************************
540 * Notes on .fon files
542 * The fonts System, FixedSys and Terminal are special. There are typically multiple
543 * versions installed for different resolutions and codepages. Windows stores which one to use
544 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
545 * Key Meaning
546 * FIXEDFON.FON FixedSys
547 * FONTS.FON System
548 * OEMFONT.FON Terminal
549 * LogPixels Current dpi set by the display control panel applet
550 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
551 * also has a LogPixels value that appears to mirror this)
553 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
554 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
555 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
556 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
557 * so that makes sense.
559 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
560 * to be mapped into the registry on Windows 2000 at least).
561 * I have
562 * woafont=app850.fon
563 * ega80woa.fon=ega80850.fon
564 * ega40woa.fon=ega40850.fon
565 * cga80woa.fon=cga80850.fon
566 * cga40woa.fon=cga40850.fon
569 /* These are all structures needed for the GSUB table */
571 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
572 #define TATEGAKI_LOWER_BOUND 0x02F1
574 typedef struct {
575 DWORD version;
576 WORD ScriptList;
577 WORD FeatureList;
578 WORD LookupList;
579 } GSUB_Header;
581 typedef struct {
582 CHAR ScriptTag[4];
583 WORD Script;
584 } GSUB_ScriptRecord;
586 typedef struct {
587 WORD ScriptCount;
588 GSUB_ScriptRecord ScriptRecord[1];
589 } GSUB_ScriptList;
591 typedef struct {
592 CHAR LangSysTag[4];
593 WORD LangSys;
594 } GSUB_LangSysRecord;
596 typedef struct {
597 WORD DefaultLangSys;
598 WORD LangSysCount;
599 GSUB_LangSysRecord LangSysRecord[1];
600 } GSUB_Script;
602 typedef struct {
603 WORD LookupOrder; /* Reserved */
604 WORD ReqFeatureIndex;
605 WORD FeatureCount;
606 WORD FeatureIndex[1];
607 } GSUB_LangSys;
609 typedef struct {
610 CHAR FeatureTag[4];
611 WORD Feature;
612 } GSUB_FeatureRecord;
614 typedef struct {
615 WORD FeatureCount;
616 GSUB_FeatureRecord FeatureRecord[1];
617 } GSUB_FeatureList;
619 typedef struct {
620 WORD FeatureParams; /* Reserved */
621 WORD LookupCount;
622 WORD LookupListIndex[1];
623 } GSUB_Feature;
625 typedef struct {
626 WORD LookupCount;
627 WORD Lookup[1];
628 } GSUB_LookupList;
630 typedef struct {
631 WORD LookupType;
632 WORD LookupFlag;
633 WORD SubTableCount;
634 WORD SubTable[1];
635 } GSUB_LookupTable;
637 typedef struct {
638 WORD CoverageFormat;
639 WORD GlyphCount;
640 WORD GlyphArray[1];
641 } GSUB_CoverageFormat1;
643 typedef struct {
644 WORD Start;
645 WORD End;
646 WORD StartCoverageIndex;
647 } GSUB_RangeRecord;
649 typedef struct {
650 WORD CoverageFormat;
651 WORD RangeCount;
652 GSUB_RangeRecord RangeRecord[1];
653 } GSUB_CoverageFormat2;
655 typedef struct {
656 WORD SubstFormat; /* = 1 */
657 WORD Coverage;
658 WORD DeltaGlyphID;
659 } GSUB_SingleSubstFormat1;
661 typedef struct {
662 WORD SubstFormat; /* = 2 */
663 WORD Coverage;
664 WORD GlyphCount;
665 WORD Substitute[1];
666 }GSUB_SingleSubstFormat2;
668 #ifdef HAVE_CARBON_CARBON_H
669 static char *find_cache_dir(void)
671 FSRef ref;
672 OSErr err;
673 static char cached_path[MAX_PATH];
674 static const char *wine = "/Wine", *fonts = "/Fonts";
676 if(*cached_path) return cached_path;
678 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
679 if(err != noErr)
681 WARN("can't create cached data folder\n");
682 return NULL;
684 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
685 if(err != noErr)
687 WARN("can't create cached data path\n");
688 *cached_path = '\0';
689 return NULL;
691 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
693 ERR("Could not create full path\n");
694 *cached_path = '\0';
695 return NULL;
697 strcat(cached_path, wine);
699 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
701 WARN("Couldn't mkdir %s\n", cached_path);
702 *cached_path = '\0';
703 return NULL;
705 strcat(cached_path, fonts);
706 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
708 WARN("Couldn't mkdir %s\n", cached_path);
709 *cached_path = '\0';
710 return NULL;
712 return cached_path;
715 /******************************************************************
716 * expand_mac_font
718 * Extracts individual TrueType font files from a Mac suitcase font
719 * and saves them into the user's caches directory (see
720 * find_cache_dir()).
721 * Returns a NULL terminated array of filenames.
723 * We do this because they are apps that try to read ttf files
724 * themselves and they don't like Mac suitcase files.
726 static char **expand_mac_font(const char *path)
728 FSRef ref;
729 SInt16 res_ref;
730 OSStatus s;
731 unsigned int idx;
732 const char *out_dir;
733 const char *filename;
734 int output_len;
735 struct {
736 char **array;
737 unsigned int size, max_size;
738 } ret;
740 TRACE("path %s\n", path);
742 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
743 if(s != noErr)
745 WARN("failed to get ref\n");
746 return NULL;
749 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
750 if(s != noErr)
752 TRACE("no data fork, so trying resource fork\n");
753 res_ref = FSOpenResFile(&ref, fsRdPerm);
754 if(res_ref == -1)
756 TRACE("unable to open resource fork\n");
757 return NULL;
761 ret.size = 0;
762 ret.max_size = 10;
763 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
764 if(!ret.array)
766 CloseResFile(res_ref);
767 return NULL;
770 out_dir = find_cache_dir();
772 filename = strrchr(path, '/');
773 if(!filename) filename = path;
774 else filename++;
776 /* output filename has the form out_dir/filename_%04x.ttf */
777 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
779 UseResFile(res_ref);
780 idx = 1;
781 while(1)
783 FamRec *fam_rec;
784 unsigned short *num_faces_ptr, num_faces, face;
785 AsscEntry *assoc;
786 Handle fond;
787 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
789 fond = Get1IndResource(fond_res, idx);
790 if(!fond) break;
791 TRACE("got fond resource %d\n", idx);
792 HLock(fond);
794 fam_rec = *(FamRec**)fond;
795 num_faces_ptr = (unsigned short *)(fam_rec + 1);
796 num_faces = GET_BE_WORD(*num_faces_ptr);
797 num_faces++;
798 assoc = (AsscEntry*)(num_faces_ptr + 1);
799 TRACE("num faces %04x\n", num_faces);
800 for(face = 0; face < num_faces; face++, assoc++)
802 Handle sfnt;
803 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
804 unsigned short size, font_id;
805 char *output;
807 size = GET_BE_WORD(assoc->fontSize);
808 font_id = GET_BE_WORD(assoc->fontID);
809 if(size != 0)
811 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
812 continue;
815 TRACE("trying to load sfnt id %04x\n", font_id);
816 sfnt = GetResource(sfnt_res, font_id);
817 if(!sfnt)
819 TRACE("can't get sfnt resource %04x\n", font_id);
820 continue;
823 output = HeapAlloc(GetProcessHeap(), 0, output_len);
824 if(output)
826 int fd;
828 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
830 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
831 if(fd != -1 || errno == EEXIST)
833 if(fd != -1)
835 unsigned char *sfnt_data;
837 HLock(sfnt);
838 sfnt_data = *(unsigned char**)sfnt;
839 write(fd, sfnt_data, GetHandleSize(sfnt));
840 HUnlock(sfnt);
841 close(fd);
843 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
845 ret.max_size *= 2;
846 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
848 ret.array[ret.size++] = output;
850 else
852 WARN("unable to create %s\n", output);
853 HeapFree(GetProcessHeap(), 0, output);
856 ReleaseResource(sfnt);
858 HUnlock(fond);
859 ReleaseResource(fond);
860 idx++;
862 CloseResFile(res_ref);
864 return ret.array;
867 #endif /* HAVE_CARBON_CARBON_H */
869 static inline BOOL is_win9x(void)
871 return GetVersion() & 0x80000000;
874 This function builds an FT_Fixed from a double. It fails if the absolute
875 value of the float number is greater than 32768.
877 static inline FT_Fixed FT_FixedFromFloat(double f)
879 return f * 0x10000;
883 This function builds an FT_Fixed from a FIXED. It simply put f.value
884 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
886 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
888 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
892 static const struct list *get_face_list_from_family(const Family *family)
894 if (!list_empty(&family->faces))
895 return &family->faces;
896 else
897 return family->replacement;
900 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
902 Family *family;
903 Face *face;
904 const char *file;
905 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
906 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
908 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
909 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
911 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
913 const struct list *face_list;
914 if(face_name && strcmpiW(face_name, family->FamilyName))
915 continue;
916 face_list = get_face_list_from_family(family);
917 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
919 if (!face->file)
920 continue;
921 file = strrchr(face->file, '/');
922 if(!file)
923 file = face->file;
924 else
925 file++;
926 if(!strcasecmp(file, file_nameA))
928 HeapFree(GetProcessHeap(), 0, file_nameA);
929 return face;
933 HeapFree(GetProcessHeap(), 0, file_nameA);
934 return NULL;
937 static Family *find_family_from_name(const WCHAR *name)
939 Family *family;
941 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
943 if(!strcmpiW(family->FamilyName, name))
944 return family;
947 return NULL;
950 static Family *find_family_from_any_name(const WCHAR *name)
952 Family *family;
954 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
956 if(!strcmpiW(family->FamilyName, name))
957 return family;
958 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
959 return family;
962 return NULL;
965 static void DumpSubstList(void)
967 FontSubst *psub;
969 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
971 if(psub->from.charset != -1 || psub->to.charset != -1)
972 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
973 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
974 else
975 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
976 debugstr_w(psub->to.name));
978 return;
981 static LPWSTR strdupW(LPCWSTR p)
983 LPWSTR ret;
984 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
985 ret = HeapAlloc(GetProcessHeap(), 0, len);
986 memcpy(ret, p, len);
987 return ret;
990 static LPSTR strdupA(LPCSTR p)
992 LPSTR ret;
993 DWORD len = (strlen(p) + 1);
994 ret = HeapAlloc(GetProcessHeap(), 0, len);
995 memcpy(ret, p, len);
996 return ret;
999 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1000 INT from_charset)
1002 FontSubst *element;
1004 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1006 if(!strcmpiW(element->from.name, from_name) &&
1007 (element->from.charset == from_charset ||
1008 element->from.charset == -1))
1009 return element;
1012 return NULL;
1015 #define ADD_FONT_SUBST_FORCE 1
1017 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1019 FontSubst *from_exist, *to_exist;
1021 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1023 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1025 list_remove(&from_exist->entry);
1026 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1027 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1028 HeapFree(GetProcessHeap(), 0, from_exist);
1029 from_exist = NULL;
1032 if(!from_exist)
1034 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1036 if(to_exist)
1038 HeapFree(GetProcessHeap(), 0, subst->to.name);
1039 subst->to.name = strdupW(to_exist->to.name);
1042 list_add_tail(subst_list, &subst->entry);
1044 return TRUE;
1047 HeapFree(GetProcessHeap(), 0, subst->from.name);
1048 HeapFree(GetProcessHeap(), 0, subst->to.name);
1049 HeapFree(GetProcessHeap(), 0, subst);
1050 return FALSE;
1053 static WCHAR *towstr(UINT cp, const char *str)
1055 int len;
1056 WCHAR *wstr;
1058 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1059 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1060 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1061 return wstr;
1064 static void split_subst_info(NameCs *nc, LPSTR str)
1066 CHAR *p = strrchr(str, ',');
1068 nc->charset = -1;
1069 if(p && *(p+1)) {
1070 nc->charset = strtol(p+1, NULL, 10);
1071 *p = '\0';
1073 nc->name = towstr(CP_ACP, str);
1076 static void LoadSubstList(void)
1078 FontSubst *psub;
1079 HKEY hkey;
1080 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1081 LPSTR value;
1082 LPVOID data;
1084 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1085 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1086 &hkey) == ERROR_SUCCESS) {
1088 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1089 &valuelen, &datalen, NULL, NULL);
1091 valuelen++; /* returned value doesn't include room for '\0' */
1092 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1093 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1095 dlen = datalen;
1096 vlen = valuelen;
1097 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1098 &dlen) == ERROR_SUCCESS) {
1099 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1101 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1102 split_subst_info(&psub->from, value);
1103 split_subst_info(&psub->to, data);
1105 /* Win 2000 doesn't allow mapping between different charsets
1106 or mapping of DEFAULT_CHARSET */
1107 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1108 psub->to.charset == DEFAULT_CHARSET) {
1109 HeapFree(GetProcessHeap(), 0, psub->to.name);
1110 HeapFree(GetProcessHeap(), 0, psub->from.name);
1111 HeapFree(GetProcessHeap(), 0, psub);
1112 } else {
1113 add_font_subst(&font_subst_list, psub, 0);
1115 /* reset dlen and vlen */
1116 dlen = datalen;
1117 vlen = valuelen;
1119 HeapFree(GetProcessHeap(), 0, data);
1120 HeapFree(GetProcessHeap(), 0, value);
1121 RegCloseKey(hkey);
1126 /*****************************************************************
1127 * get_name_table_entry
1129 * Supply the platform, encoding, language and name ids in req
1130 * and if the name exists the function will fill in the string
1131 * and string_len members. The string is owned by FreeType so
1132 * don't free it. Returns TRUE if the name is found else FALSE.
1134 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1136 FT_SfntName name;
1137 FT_UInt num_names, name_index;
1139 if(FT_IS_SFNT(ft_face))
1141 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1143 for(name_index = 0; name_index < num_names; name_index++)
1145 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1147 if((name.platform_id == req->platform_id) &&
1148 (name.encoding_id == req->encoding_id) &&
1149 (name.language_id == req->language_id) &&
1150 (name.name_id == req->name_id))
1152 req->string = name.string;
1153 req->string_len = name.string_len;
1154 return TRUE;
1159 req->string = NULL;
1160 req->string_len = 0;
1161 return FALSE;
1164 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1166 WCHAR *ret = NULL;
1167 FT_SfntName name;
1169 name.platform_id = TT_PLATFORM_MICROSOFT;
1170 name.encoding_id = TT_MS_ID_UNICODE_CS;
1171 name.language_id = language_id;
1172 name.name_id = name_id;
1174 if(get_name_table_entry(ft_face, &name))
1176 FT_UInt i;
1178 /* String is not nul terminated and string_len is a byte length. */
1179 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1180 for(i = 0; i < name.string_len / 2; i++)
1182 WORD *tmp = (WORD *)&name.string[i * 2];
1183 ret[i] = GET_BE_WORD(*tmp);
1185 ret[i] = 0;
1186 TRACE("Got localised name %s\n", debugstr_w(ret));
1189 return ret;
1192 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1194 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1195 if (f1->scalable) return TRUE;
1196 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1197 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1200 static inline void free_face( Face *face )
1202 HeapFree( GetProcessHeap(), 0, face->file );
1203 HeapFree( GetProcessHeap(), 0, face->StyleName );
1204 HeapFree( GetProcessHeap(), 0, face->FullName );
1205 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1206 HeapFree( GetProcessHeap(), 0, face );
1209 static inline void free_family( Family *family )
1211 Face *face, *cursor2;
1213 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1215 list_remove( &face->entry );
1216 free_face( face );
1218 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1219 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1220 HeapFree( GetProcessHeap(), 0, family );
1223 static inline int style_order(const Face *face)
1225 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1227 case NTM_REGULAR:
1228 return 0;
1229 case NTM_BOLD:
1230 return 1;
1231 case NTM_ITALIC:
1232 return 2;
1233 case NTM_BOLD | NTM_ITALIC:
1234 return 3;
1235 default:
1236 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1237 debugstr_w(face->family->FamilyName),
1238 debugstr_w(face->StyleName),
1239 face->ntmFlags);
1240 return 9999;
1244 static BOOL insert_face_in_family_list( Face *face, Family *family )
1246 Face *cursor;
1248 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1250 if (faces_equal( face, cursor ))
1252 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1253 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1254 cursor->font_version, face->font_version);
1256 if (face->font_version <= cursor->font_version)
1258 TRACE("Original font %s is newer so skipping %s\n",
1259 debugstr_a(cursor->file), debugstr_a(face->file));
1260 return FALSE;
1262 else
1264 TRACE("Replacing original %s with %s\n",
1265 debugstr_a(cursor->file), debugstr_a(face->file));
1266 list_add_before( &cursor->entry, &face->entry );
1267 face->family = family;
1268 list_remove( &cursor->entry);
1269 free_face( cursor );
1270 return TRUE;
1273 else
1274 TRACE("Adding new %s\n", debugstr_a(face->file));
1276 if (style_order( face ) < style_order( cursor )) break;
1279 list_add_before( &cursor->entry, &face->entry );
1280 face->family = family;
1281 return TRUE;
1284 /****************************************************************
1285 * NB This function stores the ptrs to the strings to save copying.
1286 * Don't free them after calling.
1288 static Family *create_family( WCHAR *name, WCHAR *english_name )
1290 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1291 family->FamilyName = name;
1292 family->EnglishName = english_name;
1293 list_init( &family->faces );
1294 family->replacement = &family->faces;
1296 return family;
1299 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1301 DWORD type, needed;
1302 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1303 if(r != ERROR_SUCCESS) return r;
1304 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1305 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1308 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1310 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1313 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1315 DWORD needed;
1316 DWORD num_strikes, max_strike_key_len;
1318 /* If we have a File Name key then this is a real font, not just the parent
1319 key of a bunch of non-scalable strikes */
1320 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1322 Face *face;
1323 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1324 face->cached_enum_data = NULL;
1326 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1327 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1329 face->StyleName = strdupW(face_name);
1331 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1333 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1334 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1335 face->FullName = fullName;
1337 else
1338 face->FullName = NULL;
1340 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1341 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1342 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1343 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1345 needed = sizeof(face->fs);
1346 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1348 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1350 face->scalable = TRUE;
1351 memset(&face->size, 0, sizeof(face->size));
1353 else
1355 face->scalable = FALSE;
1356 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1357 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1358 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1359 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1360 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1362 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1363 face->size.height, face->size.width, face->size.size >> 6,
1364 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1367 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1368 face->fs.fsCsb[0], face->fs.fsCsb[1],
1369 face->fs.fsUsb[0], face->fs.fsUsb[1],
1370 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1372 insert_face_in_family_list(face, family);
1374 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1377 /* do we have any bitmap strikes? */
1378 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1379 NULL, NULL, NULL, NULL);
1380 if(num_strikes != 0)
1382 WCHAR strike_name[10];
1383 DWORD strike_index = 0;
1385 needed = sizeof(strike_name) / sizeof(WCHAR);
1386 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1387 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1389 HKEY hkey_strike;
1390 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1391 load_face(hkey_strike, face_name, family);
1392 RegCloseKey(hkey_strike);
1393 needed = sizeof(strike_name) / sizeof(WCHAR);
1398 static void load_font_list_from_cache(HKEY hkey_font_cache)
1400 DWORD max_family_key_len, size;
1401 WCHAR *family_name;
1402 DWORD family_index = 0;
1403 Family *family;
1404 HKEY hkey_family;
1406 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1407 NULL, NULL, NULL, NULL);
1408 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1410 size = max_family_key_len + 1;
1411 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1412 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1414 WCHAR *english_family = NULL;
1415 DWORD face_index = 0;
1416 WCHAR *face_name;
1417 DWORD max_face_key_len;
1419 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1420 TRACE("opened family key %s\n", debugstr_w(family_name));
1421 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1423 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1424 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1427 family = create_family(strdupW(family_name), english_family);
1428 list_add_tail(&font_list, &family->entry);
1430 if(english_family)
1432 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1433 subst->from.name = strdupW(english_family);
1434 subst->from.charset = -1;
1435 subst->to.name = strdupW(family_name);
1436 subst->to.charset = -1;
1437 add_font_subst(&font_subst_list, subst, 0);
1440 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1441 NULL, NULL, NULL, NULL);
1443 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1444 size = max_face_key_len + 1;
1445 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1446 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1448 HKEY hkey_face;
1450 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1451 load_face(hkey_face, face_name, family);
1452 RegCloseKey(hkey_face);
1453 size = max_face_key_len + 1;
1455 HeapFree(GetProcessHeap(), 0, face_name);
1456 RegCloseKey(hkey_family);
1457 size = max_family_key_len + 1;
1460 HeapFree(GetProcessHeap(), 0, family_name);
1463 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1465 LONG ret;
1466 HKEY hkey_wine_fonts;
1468 /* We don't want to create the fonts key as volatile, so open this first */
1469 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1470 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1471 if(ret != ERROR_SUCCESS)
1473 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1474 return ret;
1477 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1478 KEY_ALL_ACCESS, NULL, hkey, disposition);
1479 RegCloseKey(hkey_wine_fonts);
1480 return ret;
1483 static void add_face_to_cache(Face *face)
1485 HKEY hkey_font_cache, hkey_family, hkey_face;
1486 WCHAR *face_key_name;
1488 create_font_cache_key(&hkey_font_cache, NULL);
1490 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1491 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1492 if(face->family->EnglishName)
1493 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1494 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1496 if(face->scalable)
1497 face_key_name = face->StyleName;
1498 else
1500 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1501 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1502 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1504 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1505 &hkey_face, NULL);
1506 if(!face->scalable)
1507 HeapFree(GetProcessHeap(), 0, face_key_name);
1509 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1510 if (face->FullName)
1511 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1512 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1514 reg_save_dword(hkey_face, face_index_value, face->face_index);
1515 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1516 reg_save_dword(hkey_face, face_version_value, face->font_version);
1517 reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1519 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1521 if(!face->scalable)
1523 reg_save_dword(hkey_face, face_height_value, face->size.height);
1524 reg_save_dword(hkey_face, face_width_value, face->size.width);
1525 reg_save_dword(hkey_face, face_size_value, face->size.size);
1526 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1527 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1528 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1530 RegCloseKey(hkey_face);
1531 RegCloseKey(hkey_family);
1532 RegCloseKey(hkey_font_cache);
1535 static WCHAR *prepend_at(WCHAR *family)
1537 WCHAR *str;
1539 if (!family)
1540 return NULL;
1542 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1543 str[0] = '@';
1544 strcpyW(str + 1, family);
1545 HeapFree(GetProcessHeap(), 0, family);
1546 return str;
1549 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1551 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1552 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1554 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1555 if (!*name)
1557 *name = *english;
1558 *english = NULL;
1560 else if (!strcmpiW( *name, *english ))
1562 HeapFree( GetProcessHeap(), 0, *english );
1563 *english = NULL;
1566 if (vertical)
1568 *name = prepend_at( *name );
1569 *english = prepend_at( *english );
1573 static Family *get_family( FT_Face ft_face, BOOL vertical )
1575 Family *family;
1576 WCHAR *name, *english_name;
1578 get_family_names( ft_face, &name, &english_name, vertical );
1580 family = find_family_from_name( name );
1582 if (!family)
1584 family = create_family( name, english_name );
1585 list_add_tail( &font_list, &family->entry );
1587 if (english_name)
1589 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1590 subst->from.name = strdupW( english_name );
1591 subst->from.charset = -1;
1592 subst->to.name = strdupW( name );
1593 subst->to.charset = -1;
1594 add_font_subst( &font_subst_list, subst, 0 );
1597 else
1599 HeapFree( GetProcessHeap(), 0, name );
1600 HeapFree( GetProcessHeap(), 0, english_name );
1603 return family;
1606 static inline FT_Fixed get_font_version( FT_Face ft_face )
1608 FT_Fixed version = 0;
1609 TT_Header *header;
1611 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1612 if (header) version = header->Font_Revision;
1614 return version;
1617 static inline DWORD get_ntm_flags( FT_Face ft_face )
1619 DWORD flags = 0;
1620 FT_ULong table_size = 0;
1622 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1623 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1624 if (flags == 0) flags = NTM_REGULAR;
1626 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1627 flags |= NTM_PS_OPENTYPE;
1629 return flags;
1632 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1634 int internal_leading = 0;
1635 FT_WinFNT_HeaderRec winfnt_header;
1637 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1638 internal_leading = winfnt_header.internal_leading;
1640 return internal_leading;
1643 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1645 TT_OS2 *os2;
1646 FT_UInt dummy;
1647 CHARSETINFO csi;
1648 FT_WinFNT_HeaderRec winfnt_header;
1649 int i;
1651 memset( fs, 0, sizeof(*fs) );
1653 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1654 if (os2)
1656 fs->fsUsb[0] = os2->ulUnicodeRange1;
1657 fs->fsUsb[1] = os2->ulUnicodeRange2;
1658 fs->fsUsb[2] = os2->ulUnicodeRange3;
1659 fs->fsUsb[3] = os2->ulUnicodeRange4;
1661 if (os2->version == 0)
1663 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1664 fs->fsCsb[0] = FS_LATIN1;
1665 else
1666 fs->fsCsb[0] = FS_SYMBOL;
1668 else
1670 fs->fsCsb[0] = os2->ulCodePageRange1;
1671 fs->fsCsb[1] = os2->ulCodePageRange2;
1674 else
1676 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1678 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1679 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1680 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1681 *fs = csi.fs;
1685 if (fs->fsCsb[0] == 0)
1687 /* let's see if we can find any interesting cmaps */
1688 for (i = 0; i < ft_face->num_charmaps; i++)
1690 switch (ft_face->charmaps[i]->encoding)
1692 case FT_ENCODING_UNICODE:
1693 case FT_ENCODING_APPLE_ROMAN:
1694 fs->fsCsb[0] |= FS_LATIN1;
1695 break;
1696 case FT_ENCODING_MS_SYMBOL:
1697 fs->fsCsb[0] |= FS_SYMBOL;
1698 break;
1699 default:
1700 break;
1706 #define ADDFONT_EXTERNAL_FONT 0x01
1707 #define ADDFONT_FORCE_BITMAP 0x02
1708 #define ADDFONT_ADD_TO_CACHE 0x04
1710 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1711 DWORD flags, BOOL vertical )
1713 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1714 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1716 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1717 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1718 if (file)
1720 face->file = strdupA( file );
1721 face->font_data_ptr = NULL;
1722 face->font_data_size = 0;
1724 else
1726 face->file = NULL;
1727 face->font_data_ptr = font_data_ptr;
1728 face->font_data_size = font_data_size;
1731 face->face_index = face_index;
1732 get_fontsig( ft_face, &face->fs );
1733 face->ntmFlags = get_ntm_flags( ft_face );
1734 face->font_version = get_font_version( ft_face );
1736 if (FT_IS_SCALABLE( ft_face ))
1738 memset( &face->size, 0, sizeof(face->size) );
1739 face->scalable = TRUE;
1741 else
1743 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1744 size->height, size->width, size->size >> 6,
1745 size->x_ppem >> 6, size->y_ppem >> 6);
1746 face->size.height = size->height;
1747 face->size.width = size->width;
1748 face->size.size = size->size;
1749 face->size.x_ppem = size->x_ppem;
1750 face->size.y_ppem = size->y_ppem;
1751 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1752 face->scalable = FALSE;
1755 face->vertical = vertical;
1756 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1757 face->family = NULL;
1758 face->cached_enum_data = NULL;
1760 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1761 face->fs.fsCsb[0], face->fs.fsCsb[1],
1762 face->fs.fsUsb[0], face->fs.fsUsb[1],
1763 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1765 return face;
1768 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1769 FT_Long face_index, DWORD flags, BOOL vertical)
1771 Face *face;
1772 Family *family;
1774 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical );
1775 family = get_family( ft_face, vertical );
1776 if (!insert_face_in_family_list( face, family ))
1778 free_face( face );
1779 return;
1782 if (flags & ADDFONT_ADD_TO_CACHE)
1783 add_face_to_cache( face );
1785 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1786 debugstr_w(face->StyleName));
1789 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1790 FT_Long face_index, BOOL allow_bitmap )
1792 FT_Error err;
1793 TT_OS2 *pOS2;
1794 FT_Face ft_face;
1796 if (file)
1798 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1799 err = pFT_New_Face(library, file, face_index, &ft_face);
1801 else
1803 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1804 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1807 if (err != 0)
1809 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1810 return NULL;
1813 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1814 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1816 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1817 goto fail;
1820 if (!FT_IS_SFNT( ft_face ))
1822 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1824 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1825 goto fail;
1828 else
1830 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1831 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1832 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1834 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1835 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1836 goto fail;
1839 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1840 we don't want to load these. */
1841 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1843 FT_ULong len = 0;
1845 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1847 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1848 goto fail;
1853 if (!ft_face->family_name || !ft_face->style_name)
1855 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1856 goto fail;
1859 return ft_face;
1860 fail:
1861 pFT_Done_Face( ft_face );
1862 return NULL;
1865 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1867 FT_Face ft_face;
1868 FT_Long face_index = 0, num_faces;
1869 INT ret = 0;
1871 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1872 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1874 #ifdef HAVE_CARBON_CARBON_H
1875 if(file)
1877 char **mac_list = expand_mac_font(file);
1878 if(mac_list)
1880 BOOL had_one = FALSE;
1881 char **cursor;
1882 for(cursor = mac_list; *cursor; cursor++)
1884 had_one = TRUE;
1885 AddFontToList(*cursor, NULL, 0, flags);
1886 HeapFree(GetProcessHeap(), 0, *cursor);
1888 HeapFree(GetProcessHeap(), 0, mac_list);
1889 if(had_one)
1890 return 1;
1893 #endif /* HAVE_CARBON_CARBON_H */
1895 do {
1896 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1897 if (!ft_face) return 0;
1899 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1901 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1902 pFT_Done_Face(ft_face);
1903 return 0;
1906 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1907 ++ret;
1909 if (FT_HAS_VERTICAL(ft_face))
1911 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1912 ++ret;
1915 num_faces = ft_face->num_faces;
1916 pFT_Done_Face(ft_face);
1917 } while(num_faces > ++face_index);
1918 return ret;
1921 static void DumpFontList(void)
1923 Family *family;
1924 Face *face;
1925 struct list *family_elem_ptr, *face_elem_ptr;
1927 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1928 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1929 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1930 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1931 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1932 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1933 if(!face->scalable)
1934 TRACE(" %d", face->size.height);
1935 TRACE("\n");
1938 return;
1941 /***********************************************************
1942 * The replacement list is a way to map an entire font
1943 * family onto another family. For example adding
1945 * [HKCU\Software\Wine\Fonts\Replacements]
1946 * "Wingdings"="Winedings"
1948 * would enumerate the Winedings font both as Winedings and
1949 * Wingdings. However if a real Wingdings font is present the
1950 * replacement does not take place.
1953 static void LoadReplaceList(void)
1955 HKEY hkey;
1956 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1957 LPWSTR value;
1958 LPVOID data;
1959 CHAR familyA[400];
1961 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1962 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1964 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1965 &valuelen, &datalen, NULL, NULL);
1967 valuelen++; /* returned value doesn't include room for '\0' */
1968 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1969 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1971 dlen = datalen;
1972 vlen = valuelen;
1973 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1974 &dlen) == ERROR_SUCCESS) {
1975 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1976 /* "NewName"="Oldname" */
1977 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1979 if(!find_family_from_any_name(value))
1981 Family * const family = find_family_from_any_name(data);
1982 if (family != NULL)
1984 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1985 if (new_family != NULL)
1987 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1988 new_family->FamilyName = strdupW(value);
1989 new_family->EnglishName = NULL;
1990 list_init(&new_family->faces);
1991 new_family->replacement = &family->faces;
1992 list_add_tail(&font_list, &new_family->entry);
1995 else
1997 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2000 else
2002 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2004 /* reset dlen and vlen */
2005 dlen = datalen;
2006 vlen = valuelen;
2008 HeapFree(GetProcessHeap(), 0, data);
2009 HeapFree(GetProcessHeap(), 0, value);
2010 RegCloseKey(hkey);
2014 static const WCHAR *font_links_list[] =
2016 Lucida_Sans_Unicode,
2017 Microsoft_Sans_Serif,
2018 Tahoma
2021 static const struct font_links_defaults_list
2023 /* Keyed off substitution for "MS Shell Dlg" */
2024 const WCHAR *shelldlg;
2025 /* Maximum of four substitutes, plus terminating NULL pointer */
2026 const WCHAR *substitutes[5];
2027 } font_links_defaults_list[] =
2029 /* Non East-Asian */
2030 { Tahoma, /* FIXME unverified ordering */
2031 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2033 /* Below lists are courtesy of
2034 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2036 /* Japanese */
2037 { MS_UI_Gothic,
2038 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2040 /* Chinese Simplified */
2041 { SimSun,
2042 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2044 /* Korean */
2045 { Gulim,
2046 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2048 /* Chinese Traditional */
2049 { PMingLiU,
2050 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2055 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2057 SYSTEM_LINKS *font_link;
2059 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2061 if(!strcmpiW(font_link->font_name, name))
2062 return font_link;
2065 return NULL;
2068 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2070 const WCHAR *value;
2071 int i;
2072 FontSubst *psub;
2073 Family *family;
2074 Face *face;
2075 const char *file;
2076 WCHAR *fileW;
2078 if (values)
2080 SYSTEM_LINKS *font_link;
2082 psub = get_font_subst(&font_subst_list, name, -1);
2083 /* Don't store fonts that are only substitutes for other fonts */
2084 if(psub)
2086 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2087 return;
2090 font_link = find_font_link(name);
2091 if (font_link == NULL)
2093 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2094 font_link->font_name = strdupW(name);
2095 list_init(&font_link->links);
2096 list_add_tail(&system_links, &font_link->entry);
2099 memset(&font_link->fs, 0, sizeof font_link->fs);
2100 for (i = 0; values[i] != NULL; i++)
2102 const struct list *face_list;
2103 CHILD_FONT *child_font;
2105 value = values[i];
2106 if (!strcmpiW(name,value))
2107 continue;
2108 psub = get_font_subst(&font_subst_list, value, -1);
2109 if(psub)
2110 value = psub->to.name;
2111 family = find_family_from_name(value);
2112 if (!family)
2113 continue;
2114 file = NULL;
2115 /* Use first extant filename for this Family */
2116 face_list = get_face_list_from_family(family);
2117 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2119 if (!face->file)
2120 continue;
2121 file = strrchr(face->file, '/');
2122 if (!file)
2123 file = face->file;
2124 else
2125 file++;
2126 break;
2128 if (!file)
2129 continue;
2130 fileW = towstr(CP_UNIXCP, file);
2132 face = find_face_from_filename(fileW, value);
2133 if(!face)
2135 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2136 continue;
2139 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2140 child_font->face = face;
2141 child_font->font = NULL;
2142 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2143 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2144 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2145 list_add_tail(&font_link->links, &child_font->entry);
2147 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2148 HeapFree(GetProcessHeap(), 0, fileW);
2154 /*************************************************************
2155 * init_system_links
2157 static BOOL init_system_links(void)
2159 HKEY hkey;
2160 BOOL ret = FALSE;
2161 DWORD type, max_val, max_data, val_len, data_len, index;
2162 WCHAR *value, *data;
2163 WCHAR *entry, *next;
2164 SYSTEM_LINKS *font_link, *system_font_link;
2165 CHILD_FONT *child_font;
2166 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2167 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2168 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2169 Face *face;
2170 FontSubst *psub;
2171 UINT i, j;
2173 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2175 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2176 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2177 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2178 val_len = max_val + 1;
2179 data_len = max_data;
2180 index = 0;
2181 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2183 psub = get_font_subst(&font_subst_list, value, -1);
2184 /* Don't store fonts that are only substitutes for other fonts */
2185 if(psub)
2187 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2188 goto next;
2190 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2191 font_link->font_name = strdupW(value);
2192 memset(&font_link->fs, 0, sizeof font_link->fs);
2193 list_init(&font_link->links);
2194 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2196 WCHAR *face_name;
2197 CHILD_FONT *child_font;
2199 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2201 next = entry + strlenW(entry) + 1;
2203 face_name = strchrW(entry, ',');
2204 if(face_name)
2206 *face_name++ = 0;
2207 while(isspaceW(*face_name))
2208 face_name++;
2210 psub = get_font_subst(&font_subst_list, face_name, -1);
2211 if(psub)
2212 face_name = psub->to.name;
2214 face = find_face_from_filename(entry, face_name);
2215 if(!face)
2217 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2218 continue;
2221 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2222 child_font->face = face;
2223 child_font->font = NULL;
2224 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2225 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2226 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2227 list_add_tail(&font_link->links, &child_font->entry);
2229 list_add_tail(&system_links, &font_link->entry);
2230 next:
2231 val_len = max_val + 1;
2232 data_len = max_data;
2235 HeapFree(GetProcessHeap(), 0, value);
2236 HeapFree(GetProcessHeap(), 0, data);
2237 RegCloseKey(hkey);
2241 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2242 if (!psub) {
2243 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2244 goto skip_internal;
2247 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2249 const FontSubst *psub2;
2250 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2252 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2254 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2255 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2257 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2258 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2260 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2262 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2266 skip_internal:
2268 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2269 that Tahoma has */
2271 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2272 system_font_link->font_name = strdupW(System);
2273 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2274 list_init(&system_font_link->links);
2276 face = find_face_from_filename(tahoma_ttf, Tahoma);
2277 if(face)
2279 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2280 child_font->face = face;
2281 child_font->font = NULL;
2282 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2283 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2284 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2285 list_add_tail(&system_font_link->links, &child_font->entry);
2287 font_link = find_font_link(Tahoma);
2288 if (font_link != NULL)
2290 CHILD_FONT *font_link_entry;
2291 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2293 CHILD_FONT *new_child;
2294 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2295 new_child->face = font_link_entry->face;
2296 new_child->font = NULL;
2297 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2298 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2299 list_add_tail(&system_font_link->links, &new_child->entry);
2302 list_add_tail(&system_links, &system_font_link->entry);
2303 return ret;
2306 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2308 DIR *dir;
2309 struct dirent *dent;
2310 char path[MAX_PATH];
2312 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2314 dir = opendir(dirname);
2315 if(!dir) {
2316 WARN("Can't open directory %s\n", debugstr_a(dirname));
2317 return FALSE;
2319 while((dent = readdir(dir)) != NULL) {
2320 struct stat statbuf;
2322 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2323 continue;
2325 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2327 sprintf(path, "%s/%s", dirname, dent->d_name);
2329 if(stat(path, &statbuf) == -1)
2331 WARN("Can't stat %s\n", debugstr_a(path));
2332 continue;
2334 if(S_ISDIR(statbuf.st_mode))
2335 ReadFontDir(path, external_fonts);
2336 else
2338 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2339 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2340 AddFontToList(path, NULL, 0, addfont_flags);
2343 closedir(dir);
2344 return TRUE;
2347 #ifdef SONAME_LIBFONTCONFIG
2348 static void load_fontconfig_fonts(void)
2350 void *fc_handle = NULL;
2351 FcConfig *config;
2352 FcPattern *pat;
2353 FcObjectSet *os;
2354 FcFontSet *fontset;
2355 int i, len;
2356 char *file;
2357 const char *ext;
2359 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2360 if(!fc_handle) {
2361 TRACE("Wine cannot find the fontconfig library (%s).\n",
2362 SONAME_LIBFONTCONFIG);
2363 return;
2365 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
2366 LOAD_FUNCPTR(FcConfigGetCurrent);
2367 LOAD_FUNCPTR(FcFontList);
2368 LOAD_FUNCPTR(FcFontSetDestroy);
2369 LOAD_FUNCPTR(FcInit);
2370 LOAD_FUNCPTR(FcObjectSetAdd);
2371 LOAD_FUNCPTR(FcObjectSetCreate);
2372 LOAD_FUNCPTR(FcObjectSetDestroy);
2373 LOAD_FUNCPTR(FcPatternCreate);
2374 LOAD_FUNCPTR(FcPatternDestroy);
2375 LOAD_FUNCPTR(FcPatternGetBool);
2376 LOAD_FUNCPTR(FcPatternGetString);
2377 #undef LOAD_FUNCPTR
2379 if(!pFcInit()) return;
2381 config = pFcConfigGetCurrent();
2382 pat = pFcPatternCreate();
2383 os = pFcObjectSetCreate();
2384 pFcObjectSetAdd(os, FC_FILE);
2385 pFcObjectSetAdd(os, FC_SCALABLE);
2386 fontset = pFcFontList(config, pat, os);
2387 if(!fontset) return;
2388 for(i = 0; i < fontset->nfont; i++) {
2389 FcBool scalable;
2391 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2392 continue;
2393 TRACE("fontconfig: %s\n", file);
2395 /* We're just interested in OT/TT fonts for now, so this hack just
2396 picks up the scalable fonts without extensions .pf[ab] to save time
2397 loading every other font */
2399 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2401 TRACE("not scalable\n");
2402 continue;
2405 len = strlen( file );
2406 if(len < 4) continue;
2407 ext = &file[ len - 3 ];
2408 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2409 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2411 pFcFontSetDestroy(fontset);
2412 pFcObjectSetDestroy(os);
2413 pFcPatternDestroy(pat);
2414 sym_not_found:
2415 return;
2418 #elif defined(HAVE_CARBON_CARBON_H)
2420 static void load_mac_font_callback(const void *value, void *context)
2422 CFStringRef pathStr = value;
2423 CFIndex len;
2424 char* path;
2426 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2427 path = HeapAlloc(GetProcessHeap(), 0, len);
2428 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2430 TRACE("font file %s\n", path);
2431 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2433 HeapFree(GetProcessHeap(), 0, path);
2436 static void load_mac_fonts(void)
2438 CFStringRef removeDupesKey;
2439 CFBooleanRef removeDupesValue;
2440 CFDictionaryRef options;
2441 CTFontCollectionRef col;
2442 CFArrayRef descs;
2443 CFMutableSetRef paths;
2444 CFIndex i;
2446 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2447 removeDupesValue = kCFBooleanTrue;
2448 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2449 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2450 col = CTFontCollectionCreateFromAvailableFonts(options);
2451 if (options) CFRelease(options);
2452 if (!col)
2454 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2455 return;
2458 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2459 CFRelease(col);
2460 if (!descs)
2462 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2463 return;
2466 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2467 if (!paths)
2469 WARN("CFSetCreateMutable failed\n");
2470 CFRelease(descs);
2471 return;
2474 for (i = 0; i < CFArrayGetCount(descs); i++)
2476 CTFontDescriptorRef desc;
2477 CTFontRef font;
2478 ATSFontRef atsFont;
2479 OSStatus status;
2480 FSRef fsref;
2481 CFURLRef url;
2482 CFStringRef ext;
2483 CFStringRef path;
2485 desc = CFArrayGetValueAtIndex(descs, i);
2487 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2488 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2489 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2490 if (!font) continue;
2492 atsFont = CTFontGetPlatformFont(font, NULL);
2493 if (!atsFont)
2495 CFRelease(font);
2496 continue;
2499 status = ATSFontGetFileReference(atsFont, &fsref);
2500 CFRelease(font);
2501 if (status != noErr) continue;
2503 url = CFURLCreateFromFSRef(NULL, &fsref);
2504 if (!url) continue;
2506 ext = CFURLCopyPathExtension(url);
2507 if (ext)
2509 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2510 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2511 CFRelease(ext);
2512 if (skip)
2514 CFRelease(url);
2515 continue;
2519 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2520 CFRelease(url);
2521 if (!path) continue;
2523 CFSetAddValue(paths, path);
2524 CFRelease(path);
2527 CFRelease(descs);
2529 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2530 CFRelease(paths);
2533 #endif
2535 static BOOL load_font_from_data_dir(LPCWSTR file)
2537 BOOL ret = FALSE;
2538 const char *data_dir = wine_get_data_dir();
2540 if (!data_dir) data_dir = wine_get_build_dir();
2542 if (data_dir)
2544 INT len;
2545 char *unix_name;
2547 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2549 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2551 strcpy(unix_name, data_dir);
2552 strcat(unix_name, "/fonts/");
2554 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2556 EnterCriticalSection( &freetype_cs );
2557 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2558 LeaveCriticalSection( &freetype_cs );
2559 HeapFree(GetProcessHeap(), 0, unix_name);
2561 return ret;
2564 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2566 static const WCHAR slashW[] = {'\\','\0'};
2567 BOOL ret = FALSE;
2568 WCHAR windowsdir[MAX_PATH];
2569 char *unixname;
2571 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2572 strcatW(windowsdir, fontsW);
2573 strcatW(windowsdir, slashW);
2574 strcatW(windowsdir, file);
2575 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2576 EnterCriticalSection( &freetype_cs );
2577 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2578 LeaveCriticalSection( &freetype_cs );
2579 HeapFree(GetProcessHeap(), 0, unixname);
2581 return ret;
2584 static void load_system_fonts(void)
2586 HKEY hkey;
2587 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2588 const WCHAR * const *value;
2589 DWORD dlen, type;
2590 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2591 char *unixname;
2593 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2594 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2595 strcatW(windowsdir, fontsW);
2596 for(value = SystemFontValues; *value; value++) {
2597 dlen = sizeof(data);
2598 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2599 type == REG_SZ) {
2600 BOOL added = FALSE;
2602 sprintfW(pathW, fmtW, windowsdir, data);
2603 if((unixname = wine_get_unix_file_name(pathW))) {
2604 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2605 HeapFree(GetProcessHeap(), 0, unixname);
2607 if (!added)
2608 load_font_from_data_dir(data);
2611 RegCloseKey(hkey);
2615 /*************************************************************
2617 * This adds registry entries for any externally loaded fonts
2618 * (fonts from fontconfig or FontDirs). It also deletes entries
2619 * of no longer existing fonts.
2622 static void update_reg_entries(void)
2624 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2625 LPWSTR valueW;
2626 DWORD len, len_fam;
2627 Family *family;
2628 Face *face;
2629 struct list *family_elem_ptr, *face_elem_ptr;
2630 WCHAR *file;
2631 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2632 static const WCHAR spaceW[] = {' ', '\0'};
2633 char *path;
2635 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2636 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2637 ERR("Can't create Windows font reg key\n");
2638 goto end;
2641 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2642 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2643 ERR("Can't create Windows font reg key\n");
2644 goto end;
2647 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2648 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2649 ERR("Can't create external font reg key\n");
2650 goto end;
2653 /* enumerate the fonts and add external ones to the two keys */
2655 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2656 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2657 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2658 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2659 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2660 if(!face->external) continue;
2661 len = len_fam;
2662 if (!(face->ntmFlags & NTM_REGULAR))
2663 len = len_fam + strlenW(face->StyleName) + 1;
2664 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2665 strcpyW(valueW, family->FamilyName);
2666 if(len != len_fam) {
2667 strcatW(valueW, spaceW);
2668 strcatW(valueW, face->StyleName);
2670 strcatW(valueW, TrueType);
2672 file = wine_get_dos_file_name(face->file);
2673 if(file)
2674 len = strlenW(file) + 1;
2675 else
2677 if((path = strrchr(face->file, '/')) == NULL)
2678 path = face->file;
2679 else
2680 path++;
2681 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2683 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2684 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2686 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2687 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2688 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2690 HeapFree(GetProcessHeap(), 0, file);
2691 HeapFree(GetProcessHeap(), 0, valueW);
2694 end:
2695 if(external_key) RegCloseKey(external_key);
2696 if(win9x_key) RegCloseKey(win9x_key);
2697 if(winnt_key) RegCloseKey(winnt_key);
2698 return;
2701 static void delete_external_font_keys(void)
2703 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2704 DWORD dlen, vlen, datalen, valuelen, i, type;
2705 LPWSTR valueW;
2706 LPVOID data;
2708 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2709 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2710 ERR("Can't create Windows font reg key\n");
2711 goto end;
2714 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2715 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2716 ERR("Can't create Windows font reg key\n");
2717 goto end;
2720 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2721 ERR("Can't create external font reg key\n");
2722 goto end;
2725 /* Delete all external fonts added last time */
2727 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2728 &valuelen, &datalen, NULL, NULL);
2729 valuelen++; /* returned value doesn't include room for '\0' */
2730 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2731 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2733 dlen = datalen * sizeof(WCHAR);
2734 vlen = valuelen;
2735 i = 0;
2736 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2737 &dlen) == ERROR_SUCCESS) {
2739 RegDeleteValueW(winnt_key, valueW);
2740 RegDeleteValueW(win9x_key, valueW);
2741 /* reset dlen and vlen */
2742 dlen = datalen;
2743 vlen = valuelen;
2745 HeapFree(GetProcessHeap(), 0, data);
2746 HeapFree(GetProcessHeap(), 0, valueW);
2748 /* Delete the old external fonts key */
2749 RegCloseKey(external_key);
2750 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2752 end:
2753 if(win9x_key) RegCloseKey(win9x_key);
2754 if(winnt_key) RegCloseKey(winnt_key);
2757 /*************************************************************
2758 * WineEngAddFontResourceEx
2761 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2763 INT ret = 0;
2765 GDI_CheckNotLock();
2767 if (ft_handle) /* do it only if we have freetype up and running */
2769 char *unixname;
2771 if(flags)
2772 FIXME("Ignoring flags %x\n", flags);
2774 if((unixname = wine_get_unix_file_name(file)))
2776 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2778 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2779 EnterCriticalSection( &freetype_cs );
2780 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2781 LeaveCriticalSection( &freetype_cs );
2782 HeapFree(GetProcessHeap(), 0, unixname);
2784 if (!ret && !strchrW(file, '\\')) {
2785 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2786 ret = load_font_from_winfonts_dir(file);
2787 if (!ret) {
2788 /* Try in datadir/fonts (or builddir/fonts),
2789 * needed for Magic the Gathering Online
2791 ret = load_font_from_data_dir(file);
2795 return ret;
2798 /*************************************************************
2799 * WineEngAddFontMemResourceEx
2802 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2804 GDI_CheckNotLock();
2806 if (ft_handle) /* do it only if we have freetype up and running */
2808 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2810 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2811 memcpy(pFontCopy, pbFont, cbFont);
2813 EnterCriticalSection( &freetype_cs );
2814 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2815 LeaveCriticalSection( &freetype_cs );
2817 if (*pcFonts == 0)
2819 TRACE("AddFontToList failed\n");
2820 HeapFree(GetProcessHeap(), 0, pFontCopy);
2821 return 0;
2823 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2824 * For now return something unique but quite random
2826 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2827 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2830 *pcFonts = 0;
2831 return 0;
2834 /*************************************************************
2835 * WineEngRemoveFontResourceEx
2838 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2840 GDI_CheckNotLock();
2841 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2842 return TRUE;
2845 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2847 WCHAR *fullname;
2848 char *unix_name;
2849 int file_len;
2851 if (!font_file) return NULL;
2853 file_len = strlenW( font_file );
2855 if (font_path && font_path[0])
2857 int path_len = strlenW( font_path );
2858 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2859 if (!fullname) return NULL;
2860 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2861 fullname[path_len] = '\\';
2862 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2864 else
2866 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2867 if (!len) return NULL;
2868 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2869 if (!fullname) return NULL;
2870 GetFullPathNameW( font_file, len, fullname, NULL );
2873 unix_name = wine_get_unix_file_name( fullname );
2874 HeapFree( GetProcessHeap(), 0, fullname );
2875 return unix_name;
2878 #include <pshpack1.h>
2879 struct fontdir
2881 WORD num_of_resources;
2882 WORD res_id;
2883 WORD dfVersion;
2884 DWORD dfSize;
2885 CHAR dfCopyright[60];
2886 WORD dfType;
2887 WORD dfPoints;
2888 WORD dfVertRes;
2889 WORD dfHorizRes;
2890 WORD dfAscent;
2891 WORD dfInternalLeading;
2892 WORD dfExternalLeading;
2893 BYTE dfItalic;
2894 BYTE dfUnderline;
2895 BYTE dfStrikeOut;
2896 WORD dfWeight;
2897 BYTE dfCharSet;
2898 WORD dfPixWidth;
2899 WORD dfPixHeight;
2900 BYTE dfPitchAndFamily;
2901 WORD dfAvgWidth;
2902 WORD dfMaxWidth;
2903 BYTE dfFirstChar;
2904 BYTE dfLastChar;
2905 BYTE dfDefaultChar;
2906 BYTE dfBreakChar;
2907 WORD dfWidthBytes;
2908 DWORD dfDevice;
2909 DWORD dfFace;
2910 DWORD dfReserved;
2911 CHAR szFaceName[LF_FACESIZE];
2914 #include <poppack.h>
2916 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2917 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2919 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2921 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2922 Face *face;
2923 Family *family;
2924 WCHAR *name, *english_name;
2925 ENUMLOGFONTEXW elf;
2926 NEWTEXTMETRICEXW ntm;
2927 DWORD type;
2929 if (!ft_face) return FALSE;
2930 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE );
2931 get_family_names( ft_face, &name, &english_name, FALSE );
2932 family = create_family( name, english_name );
2933 insert_face_in_family_list( face, family );
2934 pFT_Done_Face( ft_face );
2936 GetEnumStructs( face, &elf, &ntm, &type );
2937 free_family( family );
2939 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
2941 memset( fd, 0, sizeof(*fd) );
2943 fd->num_of_resources = 1;
2944 fd->res_id = 0;
2945 fd->dfVersion = 0x200;
2946 fd->dfSize = sizeof(*fd);
2947 strcpy( fd->dfCopyright, "Wine fontdir" );
2948 fd->dfType = 0x4003; /* 0x0080 set if private */
2949 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
2950 fd->dfVertRes = 72;
2951 fd->dfHorizRes = 72;
2952 fd->dfAscent = ntm.ntmTm.tmAscent;
2953 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
2954 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
2955 fd->dfItalic = ntm.ntmTm.tmItalic;
2956 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
2957 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
2958 fd->dfWeight = ntm.ntmTm.tmWeight;
2959 fd->dfCharSet = ntm.ntmTm.tmCharSet;
2960 fd->dfPixWidth = 0;
2961 fd->dfPixHeight = ntm.ntmTm.tmHeight;
2962 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
2963 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
2964 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
2965 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
2966 fd->dfLastChar = ntm.ntmTm.tmLastChar;
2967 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
2968 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
2969 fd->dfWidthBytes = 0;
2970 fd->dfDevice = 0;
2971 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
2972 fd->dfReserved = 0;
2973 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
2975 return TRUE;
2978 #define NE_FFLAGS_LIBMODULE 0x8000
2979 #define NE_OSFLAGS_WINDOWS 0x02
2981 static const char dos_string[0x40] = "This is a TrueType resource file";
2982 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
2984 #include <pshpack2.h>
2986 struct ne_typeinfo
2988 WORD type_id;
2989 WORD count;
2990 DWORD res;
2993 struct ne_nameinfo
2995 WORD off;
2996 WORD len;
2997 WORD flags;
2998 WORD id;
2999 DWORD res;
3002 struct rsrc_tab
3004 WORD align;
3005 struct ne_typeinfo fontdir_type;
3006 struct ne_nameinfo fontdir_name;
3007 struct ne_typeinfo scalable_type;
3008 struct ne_nameinfo scalable_name;
3009 WORD end_of_rsrc;
3010 BYTE fontdir_res_name[8];
3013 #include <poppack.h>
3015 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3017 BOOL ret = FALSE;
3018 HANDLE file;
3019 DWORD size, written;
3020 BYTE *ptr, *start;
3021 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3022 char *font_fileA, *last_part, *ext;
3023 IMAGE_DOS_HEADER dos;
3024 IMAGE_OS2_HEADER ne =
3026 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3027 0, 0, 0, 0, 0, 0,
3028 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3029 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3031 struct rsrc_tab rsrc_tab =
3034 { 0x8007, 1, 0 },
3035 { 0, 0, 0x0c50, 0x2c, 0 },
3036 { 0x80cc, 1, 0 },
3037 { 0, 0, 0x0c50, 0x8001, 0 },
3039 { 7,'F','O','N','T','D','I','R'}
3042 memset( &dos, 0, sizeof(dos) );
3043 dos.e_magic = IMAGE_DOS_SIGNATURE;
3044 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3046 /* import name is last part\0, resident name is last part without extension
3047 non-resident name is "FONTRES:" + lfFaceName */
3049 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3050 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3051 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3053 last_part = strrchr( font_fileA, '\\' );
3054 if (last_part) last_part++;
3055 else last_part = font_fileA;
3056 import_name_len = strlen( last_part ) + 1;
3058 ext = strchr( last_part, '.' );
3059 if (ext) res_name_len = ext - last_part;
3060 else res_name_len = import_name_len - 1;
3062 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3064 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3065 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3066 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3067 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3068 ne.ne_cbenttab = 2;
3069 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3071 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3072 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3073 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3074 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3076 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3077 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3079 if (!ptr)
3081 HeapFree( GetProcessHeap(), 0, font_fileA );
3082 return FALSE;
3085 memcpy( ptr, &dos, sizeof(dos) );
3086 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3087 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3089 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3090 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3092 ptr = start + dos.e_lfanew + ne.ne_restab;
3093 *ptr++ = res_name_len;
3094 memcpy( ptr, last_part, res_name_len );
3096 ptr = start + dos.e_lfanew + ne.ne_imptab;
3097 *ptr++ = import_name_len;
3098 memcpy( ptr, last_part, import_name_len );
3100 ptr = start + ne.ne_nrestab;
3101 *ptr++ = non_res_name_len;
3102 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3103 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3105 ptr = start + (rsrc_tab.scalable_name.off << 4);
3106 memcpy( ptr, font_fileA, font_file_len );
3108 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3109 memcpy( ptr, fontdir, fontdir->dfSize );
3111 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3112 if (file != INVALID_HANDLE_VALUE)
3114 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3115 ret = TRUE;
3116 CloseHandle( file );
3119 HeapFree( GetProcessHeap(), 0, start );
3120 HeapFree( GetProcessHeap(), 0, font_fileA );
3122 return ret;
3125 /*************************************************************
3126 * WineEngCreateScalableFontResource
3129 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3130 LPCWSTR font_file, LPCWSTR font_path )
3132 char *unix_name = get_ttf_file_name( font_file, font_path );
3133 struct fontdir fontdir;
3134 BOOL ret = FALSE;
3136 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3137 SetLastError( ERROR_INVALID_PARAMETER );
3138 else
3140 if (hidden) fontdir.dfType |= 0x80;
3141 ret = create_fot( resource, font_file, &fontdir );
3144 HeapFree( GetProcessHeap(), 0, unix_name );
3145 return ret;
3148 static const struct nls_update_font_list
3150 UINT ansi_cp, oem_cp;
3151 const char *oem, *fixed, *system;
3152 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3153 /* these are for font substitutes */
3154 const char *shelldlg, *tmsrmn;
3155 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3156 *helv_0, *tmsrmn_0;
3157 const struct subst
3159 const char *from, *to;
3160 } arial_0, courier_new_0, times_new_roman_0;
3161 } nls_update_font_list[] =
3163 /* Latin 1 (United States) */
3164 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3165 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3166 "Tahoma","Times New Roman",
3167 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3168 { 0 }, { 0 }, { 0 }
3170 /* Latin 1 (Multilingual) */
3171 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3172 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3173 "Tahoma","Times New Roman", /* FIXME unverified */
3174 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3175 { 0 }, { 0 }, { 0 }
3177 /* Eastern Europe */
3178 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3179 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3180 "Tahoma","Times New Roman", /* FIXME unverified */
3181 "Fixedsys,238", "System,238",
3182 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3183 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3184 { "Arial CE,0", "Arial,238" },
3185 { "Courier New CE,0", "Courier New,238" },
3186 { "Times New Roman CE,0", "Times New Roman,238" }
3188 /* Cyrillic */
3189 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3190 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3191 "Tahoma","Times New Roman", /* FIXME unverified */
3192 "Fixedsys,204", "System,204",
3193 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3194 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3195 { "Arial Cyr,0", "Arial,204" },
3196 { "Courier New Cyr,0", "Courier New,204" },
3197 { "Times New Roman Cyr,0", "Times New Roman,204" }
3199 /* Greek */
3200 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3201 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3202 "Tahoma","Times New Roman", /* FIXME unverified */
3203 "Fixedsys,161", "System,161",
3204 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3205 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3206 { "Arial Greek,0", "Arial,161" },
3207 { "Courier New Greek,0", "Courier New,161" },
3208 { "Times New Roman Greek,0", "Times New Roman,161" }
3210 /* Turkish */
3211 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3212 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3213 "Tahoma","Times New Roman", /* FIXME unverified */
3214 "Fixedsys,162", "System,162",
3215 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3216 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3217 { "Arial Tur,0", "Arial,162" },
3218 { "Courier New Tur,0", "Courier New,162" },
3219 { "Times New Roman Tur,0", "Times New Roman,162" }
3221 /* Hebrew */
3222 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3223 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3224 "Tahoma","Times New Roman", /* FIXME unverified */
3225 "Fixedsys,177", "System,177",
3226 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3227 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3228 { 0 }, { 0 }, { 0 }
3230 /* Arabic */
3231 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3232 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3233 "Tahoma","Times New Roman", /* FIXME unverified */
3234 "Fixedsys,178", "System,178",
3235 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3236 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3237 { 0 }, { 0 }, { 0 }
3239 /* Baltic */
3240 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3241 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3242 "Tahoma","Times New Roman", /* FIXME unverified */
3243 "Fixedsys,186", "System,186",
3244 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3245 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3246 { "Arial Baltic,0", "Arial,186" },
3247 { "Courier New Baltic,0", "Courier New,186" },
3248 { "Times New Roman Baltic,0", "Times New Roman,186" }
3250 /* Vietnamese */
3251 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3252 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3253 "Tahoma","Times New Roman", /* FIXME unverified */
3254 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3255 { 0 }, { 0 }, { 0 }
3257 /* Thai */
3258 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3259 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3260 "Tahoma","Times New Roman", /* FIXME unverified */
3261 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3262 { 0 }, { 0 }, { 0 }
3264 /* Japanese */
3265 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3266 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3267 "MS UI Gothic","MS Serif",
3268 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3269 { 0 }, { 0 }, { 0 }
3271 /* Chinese Simplified */
3272 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3273 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3274 "SimSun", "NSimSun",
3275 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3276 { 0 }, { 0 }, { 0 }
3278 /* Korean */
3279 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3280 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3281 "Gulim", "Batang",
3282 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3283 { 0 }, { 0 }, { 0 }
3285 /* Chinese Traditional */
3286 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3287 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3288 "PMingLiU", "MingLiU",
3289 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3290 { 0 }, { 0 }, { 0 }
3294 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3296 return ( ansi_cp == 932 /* CP932 for Japanese */
3297 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3298 || ansi_cp == 949 /* CP949 for Korean */
3299 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3302 static inline HKEY create_fonts_NT_registry_key(void)
3304 HKEY hkey = 0;
3306 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3307 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3308 return hkey;
3311 static inline HKEY create_fonts_9x_registry_key(void)
3313 HKEY hkey = 0;
3315 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3316 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3317 return hkey;
3320 static inline HKEY create_config_fonts_registry_key(void)
3322 HKEY hkey = 0;
3324 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3325 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3326 return hkey;
3329 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3331 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3333 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3334 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3335 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3336 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3339 static void set_value_key(HKEY hkey, const char *name, const char *value)
3341 if (value)
3342 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3343 else if (name)
3344 RegDeleteValueA(hkey, name);
3347 static void update_font_info(void)
3349 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3350 char buf[40], cpbuf[40];
3351 DWORD len, type;
3352 HKEY hkey = 0;
3353 UINT i, ansi_cp = 0, oem_cp = 0;
3354 DWORD screen_dpi = 96, font_dpi = 0;
3355 BOOL done = FALSE;
3357 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3358 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3359 &hkey) == ERROR_SUCCESS)
3361 reg_load_dword(hkey, logpixels, &screen_dpi);
3362 RegCloseKey(hkey);
3365 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3366 return;
3368 reg_load_dword(hkey, logpixels, &font_dpi);
3370 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3371 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3372 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3373 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3374 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3376 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3377 if (is_dbcs_ansi_cp(ansi_cp))
3378 use_default_fallback = TRUE;
3380 len = sizeof(buf);
3381 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3383 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3385 RegCloseKey(hkey);
3386 return;
3388 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3389 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3391 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3392 ansi_cp, oem_cp, screen_dpi);
3394 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3395 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3396 RegCloseKey(hkey);
3398 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3400 HKEY hkey;
3402 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3403 nls_update_font_list[i].oem_cp == oem_cp)
3405 hkey = create_config_fonts_registry_key();
3406 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3407 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3408 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3409 RegCloseKey(hkey);
3411 hkey = create_fonts_NT_registry_key();
3412 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3413 RegCloseKey(hkey);
3415 hkey = create_fonts_9x_registry_key();
3416 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3417 RegCloseKey(hkey);
3419 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3421 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3422 strlen(nls_update_font_list[i].shelldlg)+1);
3423 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3424 strlen(nls_update_font_list[i].tmsrmn)+1);
3426 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3427 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3428 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3429 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3430 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3431 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3432 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3433 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3435 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3436 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3437 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3439 RegCloseKey(hkey);
3441 done = TRUE;
3443 else
3445 /* Delete the FontSubstitutes from other locales */
3446 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3448 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3449 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3450 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3451 RegCloseKey(hkey);
3455 if (!done)
3456 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3459 static BOOL init_freetype(void)
3461 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3462 if(!ft_handle) {
3463 WINE_MESSAGE(
3464 "Wine cannot find the FreeType font library. To enable Wine to\n"
3465 "use TrueType fonts please install a version of FreeType greater than\n"
3466 "or equal to 2.0.5.\n"
3467 "http://www.freetype.org\n");
3468 return FALSE;
3471 #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;}
3473 LOAD_FUNCPTR(FT_Done_Face)
3474 LOAD_FUNCPTR(FT_Get_Char_Index)
3475 LOAD_FUNCPTR(FT_Get_First_Char)
3476 LOAD_FUNCPTR(FT_Get_Module)
3477 LOAD_FUNCPTR(FT_Get_Next_Char)
3478 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3479 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3480 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3481 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3482 LOAD_FUNCPTR(FT_Init_FreeType)
3483 LOAD_FUNCPTR(FT_Library_Version)
3484 LOAD_FUNCPTR(FT_Load_Glyph)
3485 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3486 LOAD_FUNCPTR(FT_Matrix_Multiply)
3487 #ifndef FT_MULFIX_INLINED
3488 LOAD_FUNCPTR(FT_MulFix)
3489 #endif
3490 LOAD_FUNCPTR(FT_New_Face)
3491 LOAD_FUNCPTR(FT_New_Memory_Face)
3492 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3493 LOAD_FUNCPTR(FT_Outline_Transform)
3494 LOAD_FUNCPTR(FT_Outline_Translate)
3495 LOAD_FUNCPTR(FT_Render_Glyph)
3496 LOAD_FUNCPTR(FT_Select_Charmap)
3497 LOAD_FUNCPTR(FT_Set_Charmap)
3498 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3499 LOAD_FUNCPTR(FT_Vector_Transform)
3500 LOAD_FUNCPTR(FT_Vector_Unit)
3501 #undef LOAD_FUNCPTR
3502 /* Don't warn if these ones are missing */
3503 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3504 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3505 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3506 #endif
3508 if(pFT_Init_FreeType(&library) != 0) {
3509 ERR("Can't init FreeType library\n");
3510 wine_dlclose(ft_handle, NULL, 0);
3511 ft_handle = NULL;
3512 return FALSE;
3514 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3516 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3517 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3518 ((FT_Version.minor << 8) & 0x00ff00) |
3519 ((FT_Version.patch ) & 0x0000ff);
3521 font_driver = &freetype_funcs;
3522 return TRUE;
3524 sym_not_found:
3525 WINE_MESSAGE(
3526 "Wine cannot find certain functions that it needs inside the FreeType\n"
3527 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3528 "FreeType to at least version 2.1.4.\n"
3529 "http://www.freetype.org\n");
3530 wine_dlclose(ft_handle, NULL, 0);
3531 ft_handle = NULL;
3532 return FALSE;
3535 static void init_font_list(void)
3537 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3538 static const WCHAR pathW[] = {'P','a','t','h',0};
3539 HKEY hkey;
3540 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3541 WCHAR windowsdir[MAX_PATH];
3542 char *unixname;
3543 const char *data_dir;
3545 delete_external_font_keys();
3547 /* load the system bitmap fonts */
3548 load_system_fonts();
3550 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3551 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3552 strcatW(windowsdir, fontsW);
3553 if((unixname = wine_get_unix_file_name(windowsdir)))
3555 ReadFontDir(unixname, FALSE);
3556 HeapFree(GetProcessHeap(), 0, unixname);
3559 /* load the system truetype fonts */
3560 data_dir = wine_get_data_dir();
3561 if (!data_dir) data_dir = wine_get_build_dir();
3562 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3564 strcpy(unixname, data_dir);
3565 strcat(unixname, "/fonts/");
3566 ReadFontDir(unixname, TRUE);
3567 HeapFree(GetProcessHeap(), 0, unixname);
3570 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3571 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3572 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3573 will skip these. */
3574 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3575 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3576 &hkey) == ERROR_SUCCESS)
3578 LPWSTR data, valueW;
3579 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3580 &valuelen, &datalen, NULL, NULL);
3582 valuelen++; /* returned value doesn't include room for '\0' */
3583 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3584 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3585 if (valueW && data)
3587 dlen = datalen * sizeof(WCHAR);
3588 vlen = valuelen;
3589 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3590 &dlen) == ERROR_SUCCESS)
3592 if(data[0] && (data[1] == ':'))
3594 if((unixname = wine_get_unix_file_name(data)))
3596 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3597 HeapFree(GetProcessHeap(), 0, unixname);
3600 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3602 WCHAR pathW[MAX_PATH];
3603 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3604 BOOL added = FALSE;
3606 sprintfW(pathW, fmtW, windowsdir, data);
3607 if((unixname = wine_get_unix_file_name(pathW)))
3609 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3610 HeapFree(GetProcessHeap(), 0, unixname);
3612 if (!added)
3613 load_font_from_data_dir(data);
3615 /* reset dlen and vlen */
3616 dlen = datalen;
3617 vlen = valuelen;
3620 HeapFree(GetProcessHeap(), 0, data);
3621 HeapFree(GetProcessHeap(), 0, valueW);
3622 RegCloseKey(hkey);
3625 #ifdef SONAME_LIBFONTCONFIG
3626 load_fontconfig_fonts();
3627 #elif defined(HAVE_CARBON_CARBON_H)
3628 load_mac_fonts();
3629 #endif
3631 /* then look in any directories that we've specified in the config file */
3632 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3633 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3635 DWORD len;
3636 LPWSTR valueW;
3637 LPSTR valueA, ptr;
3639 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3641 len += sizeof(WCHAR);
3642 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3643 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3645 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3646 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3647 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3648 TRACE( "got font path %s\n", debugstr_a(valueA) );
3649 ptr = valueA;
3650 while (ptr)
3652 const char* home;
3653 LPSTR next = strchr( ptr, ':' );
3654 if (next) *next++ = 0;
3655 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3656 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3658 strcpy( unixname, home );
3659 strcat( unixname, ptr + 1 );
3660 ReadFontDir( unixname, TRUE );
3661 HeapFree( GetProcessHeap(), 0, unixname );
3663 else
3664 ReadFontDir( ptr, TRUE );
3665 ptr = next;
3667 HeapFree( GetProcessHeap(), 0, valueA );
3669 HeapFree( GetProcessHeap(), 0, valueW );
3671 RegCloseKey(hkey);
3675 static BOOL move_to_front(const WCHAR *name)
3677 Family *family, *cursor2;
3678 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3680 if(!strcmpiW(family->FamilyName, name))
3682 list_remove(&family->entry);
3683 list_add_head(&font_list, &family->entry);
3684 return TRUE;
3687 return FALSE;
3690 static BOOL set_default(const WCHAR **name_list)
3692 while (*name_list)
3694 if (move_to_front(*name_list)) return TRUE;
3695 name_list++;
3698 return FALSE;
3701 static void reorder_font_list(void)
3703 set_default( default_serif_list );
3704 set_default( default_fixed_list );
3705 set_default( default_sans_list );
3708 /*************************************************************
3709 * WineEngInit
3711 * Initialize FreeType library and create a list of available faces
3713 BOOL WineEngInit(void)
3715 HKEY hkey_font_cache;
3716 DWORD disposition;
3717 HANDLE font_mutex;
3719 /* update locale dependent font info in registry */
3720 update_font_info();
3722 if(!init_freetype()) return FALSE;
3724 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3726 ERR("Failed to create font mutex\n");
3727 return FALSE;
3729 WaitForSingleObject(font_mutex, INFINITE);
3731 create_font_cache_key(&hkey_font_cache, &disposition);
3733 if(disposition == REG_CREATED_NEW_KEY)
3734 init_font_list();
3735 else
3736 load_font_list_from_cache(hkey_font_cache);
3738 RegCloseKey(hkey_font_cache);
3740 reorder_font_list();
3742 DumpFontList();
3743 LoadSubstList();
3744 DumpSubstList();
3745 LoadReplaceList();
3747 if(disposition == REG_CREATED_NEW_KEY)
3748 update_reg_entries();
3750 init_system_links();
3752 ReleaseMutex(font_mutex);
3753 return TRUE;
3757 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3759 TT_OS2 *pOS2;
3760 TT_HoriHeader *pHori;
3762 LONG ppem;
3764 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3765 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3767 if(height == 0) height = 16;
3769 /* Calc. height of EM square:
3771 * For +ve lfHeight we have
3772 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3773 * Re-arranging gives:
3774 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3776 * For -ve lfHeight we have
3777 * |lfHeight| = ppem
3778 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3779 * with il = winAscent + winDescent - units_per_em]
3783 if(height > 0) {
3784 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3785 ppem = MulDiv(ft_face->units_per_EM, height,
3786 pHori->Ascender - pHori->Descender);
3787 else
3788 ppem = MulDiv(ft_face->units_per_EM, height,
3789 pOS2->usWinAscent + pOS2->usWinDescent);
3791 else
3792 ppem = -height;
3794 return ppem;
3797 static struct font_mapping *map_font_file( const char *name )
3799 struct font_mapping *mapping;
3800 struct stat st;
3801 int fd;
3803 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3804 if (fstat( fd, &st ) == -1) goto error;
3806 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3808 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3810 mapping->refcount++;
3811 close( fd );
3812 return mapping;
3815 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3816 goto error;
3818 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3819 close( fd );
3821 if (mapping->data == MAP_FAILED)
3823 HeapFree( GetProcessHeap(), 0, mapping );
3824 return NULL;
3826 mapping->refcount = 1;
3827 mapping->dev = st.st_dev;
3828 mapping->ino = st.st_ino;
3829 mapping->size = st.st_size;
3830 list_add_tail( &mappings_list, &mapping->entry );
3831 return mapping;
3833 error:
3834 close( fd );
3835 return NULL;
3838 static void unmap_font_file( struct font_mapping *mapping )
3840 if (!--mapping->refcount)
3842 list_remove( &mapping->entry );
3843 munmap( mapping->data, mapping->size );
3844 HeapFree( GetProcessHeap(), 0, mapping );
3848 static LONG load_VDMX(GdiFont*, LONG);
3850 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3852 FT_Error err;
3853 FT_Face ft_face;
3854 void *data_ptr;
3855 DWORD data_size;
3857 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3859 if (face->file)
3861 if (!(font->mapping = map_font_file( face->file )))
3863 WARN("failed to map %s\n", debugstr_a(face->file));
3864 return 0;
3866 data_ptr = font->mapping->data;
3867 data_size = font->mapping->size;
3869 else
3871 data_ptr = face->font_data_ptr;
3872 data_size = face->font_data_size;
3875 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3876 if(err) {
3877 ERR("FT_New_Face rets %d\n", err);
3878 return 0;
3881 /* set it here, as load_VDMX needs it */
3882 font->ft_face = ft_face;
3884 if(FT_IS_SCALABLE(ft_face)) {
3885 /* load the VDMX table if we have one */
3886 font->ppem = load_VDMX(font, height);
3887 if(font->ppem == 0)
3888 font->ppem = calc_ppem_for_height(ft_face, height);
3889 TRACE("height %d => ppem %d\n", height, font->ppem);
3891 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3892 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3893 } else {
3894 font->ppem = height;
3895 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3896 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3898 return ft_face;
3902 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3904 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3905 a single face with the requested charset. The idea is to check if
3906 the selected font supports the current ANSI codepage, if it does
3907 return the corresponding charset, else return the first charset */
3909 CHARSETINFO csi;
3910 int acp = GetACP(), i;
3911 DWORD fs0;
3913 *cp = acp;
3914 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3916 const SYSTEM_LINKS *font_link;
3918 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3919 return csi.ciCharset;
3921 font_link = find_font_link(family_name);
3922 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3923 return csi.ciCharset;
3926 for(i = 0; i < 32; i++) {
3927 fs0 = 1L << i;
3928 if(face->fs.fsCsb[0] & fs0) {
3929 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3930 *cp = csi.ciACP;
3931 return csi.ciCharset;
3933 else
3934 FIXME("TCI failing on %x\n", fs0);
3938 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3939 face->fs.fsCsb[0], face->file);
3940 *cp = acp;
3941 return DEFAULT_CHARSET;
3944 static GdiFont *alloc_font(void)
3946 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3947 ret->gmsize = 1;
3948 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3949 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3950 ret->potm = NULL;
3951 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3952 ret->total_kern_pairs = (DWORD)-1;
3953 ret->kern_pairs = NULL;
3954 list_init(&ret->hfontlist);
3955 list_init(&ret->child_fonts);
3956 return ret;
3959 static void free_font(GdiFont *font)
3961 struct list *cursor, *cursor2;
3962 DWORD i;
3964 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3966 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3967 list_remove(cursor);
3968 if(child->font)
3969 free_font(child->font);
3970 HeapFree(GetProcessHeap(), 0, child);
3973 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3975 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3976 DeleteObject(hfontlist->hfont);
3977 list_remove(&hfontlist->entry);
3978 HeapFree(GetProcessHeap(), 0, hfontlist);
3981 if (font->ft_face) pFT_Done_Face(font->ft_face);
3982 if (font->mapping) unmap_font_file( font->mapping );
3983 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3984 HeapFree(GetProcessHeap(), 0, font->potm);
3985 HeapFree(GetProcessHeap(), 0, font->name);
3986 for (i = 0; i < font->gmsize; i++)
3987 HeapFree(GetProcessHeap(),0,font->gm[i]);
3988 HeapFree(GetProcessHeap(), 0, font->gm);
3989 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3990 HeapFree(GetProcessHeap(), 0, font);
3994 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3996 FT_Face ft_face = font->ft_face;
3997 FT_ULong len;
3998 FT_Error err;
4000 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4002 if(!buf)
4003 len = 0;
4004 else
4005 len = cbData;
4007 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4009 /* make sure value of len is the value freetype says it needs */
4010 if (buf && len)
4012 FT_ULong needed = 0;
4013 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4014 if( !err && needed < len) len = needed;
4016 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4017 if (err)
4019 TRACE("Can't find table %c%c%c%c\n",
4020 /* bytes were reversed */
4021 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4022 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4023 return GDI_ERROR;
4025 return len;
4028 /*************************************************************
4029 * load_VDMX
4031 * load the vdmx entry for the specified height
4034 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4035 ( ( (FT_ULong)_x4 << 24 ) | \
4036 ( (FT_ULong)_x3 << 16 ) | \
4037 ( (FT_ULong)_x2 << 8 ) | \
4038 (FT_ULong)_x1 )
4040 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4042 typedef struct {
4043 BYTE bCharSet;
4044 BYTE xRatio;
4045 BYTE yStartRatio;
4046 BYTE yEndRatio;
4047 } Ratios;
4049 typedef struct {
4050 WORD recs;
4051 BYTE startsz;
4052 BYTE endsz;
4053 } VDMX_group;
4055 static LONG load_VDMX(GdiFont *font, LONG height)
4057 WORD hdr[3], tmp;
4058 VDMX_group group;
4059 BYTE devXRatio, devYRatio;
4060 USHORT numRecs, numRatios;
4061 DWORD result, offset = -1;
4062 LONG ppem = 0;
4063 int i;
4065 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4067 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4068 return ppem;
4070 /* FIXME: need the real device aspect ratio */
4071 devXRatio = 1;
4072 devYRatio = 1;
4074 numRecs = GET_BE_WORD(hdr[1]);
4075 numRatios = GET_BE_WORD(hdr[2]);
4077 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4078 for(i = 0; i < numRatios; i++) {
4079 Ratios ratio;
4081 offset = (3 * 2) + (i * sizeof(Ratios));
4082 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4083 offset = -1;
4085 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4087 if((ratio.xRatio == 0 &&
4088 ratio.yStartRatio == 0 &&
4089 ratio.yEndRatio == 0) ||
4090 (devXRatio == ratio.xRatio &&
4091 devYRatio >= ratio.yStartRatio &&
4092 devYRatio <= ratio.yEndRatio))
4094 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4095 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4096 offset = GET_BE_WORD(tmp);
4097 break;
4101 if(offset == -1) {
4102 FIXME("No suitable ratio found\n");
4103 return ppem;
4106 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4107 USHORT recs;
4108 BYTE startsz, endsz;
4109 WORD *vTable;
4111 recs = GET_BE_WORD(group.recs);
4112 startsz = group.startsz;
4113 endsz = group.endsz;
4115 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4117 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4118 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4119 if(result == GDI_ERROR) {
4120 FIXME("Failed to retrieve vTable\n");
4121 goto end;
4124 if(height > 0) {
4125 for(i = 0; i < recs; i++) {
4126 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4127 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4128 ppem = GET_BE_WORD(vTable[i * 3]);
4130 if(yMax + -yMin == height) {
4131 font->yMax = yMax;
4132 font->yMin = yMin;
4133 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4134 break;
4136 if(yMax + -yMin > height) {
4137 if(--i < 0) {
4138 ppem = 0;
4139 goto end; /* failed */
4141 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4142 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4143 ppem = GET_BE_WORD(vTable[i * 3]);
4144 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4145 break;
4148 if(!font->yMax) {
4149 ppem = 0;
4150 TRACE("ppem not found for height %d\n", height);
4153 end:
4154 HeapFree(GetProcessHeap(), 0, vTable);
4157 return ppem;
4160 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4162 if(font->font_desc.hash != fd->hash) return TRUE;
4163 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4164 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4165 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4166 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4169 static void calc_hash(FONT_DESC *pfd)
4171 DWORD hash = 0, *ptr, two_chars;
4172 WORD *pwc;
4173 unsigned int i;
4175 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4176 hash ^= *ptr;
4177 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4178 hash ^= *ptr;
4179 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4180 two_chars = *ptr;
4181 pwc = (WCHAR *)&two_chars;
4182 if(!*pwc) break;
4183 *pwc = toupperW(*pwc);
4184 pwc++;
4185 *pwc = toupperW(*pwc);
4186 hash ^= two_chars;
4187 if(!*pwc) break;
4189 hash ^= !pfd->can_use_bitmap;
4190 pfd->hash = hash;
4191 return;
4194 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4196 GdiFont *ret;
4197 FONT_DESC fd;
4198 HFONTLIST *hflist;
4199 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4201 fd.lf = *plf;
4202 fd.matrix = *pmat;
4203 fd.can_use_bitmap = can_use_bitmap;
4204 calc_hash(&fd);
4206 /* try the child list */
4207 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4208 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4209 if(!fontcmp(ret, &fd)) {
4210 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4211 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4212 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4213 if(hflist->hfont == hfont)
4214 return ret;
4219 /* try the in-use list */
4220 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4221 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4222 if(!fontcmp(ret, &fd)) {
4223 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4224 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4225 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4226 if(hflist->hfont == hfont)
4227 return ret;
4229 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4230 hflist->hfont = hfont;
4231 list_add_head(&ret->hfontlist, &hflist->entry);
4232 return ret;
4236 /* then the unused list */
4237 font_elem_ptr = list_head(&unused_gdi_font_list);
4238 while(font_elem_ptr) {
4239 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4240 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4241 if(!fontcmp(ret, &fd)) {
4242 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4243 assert(list_empty(&ret->hfontlist));
4244 TRACE("Found %p in unused list\n", ret);
4245 list_remove(&ret->entry);
4246 list_add_head(&gdi_font_list, &ret->entry);
4247 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4248 hflist->hfont = hfont;
4249 list_add_head(&ret->hfontlist, &hflist->entry);
4250 return ret;
4253 return NULL;
4256 static void add_to_cache(GdiFont *font)
4258 static DWORD cache_num = 1;
4260 font->cache_num = cache_num++;
4261 list_add_head(&gdi_font_list, &font->entry);
4264 /*************************************************************
4265 * create_child_font_list
4267 static BOOL create_child_font_list(GdiFont *font)
4269 BOOL ret = FALSE;
4270 SYSTEM_LINKS *font_link;
4271 CHILD_FONT *font_link_entry, *new_child;
4272 FontSubst *psub;
4273 WCHAR* font_name;
4275 psub = get_font_subst(&font_subst_list, font->name, -1);
4276 font_name = psub ? psub->to.name : font->name;
4277 font_link = find_font_link(font_name);
4278 if (font_link != NULL)
4280 TRACE("found entry in system list\n");
4281 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4283 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4284 new_child->face = font_link_entry->face;
4285 new_child->font = NULL;
4286 list_add_tail(&font->child_fonts, &new_child->entry);
4287 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4289 ret = TRUE;
4292 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4293 * Sans Serif. This is how asian windows get default fallbacks for fonts
4295 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4296 font->charset != OEM_CHARSET &&
4297 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4299 font_link = find_font_link(szDefaultFallbackLink);
4300 if (font_link != NULL)
4302 TRACE("found entry in default fallback list\n");
4303 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4305 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4306 new_child->face = font_link_entry->face;
4307 new_child->font = NULL;
4308 list_add_tail(&font->child_fonts, &new_child->entry);
4309 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4311 ret = TRUE;
4315 return ret;
4318 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4320 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4322 if (pFT_Set_Charmap)
4324 FT_Int i;
4325 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4327 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4329 for (i = 0; i < ft_face->num_charmaps; i++)
4331 if (ft_face->charmaps[i]->encoding == encoding)
4333 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4334 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4336 switch (ft_face->charmaps[i]->platform_id)
4338 default:
4339 cmap_def = ft_face->charmaps[i];
4340 break;
4341 case 0: /* Apple Unicode */
4342 cmap0 = ft_face->charmaps[i];
4343 break;
4344 case 1: /* Macintosh */
4345 cmap1 = ft_face->charmaps[i];
4346 break;
4347 case 2: /* ISO */
4348 cmap2 = ft_face->charmaps[i];
4349 break;
4350 case 3: /* Microsoft */
4351 cmap3 = ft_face->charmaps[i];
4352 break;
4356 if (cmap3) /* prefer Microsoft cmap table */
4357 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4358 else if (cmap1)
4359 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4360 else if (cmap2)
4361 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4362 else if (cmap0)
4363 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4364 else if (cmap_def)
4365 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4367 return ft_err == FT_Err_Ok;
4370 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4374 /*************************************************************
4375 * freetype_CreateDC
4377 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4378 LPCWSTR output, const DEVMODEW *devmode )
4380 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4382 if (!physdev) return FALSE;
4383 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4384 return TRUE;
4388 /*************************************************************
4389 * freetype_DeleteDC
4391 static BOOL freetype_DeleteDC( PHYSDEV dev )
4393 struct freetype_physdev *physdev = get_freetype_dev( dev );
4394 HeapFree( GetProcessHeap(), 0, physdev );
4395 return TRUE;
4399 /*************************************************************
4400 * freetype_SelectFont
4402 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
4404 struct freetype_physdev *physdev = get_freetype_dev( dev );
4405 GdiFont *ret;
4406 Face *face, *best, *best_bitmap;
4407 Family *family, *last_resort_family;
4408 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4409 INT height, width = 0;
4410 unsigned int score = 0, new_score;
4411 signed int diff = 0, newdiff;
4412 BOOL bd, it, can_use_bitmap, want_vertical;
4413 LOGFONTW lf;
4414 CHARSETINFO csi;
4415 HFONTLIST *hflist;
4416 FMAT2 dcmat;
4417 FontSubst *psub = NULL;
4418 DC *dc = get_dc_ptr( dev->hdc );
4419 const SYSTEM_LINKS *font_link;
4421 if (!hfont) /* notification that the font has been changed by another driver */
4423 dc->gdiFont = NULL;
4424 physdev->font = NULL;
4425 release_dc_ptr( dc );
4426 return 0;
4429 GetObjectW( hfont, sizeof(lf), &lf );
4430 lf.lfWidth = abs(lf.lfWidth);
4432 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4434 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4435 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4436 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4437 lf.lfEscapement);
4439 if(dc->GraphicsMode == GM_ADVANCED)
4441 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4442 /* Try to avoid not necessary glyph transformations */
4443 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4445 lf.lfHeight *= fabs(dcmat.eM11);
4446 lf.lfWidth *= fabs(dcmat.eM11);
4447 dcmat.eM11 = dcmat.eM22 = 1.0;
4450 else
4452 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4453 font scaling abilities. */
4454 dcmat.eM11 = dcmat.eM22 = 1.0;
4455 dcmat.eM21 = dcmat.eM12 = 0;
4456 if (dc->vport2WorldValid)
4458 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4459 lf.lfOrientation = -lf.lfOrientation;
4460 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4461 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4465 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4466 dcmat.eM21, dcmat.eM22);
4468 GDI_CheckNotLock();
4469 EnterCriticalSection( &freetype_cs );
4471 /* check the cache first */
4472 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4473 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4474 goto done;
4477 if(list_empty(&font_list)) /* No fonts installed */
4479 TRACE("No fonts installed\n");
4480 goto done;
4483 TRACE("not in cache\n");
4484 ret = alloc_font();
4486 ret->font_desc.matrix = dcmat;
4487 ret->font_desc.lf = lf;
4488 ret->font_desc.can_use_bitmap = can_use_bitmap;
4489 calc_hash(&ret->font_desc);
4490 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4491 hflist->hfont = hfont;
4492 list_add_head(&ret->hfontlist, &hflist->entry);
4494 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4495 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4496 original value lfCharSet. Note this is a special case for
4497 Symbol and doesn't happen at least for "Wingdings*" */
4499 if(!strcmpiW(lf.lfFaceName, SymbolW))
4500 lf.lfCharSet = SYMBOL_CHARSET;
4502 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4503 switch(lf.lfCharSet) {
4504 case DEFAULT_CHARSET:
4505 csi.fs.fsCsb[0] = 0;
4506 break;
4507 default:
4508 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4509 csi.fs.fsCsb[0] = 0;
4510 break;
4514 family = NULL;
4515 if(lf.lfFaceName[0] != '\0') {
4516 CHILD_FONT *font_link_entry;
4517 LPWSTR FaceName = lf.lfFaceName;
4519 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4521 if(psub) {
4522 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4523 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4524 if (psub->to.charset != -1)
4525 lf.lfCharSet = psub->to.charset;
4528 /* We want a match on name and charset or just name if
4529 charset was DEFAULT_CHARSET. If the latter then
4530 we fixup the returned charset later in get_nearest_charset
4531 where we'll either use the charset of the current ansi codepage
4532 or if that's unavailable the first charset that the font supports.
4534 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4535 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4536 if (!strcmpiW(family->FamilyName, FaceName) ||
4537 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4539 font_link = find_font_link(family->FamilyName);
4540 face_list = get_face_list_from_family(family);
4541 LIST_FOR_EACH(face_elem_ptr, face_list) {
4542 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4543 if (!(face->scalable || can_use_bitmap))
4544 continue;
4545 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4546 goto found;
4547 if (font_link != NULL &&
4548 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4549 goto found;
4550 if (!csi.fs.fsCsb[0])
4551 goto found;
4556 /* Search by full face name. */
4557 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4558 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4559 face_list = get_face_list_from_family(family);
4560 LIST_FOR_EACH(face_elem_ptr, face_list) {
4561 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4562 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4563 (face->scalable || can_use_bitmap))
4565 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4566 goto found_face;
4567 font_link = find_font_link(family->FamilyName);
4568 if (font_link != NULL &&
4569 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4570 goto found_face;
4576 * Try check the SystemLink list first for a replacement font.
4577 * We may find good replacements there.
4579 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4581 if(!strcmpiW(font_link->font_name, FaceName) ||
4582 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4584 TRACE("found entry in system list\n");
4585 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4587 const SYSTEM_LINKS *links;
4589 face = font_link_entry->face;
4590 if (!(face->scalable || can_use_bitmap))
4591 continue;
4592 family = face->family;
4593 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4594 goto found;
4595 links = find_font_link(family->FamilyName);
4596 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4597 goto found;
4603 psub = NULL; /* substitution is no more relevant */
4605 /* If requested charset was DEFAULT_CHARSET then try using charset
4606 corresponding to the current ansi codepage */
4607 if (!csi.fs.fsCsb[0])
4609 INT acp = GetACP();
4610 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4611 FIXME("TCI failed on codepage %d\n", acp);
4612 csi.fs.fsCsb[0] = 0;
4613 } else
4614 lf.lfCharSet = csi.ciCharset;
4617 want_vertical = (lf.lfFaceName[0] == '@');
4619 /* Face families are in the top 4 bits of lfPitchAndFamily,
4620 so mask with 0xF0 before testing */
4622 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4623 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4624 strcpyW(lf.lfFaceName, defFixed);
4625 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4626 strcpyW(lf.lfFaceName, defSerif);
4627 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4628 strcpyW(lf.lfFaceName, defSans);
4629 else
4630 strcpyW(lf.lfFaceName, defSans);
4631 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4632 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4633 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4634 font_link = find_font_link(family->FamilyName);
4635 face_list = get_face_list_from_family(family);
4636 LIST_FOR_EACH(face_elem_ptr, face_list) {
4637 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4638 if (!(face->scalable || can_use_bitmap))
4639 continue;
4640 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4641 goto found;
4642 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4643 goto found;
4648 last_resort_family = NULL;
4649 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4650 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4651 font_link = find_font_link(family->FamilyName);
4652 face_list = get_face_list_from_family(family);
4653 LIST_FOR_EACH(face_elem_ptr, face_list) {
4654 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4655 if(face->vertical == want_vertical &&
4656 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4657 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4658 if(face->scalable)
4659 goto found;
4660 if(can_use_bitmap && !last_resort_family)
4661 last_resort_family = family;
4666 if(last_resort_family) {
4667 family = last_resort_family;
4668 csi.fs.fsCsb[0] = 0;
4669 goto found;
4672 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4673 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4674 face_list = get_face_list_from_family(family);
4675 LIST_FOR_EACH(face_elem_ptr, face_list) {
4676 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4677 if(face->scalable && face->vertical == want_vertical) {
4678 csi.fs.fsCsb[0] = 0;
4679 WARN("just using first face for now\n");
4680 goto found;
4682 if(can_use_bitmap && !last_resort_family)
4683 last_resort_family = family;
4686 if(!last_resort_family) {
4687 FIXME("can't find a single appropriate font - bailing\n");
4688 free_font(ret);
4689 ret = NULL;
4690 goto done;
4693 WARN("could only find a bitmap font - this will probably look awful!\n");
4694 family = last_resort_family;
4695 csi.fs.fsCsb[0] = 0;
4697 found:
4698 it = lf.lfItalic ? 1 : 0;
4699 bd = lf.lfWeight > 550 ? 1 : 0;
4701 height = lf.lfHeight;
4703 face = best = best_bitmap = NULL;
4704 font_link = find_font_link(family->FamilyName);
4705 face_list = get_face_list_from_family(family);
4706 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4708 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4709 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4710 !csi.fs.fsCsb[0])
4712 BOOL italic, bold;
4714 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4715 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4716 new_score = (italic ^ it) + (bold ^ bd);
4717 if(!best || new_score <= score)
4719 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4720 italic, bold, it, bd);
4721 score = new_score;
4722 best = face;
4723 if(best->scalable && score == 0) break;
4724 if(!best->scalable)
4726 if(height > 0)
4727 newdiff = height - (signed int)(best->size.height);
4728 else
4729 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4730 if(!best_bitmap || new_score < score ||
4731 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4733 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4734 diff = newdiff;
4735 best_bitmap = best;
4736 if(score == 0 && diff == 0) break;
4742 if(best)
4743 face = best->scalable ? best : best_bitmap;
4744 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4745 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4747 found_face:
4748 height = lf.lfHeight;
4750 ret->fs = face->fs;
4752 if(csi.fs.fsCsb[0]) {
4753 ret->charset = lf.lfCharSet;
4754 ret->codepage = csi.ciACP;
4756 else
4757 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4759 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4760 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4762 ret->aveWidth = height ? lf.lfWidth : 0;
4764 if(!face->scalable) {
4765 /* Windows uses integer scaling factors for bitmap fonts */
4766 INT scale, scaled_height;
4767 GdiFont *cachedfont;
4769 /* FIXME: rotation of bitmap fonts is ignored */
4770 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4771 if (ret->aveWidth)
4772 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4773 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4774 dcmat.eM11 = dcmat.eM22 = 1.0;
4775 /* As we changed the matrix, we need to search the cache for the font again,
4776 * otherwise we might explode the cache. */
4777 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4778 TRACE("Found cached font after non-scalable matrix rescale!\n");
4779 free_font( ret );
4780 ret = cachedfont;
4781 goto done;
4783 calc_hash(&ret->font_desc);
4785 if (height != 0) height = diff;
4786 height += face->size.height;
4788 scale = (height + face->size.height - 1) / face->size.height;
4789 scaled_height = scale * face->size.height;
4790 /* Only jump to the next height if the difference <= 25% original height */
4791 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4792 /* The jump between unscaled and doubled is delayed by 1 */
4793 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4794 ret->scale_y = scale;
4796 width = face->size.x_ppem >> 6;
4797 height = face->size.y_ppem >> 6;
4799 else
4800 ret->scale_y = 1.0;
4801 TRACE("font scale y: %f\n", ret->scale_y);
4803 ret->ft_face = OpenFontFace(ret, face, width, height);
4805 if (!ret->ft_face)
4807 free_font( ret );
4808 ret = NULL;
4809 goto done;
4812 ret->ntmFlags = face->ntmFlags;
4814 if (ret->charset == SYMBOL_CHARSET &&
4815 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4816 /* No ops */
4818 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4819 /* No ops */
4821 else {
4822 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4825 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4826 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4827 ret->underline = lf.lfUnderline ? 0xff : 0;
4828 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4829 create_child_font_list(ret);
4831 if (face->vertical) /* We need to try to load the GSUB table */
4833 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4834 if (length != GDI_ERROR)
4836 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4837 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4838 TRACE("Loaded GSUB table of %i bytes\n",length);
4842 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4844 add_to_cache(ret);
4845 done:
4846 if (ret)
4848 dc->gdiFont = ret;
4849 physdev->font = ret;
4851 LeaveCriticalSection( &freetype_cs );
4852 release_dc_ptr( dc );
4853 return ret ? hfont : 0;
4856 static void dump_gdi_font_list(void)
4858 GdiFont *gdiFont;
4859 struct list *elem_ptr;
4861 TRACE("---------- gdiFont Cache ----------\n");
4862 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4863 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4864 TRACE("gdiFont=%p %s %d\n",
4865 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4868 TRACE("---------- Unused gdiFont Cache ----------\n");
4869 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4870 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4871 TRACE("gdiFont=%p %s %d\n",
4872 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4875 TRACE("---------- Child gdiFont Cache ----------\n");
4876 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4877 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4878 TRACE("gdiFont=%p %s %d\n",
4879 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4883 /*************************************************************
4884 * WineEngDestroyFontInstance
4886 * free the gdiFont associated with this handle
4889 BOOL WineEngDestroyFontInstance(HFONT handle)
4891 GdiFont *gdiFont;
4892 HFONTLIST *hflist;
4893 BOOL ret = FALSE;
4894 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4895 int i = 0;
4897 GDI_CheckNotLock();
4898 EnterCriticalSection( &freetype_cs );
4900 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4902 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4903 while(hfontlist_elem_ptr) {
4904 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4905 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4906 if(hflist->hfont == handle) {
4907 TRACE("removing child font %p from child list\n", gdiFont);
4908 list_remove(&gdiFont->entry);
4909 LeaveCriticalSection( &freetype_cs );
4910 return TRUE;
4915 TRACE("destroying hfont=%p\n", handle);
4916 if(TRACE_ON(font))
4917 dump_gdi_font_list();
4919 font_elem_ptr = list_head(&gdi_font_list);
4920 while(font_elem_ptr) {
4921 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4922 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4924 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4925 while(hfontlist_elem_ptr) {
4926 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4927 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4928 if(hflist->hfont == handle) {
4929 list_remove(&hflist->entry);
4930 HeapFree(GetProcessHeap(), 0, hflist);
4931 ret = TRUE;
4934 if(list_empty(&gdiFont->hfontlist)) {
4935 TRACE("Moving to Unused list\n");
4936 list_remove(&gdiFont->entry);
4937 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4942 font_elem_ptr = list_head(&unused_gdi_font_list);
4943 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4944 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4945 while(font_elem_ptr) {
4946 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4947 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4948 TRACE("freeing %p\n", gdiFont);
4949 list_remove(&gdiFont->entry);
4950 free_font(gdiFont);
4952 LeaveCriticalSection( &freetype_cs );
4953 return ret;
4956 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4958 HRSRC rsrc;
4959 HGLOBAL hMem;
4960 WCHAR *p;
4961 int i;
4963 id += IDS_FIRST_SCRIPT;
4964 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4965 if (!rsrc) return 0;
4966 hMem = LoadResource( gdi32_module, rsrc );
4967 if (!hMem) return 0;
4969 p = LockResource( hMem );
4970 id &= 0x000f;
4971 while (id--) p += *p + 1;
4973 i = min(LF_FACESIZE - 1, *p);
4974 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4975 buffer[i] = 0;
4976 return i;
4980 /***************************************************
4981 * create_enum_charset_list
4983 * This function creates charset enumeration list because in DEFAULT_CHARSET
4984 * case, the ANSI codepage's charset takes precedence over other charsets.
4985 * This function works as a filter other than DEFAULT_CHARSET case.
4987 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4989 CHARSETINFO csi;
4990 DWORD n = 0;
4992 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4993 csi.fs.fsCsb[0] != 0) {
4994 list->element[n].mask = csi.fs.fsCsb[0];
4995 list->element[n].charset = csi.ciCharset;
4996 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4997 n++;
4999 else { /* charset is DEFAULT_CHARSET or invalid. */
5000 INT acp, i;
5002 /* Set the current codepage's charset as the first element. */
5003 acp = GetACP();
5004 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5005 csi.fs.fsCsb[0] != 0) {
5006 list->element[n].mask = csi.fs.fsCsb[0];
5007 list->element[n].charset = csi.ciCharset;
5008 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5009 n++;
5012 /* Fill out left elements. */
5013 for (i = 0; i < 32; i++) {
5014 FONTSIGNATURE fs;
5015 fs.fsCsb[0] = 1L << i;
5016 fs.fsCsb[1] = 0;
5017 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
5018 continue; /* skip, already added. */
5019 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5020 continue; /* skip, this is an invalid fsCsb bit. */
5022 list->element[n].mask = fs.fsCsb[0];
5023 list->element[n].charset = csi.ciCharset;
5024 load_script_name( i, list->element[n].name );
5025 n++;
5028 list->total = n;
5030 return n;
5033 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5034 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5036 GdiFont *font;
5037 LONG width, height;
5039 if (face->cached_enum_data)
5041 TRACE("Cached\n");
5042 *pelf = face->cached_enum_data->elf;
5043 *pntm = face->cached_enum_data->ntm;
5044 *ptype = face->cached_enum_data->type;
5045 return;
5048 font = alloc_font();
5050 if(face->scalable) {
5051 height = -2048; /* 2048 is the most common em size */
5052 width = 0;
5053 } else {
5054 height = face->size.y_ppem >> 6;
5055 width = face->size.x_ppem >> 6;
5057 font->scale_y = 1.0;
5059 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5061 free_font(font);
5062 return;
5065 font->name = strdupW(face->family->FamilyName);
5066 font->ntmFlags = face->ntmFlags;
5068 if (get_outline_text_metrics(font))
5070 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5072 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5074 lstrcpynW(pelf->elfLogFont.lfFaceName,
5075 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5076 LF_FACESIZE);
5077 lstrcpynW(pelf->elfFullName,
5078 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
5079 LF_FULLFACESIZE);
5080 lstrcpynW(pelf->elfStyle,
5081 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5082 LF_FACESIZE);
5084 else
5086 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5088 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5090 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5091 if (face->FullName)
5092 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5093 else
5094 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5095 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5098 pntm->ntmTm.ntmFlags = face->ntmFlags;
5099 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5100 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5101 pntm->ntmFontSig = face->fs;
5103 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5105 pelf->elfLogFont.lfEscapement = 0;
5106 pelf->elfLogFont.lfOrientation = 0;
5107 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5108 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5109 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5110 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5111 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5112 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5113 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5114 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5115 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5116 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5117 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5119 *ptype = 0;
5120 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5121 *ptype |= TRUETYPE_FONTTYPE;
5122 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5123 *ptype |= DEVICE_FONTTYPE;
5124 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5125 *ptype |= RASTER_FONTTYPE;
5127 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5128 if (face->cached_enum_data)
5130 face->cached_enum_data->elf = *pelf;
5131 face->cached_enum_data->ntm = *pntm;
5132 face->cached_enum_data->type = *ptype;
5135 free_font(font);
5138 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
5140 static const WCHAR spaceW[] = { ' ', 0 };
5142 strcpyW(full_name, family_name);
5143 strcatW(full_name, spaceW);
5144 strcatW(full_name, style_name);
5147 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5149 const struct list *face_list, *face_elem_ptr;
5151 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5153 face_list = get_face_list_from_family(family);
5154 LIST_FOR_EACH(face_elem_ptr, face_list)
5156 WCHAR full_family_name[LF_FULLFACESIZE];
5157 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5159 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
5161 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5162 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
5163 continue;
5166 create_full_name(full_family_name, family->FamilyName, face->StyleName);
5167 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
5170 return FALSE;
5173 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5175 WCHAR full_family_name[LF_FULLFACESIZE];
5177 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5179 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
5181 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5182 debugstr_w(family_name), debugstr_w(face->StyleName));
5183 return FALSE;
5186 create_full_name(full_family_name, family_name, face->StyleName);
5187 return !strcmpiW(lf->lfFaceName, full_family_name);
5190 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5191 FONTENUMPROCW proc, LPARAM lparam)
5193 ENUMLOGFONTEXW elf;
5194 NEWTEXTMETRICEXW ntm;
5195 DWORD type = 0;
5196 int i;
5198 GetEnumStructs(face, &elf, &ntm, &type);
5199 for(i = 0; i < list->total; i++) {
5200 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5201 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5202 load_script_name( IDS_OEM_DOS, elf.elfScript );
5203 i = list->total; /* break out of loop after enumeration */
5204 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
5205 continue;
5206 else {
5207 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5208 strcpyW(elf.elfScript, list->element[i].name);
5209 if (!elf.elfScript[0])
5210 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5212 /* Font Replacement */
5213 if (family != face->family)
5215 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5216 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
5218 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5219 debugstr_w(elf.elfLogFont.lfFaceName),
5220 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5221 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5222 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5223 ntm.ntmTm.ntmFlags);
5224 /* release section before callback (FIXME) */
5225 LeaveCriticalSection( &freetype_cs );
5226 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5227 EnterCriticalSection( &freetype_cs );
5229 return TRUE;
5232 /*************************************************************
5233 * freetype_EnumFonts
5235 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5237 Family *family;
5238 Face *face;
5239 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5240 LOGFONTW lf;
5241 struct enum_charset_list enum_charsets;
5243 if (!plf)
5245 lf.lfCharSet = DEFAULT_CHARSET;
5246 lf.lfPitchAndFamily = 0;
5247 lf.lfFaceName[0] = 0;
5248 plf = &lf;
5251 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5253 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5255 GDI_CheckNotLock();
5256 EnterCriticalSection( &freetype_cs );
5257 if(plf->lfFaceName[0]) {
5258 FontSubst *psub;
5259 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5261 if(psub) {
5262 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5263 debugstr_w(psub->to.name));
5264 lf = *plf;
5265 strcpyW(lf.lfFaceName, psub->to.name);
5266 plf = &lf;
5269 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5270 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5271 if(family_matches(family, plf)) {
5272 face_list = get_face_list_from_family(family);
5273 LIST_FOR_EACH(face_elem_ptr, face_list) {
5274 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5275 if (!face_matches(family->FamilyName, face, plf)) continue;
5276 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5280 } else {
5281 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5282 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5283 face_list = get_face_list_from_family(family);
5284 face_elem_ptr = list_head(face_list);
5285 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5286 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5289 LeaveCriticalSection( &freetype_cs );
5290 return TRUE;
5293 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5295 pt->x.value = vec->x >> 6;
5296 pt->x.fract = (vec->x & 0x3f) << 10;
5297 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5298 pt->y.value = vec->y >> 6;
5299 pt->y.fract = (vec->y & 0x3f) << 10;
5300 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5301 return;
5304 /***************************************************
5305 * According to the MSDN documentation on WideCharToMultiByte,
5306 * certain codepages cannot set the default_used parameter.
5307 * This returns TRUE if the codepage can set that parameter, false else
5308 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5310 static BOOL codepage_sets_default_used(UINT codepage)
5312 switch (codepage)
5314 case CP_UTF7:
5315 case CP_UTF8:
5316 case CP_SYMBOL:
5317 return FALSE;
5318 default:
5319 return TRUE;
5324 * GSUB Table handling functions
5327 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5329 const GSUB_CoverageFormat1* cf1;
5331 cf1 = table;
5333 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5335 int count = GET_BE_WORD(cf1->GlyphCount);
5336 int i;
5337 TRACE("Coverage Format 1, %i glyphs\n",count);
5338 for (i = 0; i < count; i++)
5339 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5340 return i;
5341 return -1;
5343 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5345 const GSUB_CoverageFormat2* cf2;
5346 int i;
5347 int count;
5348 cf2 = (const GSUB_CoverageFormat2*)cf1;
5350 count = GET_BE_WORD(cf2->RangeCount);
5351 TRACE("Coverage Format 2, %i ranges\n",count);
5352 for (i = 0; i < count; i++)
5354 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5355 return -1;
5356 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5357 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5359 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5360 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5363 return -1;
5365 else
5366 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5368 return -1;
5371 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5373 const GSUB_ScriptList *script;
5374 const GSUB_Script *deflt = NULL;
5375 int i;
5376 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5378 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5379 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5381 const GSUB_Script *scr;
5382 int offset;
5384 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5385 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5387 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5388 return scr;
5389 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5390 deflt = scr;
5392 return deflt;
5395 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5397 int i;
5398 int offset;
5399 const GSUB_LangSys *Lang;
5401 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5403 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5405 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5406 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5408 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5409 return Lang;
5411 offset = GET_BE_WORD(script->DefaultLangSys);
5412 if (offset)
5414 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5415 return Lang;
5417 return NULL;
5420 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5422 int i;
5423 const GSUB_FeatureList *feature;
5424 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5426 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5427 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5429 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5430 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5432 const GSUB_Feature *feat;
5433 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5434 return feat;
5437 return NULL;
5440 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5442 int i;
5443 int offset;
5444 const GSUB_LookupList *lookup;
5445 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5447 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5448 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5450 const GSUB_LookupTable *look;
5451 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5452 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5453 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5454 if (GET_BE_WORD(look->LookupType) != 1)
5455 FIXME("We only handle SubType 1\n");
5456 else
5458 int j;
5460 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5462 const GSUB_SingleSubstFormat1 *ssf1;
5463 offset = GET_BE_WORD(look->SubTable[j]);
5464 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5465 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5467 int offset = GET_BE_WORD(ssf1->Coverage);
5468 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5469 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5471 TRACE(" Glyph 0x%x ->",glyph);
5472 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5473 TRACE(" 0x%x\n",glyph);
5476 else
5478 const GSUB_SingleSubstFormat2 *ssf2;
5479 INT index;
5480 INT offset;
5482 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5483 offset = GET_BE_WORD(ssf1->Coverage);
5484 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5485 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5486 TRACE(" Coverage index %i\n",index);
5487 if (index != -1)
5489 TRACE(" Glyph is 0x%x ->",glyph);
5490 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5491 TRACE("0x%x\n",glyph);
5497 return glyph;
5500 static const char* get_opentype_script(const GdiFont *font)
5503 * I am not sure if this is the correct way to generate our script tag
5506 switch (font->charset)
5508 case ANSI_CHARSET: return "latn";
5509 case BALTIC_CHARSET: return "latn"; /* ?? */
5510 case CHINESEBIG5_CHARSET: return "hani";
5511 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5512 case GB2312_CHARSET: return "hani";
5513 case GREEK_CHARSET: return "grek";
5514 case HANGUL_CHARSET: return "hang";
5515 case RUSSIAN_CHARSET: return "cyrl";
5516 case SHIFTJIS_CHARSET: return "kana";
5517 case TURKISH_CHARSET: return "latn"; /* ?? */
5518 case VIETNAMESE_CHARSET: return "latn";
5519 case JOHAB_CHARSET: return "latn"; /* ?? */
5520 case ARABIC_CHARSET: return "arab";
5521 case HEBREW_CHARSET: return "hebr";
5522 case THAI_CHARSET: return "thai";
5523 default: return "latn";
5527 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5529 const GSUB_Header *header;
5530 const GSUB_Script *script;
5531 const GSUB_LangSys *language;
5532 const GSUB_Feature *feature;
5534 if (!font->GSUB_Table)
5535 return glyph;
5537 header = font->GSUB_Table;
5539 script = GSUB_get_script_table(header, get_opentype_script(font));
5540 if (!script)
5542 TRACE("Script not found\n");
5543 return glyph;
5545 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5546 if (!language)
5548 TRACE("Language not found\n");
5549 return glyph;
5551 feature = GSUB_get_feature(header, language, "vrt2");
5552 if (!feature)
5553 feature = GSUB_get_feature(header, language, "vert");
5554 if (!feature)
5556 TRACE("vrt2/vert feature not found\n");
5557 return glyph;
5559 return GSUB_apply_feature(header, feature, glyph);
5562 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5564 FT_UInt glyphId;
5566 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5567 WCHAR wc = (WCHAR)glyph;
5568 BOOL default_used;
5569 BOOL *default_used_pointer;
5570 FT_UInt ret;
5571 char buf;
5572 default_used_pointer = NULL;
5573 default_used = FALSE;
5574 if (codepage_sets_default_used(font->codepage))
5575 default_used_pointer = &default_used;
5576 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5577 ret = 0;
5578 else
5579 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5580 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5581 return ret;
5584 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5586 if (glyph < 0x100) glyph += 0xf000;
5587 /* there is a number of old pre-Unicode "broken" TTFs, which
5588 do have symbols at U+00XX instead of U+f0XX */
5589 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5590 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5592 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5594 return glyphId;
5597 /*************************************************************
5598 * freetype_GetGlyphIndices
5600 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5602 struct freetype_physdev *physdev = get_freetype_dev( dev );
5603 int i;
5604 WORD default_char;
5605 BOOL got_default = FALSE;
5607 if (!physdev->font)
5609 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5610 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5613 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5615 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5616 got_default = TRUE;
5619 GDI_CheckNotLock();
5620 EnterCriticalSection( &freetype_cs );
5622 for(i = 0; i < count; i++)
5624 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5625 if (pgi[i] == 0)
5627 if (!got_default)
5629 if (FT_IS_SFNT(physdev->font->ft_face))
5631 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5632 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5634 else
5636 TEXTMETRICW textm;
5637 get_text_metrics(physdev->font, &textm);
5638 default_char = textm.tmDefaultChar;
5640 got_default = TRUE;
5642 pgi[i] = default_char;
5645 LeaveCriticalSection( &freetype_cs );
5646 return count;
5649 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5651 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5652 return !memcmp(matrix, &identity, sizeof(FMAT2));
5655 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5657 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5658 return !memcmp(matrix, &identity, sizeof(MAT2));
5661 static inline BYTE get_max_level( UINT format )
5663 switch( format )
5665 case GGO_GRAY2_BITMAP: return 4;
5666 case GGO_GRAY4_BITMAP: return 16;
5667 case GGO_GRAY8_BITMAP: return 64;
5669 return 255;
5672 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5674 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5675 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5676 const MAT2* lpmat)
5678 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5679 FT_Face ft_face = incoming_font->ft_face;
5680 GdiFont *font = incoming_font;
5681 FT_UInt glyph_index;
5682 DWORD width, height, pitch, needed = 0;
5683 FT_Bitmap ft_bitmap;
5684 FT_Error err;
5685 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5686 FT_Angle angle = 0;
5687 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5688 double widthRatio = 1.0;
5689 FT_Matrix transMat = identityMat;
5690 FT_Matrix transMatUnrotated;
5691 BOOL needsTransform = FALSE;
5692 BOOL tategaki = (font->GSUB_Table != NULL);
5693 UINT original_index;
5695 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5696 buflen, buf, lpmat);
5698 TRACE("font transform %f %f %f %f\n",
5699 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5700 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5702 if(format & GGO_GLYPH_INDEX) {
5703 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5704 original_index = glyph;
5705 format &= ~GGO_GLYPH_INDEX;
5706 } else {
5707 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5708 ft_face = font->ft_face;
5709 original_index = glyph_index;
5712 if(format & GGO_UNHINTED) {
5713 load_flags |= FT_LOAD_NO_HINTING;
5714 format &= ~GGO_UNHINTED;
5717 /* tategaki never appears to happen to lower glyph index */
5718 if (glyph_index < TATEGAKI_LOWER_BOUND )
5719 tategaki = FALSE;
5721 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5722 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5723 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5724 font->gmsize * sizeof(GM*));
5725 } else {
5726 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5727 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5729 *lpgm = FONT_GM(font,original_index)->gm;
5730 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5731 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5732 lpgm->gmCellIncX, lpgm->gmCellIncY);
5733 return 1; /* FIXME */
5737 if (!font->gm[original_index / GM_BLOCK_SIZE])
5738 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5740 /* Scaling factor */
5741 if (font->aveWidth)
5743 TEXTMETRICW tm;
5745 get_text_metrics(font, &tm);
5747 widthRatio = (double)font->aveWidth;
5748 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5750 else
5751 widthRatio = font->scale_y;
5753 /* Scaling transform */
5754 if (widthRatio != 1.0 || font->scale_y != 1.0)
5756 FT_Matrix scaleMat;
5757 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5758 scaleMat.xy = 0;
5759 scaleMat.yx = 0;
5760 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5762 pFT_Matrix_Multiply(&scaleMat, &transMat);
5763 needsTransform = TRUE;
5766 /* Slant transform */
5767 if (font->fake_italic) {
5768 FT_Matrix slantMat;
5770 slantMat.xx = (1 << 16);
5771 slantMat.xy = ((1 << 16) >> 2);
5772 slantMat.yx = 0;
5773 slantMat.yy = (1 << 16);
5774 pFT_Matrix_Multiply(&slantMat, &transMat);
5775 needsTransform = TRUE;
5778 /* Rotation transform */
5779 transMatUnrotated = transMat;
5780 if(font->orientation && !tategaki) {
5781 FT_Matrix rotationMat;
5782 FT_Vector vecAngle;
5783 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5784 pFT_Vector_Unit(&vecAngle, angle);
5785 rotationMat.xx = vecAngle.x;
5786 rotationMat.xy = -vecAngle.y;
5787 rotationMat.yx = -rotationMat.xy;
5788 rotationMat.yy = rotationMat.xx;
5790 pFT_Matrix_Multiply(&rotationMat, &transMat);
5791 needsTransform = TRUE;
5794 /* World transform */
5795 if (!is_identity_FMAT2(&font->font_desc.matrix))
5797 FT_Matrix worldMat;
5798 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5799 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5800 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5801 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5802 pFT_Matrix_Multiply(&worldMat, &transMat);
5803 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5804 needsTransform = TRUE;
5807 /* Extra transformation specified by caller */
5808 if (!is_identity_MAT2(lpmat))
5810 FT_Matrix extraMat;
5811 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5812 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5813 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5814 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5815 pFT_Matrix_Multiply(&extraMat, &transMat);
5816 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5817 needsTransform = TRUE;
5820 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5821 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5822 format == GGO_GRAY8_BITMAP))
5824 load_flags |= FT_LOAD_NO_BITMAP;
5827 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5829 if(err) {
5830 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5831 return GDI_ERROR;
5834 if(!needsTransform) {
5835 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5836 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5837 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5839 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5840 bottom = (ft_face->glyph->metrics.horiBearingY -
5841 ft_face->glyph->metrics.height) & -64;
5842 lpgm->gmCellIncX = adv;
5843 lpgm->gmCellIncY = 0;
5844 } else {
5845 INT xc, yc;
5846 FT_Vector vec;
5848 left = right = 0;
5850 for(xc = 0; xc < 2; xc++) {
5851 for(yc = 0; yc < 2; yc++) {
5852 vec.x = (ft_face->glyph->metrics.horiBearingX +
5853 xc * ft_face->glyph->metrics.width);
5854 vec.y = ft_face->glyph->metrics.horiBearingY -
5855 yc * ft_face->glyph->metrics.height;
5856 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5857 pFT_Vector_Transform(&vec, &transMat);
5858 if(xc == 0 && yc == 0) {
5859 left = right = vec.x;
5860 top = bottom = vec.y;
5861 } else {
5862 if(vec.x < left) left = vec.x;
5863 else if(vec.x > right) right = vec.x;
5864 if(vec.y < bottom) bottom = vec.y;
5865 else if(vec.y > top) top = vec.y;
5869 left = left & -64;
5870 right = (right + 63) & -64;
5871 bottom = bottom & -64;
5872 top = (top + 63) & -64;
5874 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5875 vec.x = ft_face->glyph->metrics.horiAdvance;
5876 vec.y = 0;
5877 pFT_Vector_Transform(&vec, &transMat);
5878 lpgm->gmCellIncX = (vec.x+63) >> 6;
5879 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5881 vec.x = ft_face->glyph->metrics.horiAdvance;
5882 vec.y = 0;
5883 pFT_Vector_Transform(&vec, &transMatUnrotated);
5884 adv = (vec.x+63) >> 6;
5887 lsb = left >> 6;
5888 bbx = (right - left) >> 6;
5889 lpgm->gmBlackBoxX = (right - left) >> 6;
5890 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5891 lpgm->gmptGlyphOrigin.x = left >> 6;
5892 lpgm->gmptGlyphOrigin.y = top >> 6;
5894 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5895 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5896 lpgm->gmCellIncX, lpgm->gmCellIncY);
5898 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5899 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5901 FONT_GM(font,original_index)->gm = *lpgm;
5902 FONT_GM(font,original_index)->adv = adv;
5903 FONT_GM(font,original_index)->lsb = lsb;
5904 FONT_GM(font,original_index)->bbx = bbx;
5905 FONT_GM(font,original_index)->init = TRUE;
5908 if(format == GGO_METRICS)
5910 return 1; /* FIXME */
5913 if(ft_face->glyph->format != ft_glyph_format_outline &&
5914 (format == GGO_NATIVE || format == GGO_BEZIER))
5916 TRACE("loaded a bitmap\n");
5917 return GDI_ERROR;
5920 switch(format) {
5921 case GGO_BITMAP:
5922 width = lpgm->gmBlackBoxX;
5923 height = lpgm->gmBlackBoxY;
5924 pitch = ((width + 31) >> 5) << 2;
5925 needed = pitch * height;
5927 if(!buf || !buflen) break;
5929 switch(ft_face->glyph->format) {
5930 case ft_glyph_format_bitmap:
5932 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5933 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5934 INT h = ft_face->glyph->bitmap.rows;
5935 while(h--) {
5936 memcpy(dst, src, w);
5937 src += ft_face->glyph->bitmap.pitch;
5938 dst += pitch;
5940 break;
5943 case ft_glyph_format_outline:
5944 ft_bitmap.width = width;
5945 ft_bitmap.rows = height;
5946 ft_bitmap.pitch = pitch;
5947 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5948 ft_bitmap.buffer = buf;
5950 if(needsTransform)
5951 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5953 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5955 /* Note: FreeType will only set 'black' bits for us. */
5956 memset(buf, 0, needed);
5957 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5958 break;
5960 default:
5961 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5962 return GDI_ERROR;
5964 break;
5966 case GGO_GRAY2_BITMAP:
5967 case GGO_GRAY4_BITMAP:
5968 case GGO_GRAY8_BITMAP:
5969 case WINE_GGO_GRAY16_BITMAP:
5971 unsigned int max_level, row, col;
5972 BYTE *start, *ptr;
5974 width = lpgm->gmBlackBoxX;
5975 height = lpgm->gmBlackBoxY;
5976 pitch = (width + 3) / 4 * 4;
5977 needed = pitch * height;
5979 if(!buf || !buflen) break;
5981 max_level = get_max_level( format );
5983 switch(ft_face->glyph->format) {
5984 case ft_glyph_format_bitmap:
5986 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5987 INT h = ft_face->glyph->bitmap.rows;
5988 INT x;
5989 memset( buf, 0, needed );
5990 while(h--) {
5991 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5992 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5993 src += ft_face->glyph->bitmap.pitch;
5994 dst += pitch;
5996 return needed;
5998 case ft_glyph_format_outline:
6000 ft_bitmap.width = width;
6001 ft_bitmap.rows = height;
6002 ft_bitmap.pitch = pitch;
6003 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6004 ft_bitmap.buffer = buf;
6006 if(needsTransform)
6007 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6009 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6011 memset(ft_bitmap.buffer, 0, buflen);
6013 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6015 if (max_level != 255)
6017 for (row = 0, start = buf; row < height; row++)
6019 for (col = 0, ptr = start; col < width; col++, ptr++)
6020 *ptr = (((int)*ptr) * max_level + 128) / 256;
6021 start += pitch;
6024 return needed;
6027 default:
6028 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6029 return GDI_ERROR;
6031 break;
6034 case WINE_GGO_HRGB_BITMAP:
6035 case WINE_GGO_HBGR_BITMAP:
6036 case WINE_GGO_VRGB_BITMAP:
6037 case WINE_GGO_VBGR_BITMAP:
6038 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6040 switch (ft_face->glyph->format)
6042 case FT_GLYPH_FORMAT_BITMAP:
6044 BYTE *src, *dst;
6045 INT src_pitch, x;
6047 width = lpgm->gmBlackBoxX;
6048 height = lpgm->gmBlackBoxY;
6049 pitch = width * 4;
6050 needed = pitch * height;
6052 if (!buf || !buflen) break;
6054 memset(buf, 0, buflen);
6055 dst = buf;
6056 src = ft_face->glyph->bitmap.buffer;
6057 src_pitch = ft_face->glyph->bitmap.pitch;
6059 height = min( height, ft_face->glyph->bitmap.rows );
6060 while ( height-- )
6062 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6064 if ( src[x / 8] & masks[x % 8] )
6065 ((unsigned int *)dst)[x] = ~0u;
6067 src += src_pitch;
6068 dst += pitch;
6071 break;
6074 case FT_GLYPH_FORMAT_OUTLINE:
6076 unsigned int *dst;
6077 BYTE *src;
6078 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6079 INT x_shift, y_shift;
6080 BOOL rgb;
6081 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6082 FT_Render_Mode render_mode =
6083 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6084 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6086 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6088 if ( render_mode == FT_RENDER_MODE_LCD)
6090 lpgm->gmBlackBoxX += 2;
6091 lpgm->gmptGlyphOrigin.x -= 1;
6093 else
6095 lpgm->gmBlackBoxY += 2;
6096 lpgm->gmptGlyphOrigin.y += 1;
6100 width = lpgm->gmBlackBoxX;
6101 height = lpgm->gmBlackBoxY;
6102 pitch = width * 4;
6103 needed = pitch * height;
6105 if (!buf || !buflen) break;
6107 memset(buf, 0, buflen);
6108 dst = buf;
6109 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6111 if ( needsTransform )
6112 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6114 if ( pFT_Library_SetLcdFilter )
6115 pFT_Library_SetLcdFilter( library, lcdfilter );
6116 pFT_Render_Glyph (ft_face->glyph, render_mode);
6118 src = ft_face->glyph->bitmap.buffer;
6119 src_pitch = ft_face->glyph->bitmap.pitch;
6120 src_width = ft_face->glyph->bitmap.width;
6121 src_height = ft_face->glyph->bitmap.rows;
6123 if ( render_mode == FT_RENDER_MODE_LCD)
6125 rgb_interval = 1;
6126 hmul = 3;
6127 vmul = 1;
6129 else
6131 rgb_interval = src_pitch;
6132 hmul = 1;
6133 vmul = 3;
6136 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6137 if ( x_shift < 0 ) x_shift = 0;
6138 if ( x_shift + (src_width / hmul) > width )
6139 x_shift = width - (src_width / hmul);
6141 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6142 if ( y_shift < 0 ) y_shift = 0;
6143 if ( y_shift + (src_height / vmul) > height )
6144 y_shift = height - (src_height / vmul);
6146 dst += x_shift + y_shift * ( pitch / 4 );
6147 while ( src_height )
6149 for ( x = 0; x < src_width / hmul; x++ )
6151 if ( rgb )
6153 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6154 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6155 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6156 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6158 else
6160 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6161 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6162 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6163 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6166 src += src_pitch * vmul;
6167 dst += pitch / 4;
6168 src_height -= vmul;
6171 break;
6174 default:
6175 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6176 return GDI_ERROR;
6179 break;
6181 #else
6182 return GDI_ERROR;
6183 #endif
6185 case GGO_NATIVE:
6187 int contour, point = 0, first_pt;
6188 FT_Outline *outline = &ft_face->glyph->outline;
6189 TTPOLYGONHEADER *pph;
6190 TTPOLYCURVE *ppc;
6191 DWORD pph_start, cpfx, type;
6193 if(buflen == 0) buf = NULL;
6195 if (needsTransform && buf) {
6196 pFT_Outline_Transform(outline, &transMat);
6199 for(contour = 0; contour < outline->n_contours; contour++) {
6200 pph_start = needed;
6201 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6202 first_pt = point;
6203 if(buf) {
6204 pph->dwType = TT_POLYGON_TYPE;
6205 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6207 needed += sizeof(*pph);
6208 point++;
6209 while(point <= outline->contours[contour]) {
6210 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6211 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6212 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6213 cpfx = 0;
6214 do {
6215 if(buf)
6216 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6217 cpfx++;
6218 point++;
6219 } while(point <= outline->contours[contour] &&
6220 (outline->tags[point] & FT_Curve_Tag_On) ==
6221 (outline->tags[point-1] & FT_Curve_Tag_On));
6222 /* At the end of a contour Windows adds the start point, but
6223 only for Beziers */
6224 if(point > outline->contours[contour] &&
6225 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6226 if(buf)
6227 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6228 cpfx++;
6229 } else if(point <= outline->contours[contour] &&
6230 outline->tags[point] & FT_Curve_Tag_On) {
6231 /* add closing pt for bezier */
6232 if(buf)
6233 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6234 cpfx++;
6235 point++;
6237 if(buf) {
6238 ppc->wType = type;
6239 ppc->cpfx = cpfx;
6241 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6243 if(buf)
6244 pph->cb = needed - pph_start;
6246 break;
6248 case GGO_BEZIER:
6250 /* Convert the quadratic Beziers to cubic Beziers.
6251 The parametric eqn for a cubic Bezier is, from PLRM:
6252 r(t) = at^3 + bt^2 + ct + r0
6253 with the control points:
6254 r1 = r0 + c/3
6255 r2 = r1 + (c + b)/3
6256 r3 = r0 + c + b + a
6258 A quadratic Bezier has the form:
6259 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6261 So equating powers of t leads to:
6262 r1 = 2/3 p1 + 1/3 p0
6263 r2 = 2/3 p1 + 1/3 p2
6264 and of course r0 = p0, r3 = p2
6267 int contour, point = 0, first_pt;
6268 FT_Outline *outline = &ft_face->glyph->outline;
6269 TTPOLYGONHEADER *pph;
6270 TTPOLYCURVE *ppc;
6271 DWORD pph_start, cpfx, type;
6272 FT_Vector cubic_control[4];
6273 if(buflen == 0) buf = NULL;
6275 if (needsTransform && buf) {
6276 pFT_Outline_Transform(outline, &transMat);
6279 for(contour = 0; contour < outline->n_contours; contour++) {
6280 pph_start = needed;
6281 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6282 first_pt = point;
6283 if(buf) {
6284 pph->dwType = TT_POLYGON_TYPE;
6285 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6287 needed += sizeof(*pph);
6288 point++;
6289 while(point <= outline->contours[contour]) {
6290 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6291 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6292 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6293 cpfx = 0;
6294 do {
6295 if(type == TT_PRIM_LINE) {
6296 if(buf)
6297 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6298 cpfx++;
6299 point++;
6300 } else {
6301 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6302 so cpfx = 3n */
6304 /* FIXME: Possible optimization in endpoint calculation
6305 if there are two consecutive curves */
6306 cubic_control[0] = outline->points[point-1];
6307 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6308 cubic_control[0].x += outline->points[point].x + 1;
6309 cubic_control[0].y += outline->points[point].y + 1;
6310 cubic_control[0].x >>= 1;
6311 cubic_control[0].y >>= 1;
6313 if(point+1 > outline->contours[contour])
6314 cubic_control[3] = outline->points[first_pt];
6315 else {
6316 cubic_control[3] = outline->points[point+1];
6317 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6318 cubic_control[3].x += outline->points[point].x + 1;
6319 cubic_control[3].y += outline->points[point].y + 1;
6320 cubic_control[3].x >>= 1;
6321 cubic_control[3].y >>= 1;
6324 /* r1 = 1/3 p0 + 2/3 p1
6325 r2 = 1/3 p2 + 2/3 p1 */
6326 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6327 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6328 cubic_control[2] = cubic_control[1];
6329 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6330 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6331 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6332 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6333 if(buf) {
6334 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6335 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6336 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6338 cpfx += 3;
6339 point++;
6341 } while(point <= outline->contours[contour] &&
6342 (outline->tags[point] & FT_Curve_Tag_On) ==
6343 (outline->tags[point-1] & FT_Curve_Tag_On));
6344 /* At the end of a contour Windows adds the start point,
6345 but only for Beziers and we've already done that.
6347 if(point <= outline->contours[contour] &&
6348 outline->tags[point] & FT_Curve_Tag_On) {
6349 /* This is the closing pt of a bezier, but we've already
6350 added it, so just inc point and carry on */
6351 point++;
6353 if(buf) {
6354 ppc->wType = type;
6355 ppc->cpfx = cpfx;
6357 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6359 if(buf)
6360 pph->cb = needed - pph_start;
6362 break;
6365 default:
6366 FIXME("Unsupported format %d\n", format);
6367 return GDI_ERROR;
6369 return needed;
6372 static BOOL get_bitmap_text_metrics(GdiFont *font)
6374 FT_Face ft_face = font->ft_face;
6375 FT_WinFNT_HeaderRec winfnt_header;
6376 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6377 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6378 font->potm->otmSize = size;
6380 #define TM font->potm->otmTextMetrics
6381 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6383 TM.tmHeight = winfnt_header.pixel_height;
6384 TM.tmAscent = winfnt_header.ascent;
6385 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6386 TM.tmInternalLeading = winfnt_header.internal_leading;
6387 TM.tmExternalLeading = winfnt_header.external_leading;
6388 TM.tmAveCharWidth = winfnt_header.avg_width;
6389 TM.tmMaxCharWidth = winfnt_header.max_width;
6390 TM.tmWeight = winfnt_header.weight;
6391 TM.tmOverhang = 0;
6392 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6393 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6394 TM.tmFirstChar = winfnt_header.first_char;
6395 TM.tmLastChar = winfnt_header.last_char;
6396 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6397 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6398 TM.tmItalic = winfnt_header.italic;
6399 TM.tmUnderlined = font->underline;
6400 TM.tmStruckOut = font->strikeout;
6401 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6402 TM.tmCharSet = winfnt_header.charset;
6404 else
6406 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6407 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6408 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6409 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6410 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6411 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6412 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6413 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6414 TM.tmOverhang = 0;
6415 TM.tmDigitizedAspectX = 96; /* FIXME */
6416 TM.tmDigitizedAspectY = 96; /* FIXME */
6417 TM.tmFirstChar = 1;
6418 TM.tmLastChar = 255;
6419 TM.tmDefaultChar = 32;
6420 TM.tmBreakChar = 32;
6421 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6422 TM.tmUnderlined = font->underline;
6423 TM.tmStruckOut = font->strikeout;
6424 /* NB inverted meaning of TMPF_FIXED_PITCH */
6425 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6426 TM.tmCharSet = font->charset;
6428 #undef TM
6430 return TRUE;
6434 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6436 double scale_x, scale_y;
6438 if (font->aveWidth)
6440 scale_x = (double)font->aveWidth;
6441 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6443 else
6444 scale_x = font->scale_y;
6446 scale_x *= fabs(font->font_desc.matrix.eM11);
6447 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6449 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6450 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6452 SCALE_Y(ptm->tmHeight);
6453 SCALE_Y(ptm->tmAscent);
6454 SCALE_Y(ptm->tmDescent);
6455 SCALE_Y(ptm->tmInternalLeading);
6456 SCALE_Y(ptm->tmExternalLeading);
6457 SCALE_Y(ptm->tmOverhang);
6459 SCALE_X(ptm->tmAveCharWidth);
6460 SCALE_X(ptm->tmMaxCharWidth);
6462 #undef SCALE_X
6463 #undef SCALE_Y
6466 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6468 double scale_x, scale_y;
6470 if (font->aveWidth)
6472 scale_x = (double)font->aveWidth;
6473 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6475 else
6476 scale_x = font->scale_y;
6478 scale_x *= fabs(font->font_desc.matrix.eM11);
6479 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6481 scale_font_metrics(font, &potm->otmTextMetrics);
6483 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6484 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6486 SCALE_Y(potm->otmAscent);
6487 SCALE_Y(potm->otmDescent);
6488 SCALE_Y(potm->otmLineGap);
6489 SCALE_Y(potm->otmsCapEmHeight);
6490 SCALE_Y(potm->otmsXHeight);
6491 SCALE_Y(potm->otmrcFontBox.top);
6492 SCALE_Y(potm->otmrcFontBox.bottom);
6493 SCALE_X(potm->otmrcFontBox.left);
6494 SCALE_X(potm->otmrcFontBox.right);
6495 SCALE_Y(potm->otmMacAscent);
6496 SCALE_Y(potm->otmMacDescent);
6497 SCALE_Y(potm->otmMacLineGap);
6498 SCALE_X(potm->otmptSubscriptSize.x);
6499 SCALE_Y(potm->otmptSubscriptSize.y);
6500 SCALE_X(potm->otmptSubscriptOffset.x);
6501 SCALE_Y(potm->otmptSubscriptOffset.y);
6502 SCALE_X(potm->otmptSuperscriptSize.x);
6503 SCALE_Y(potm->otmptSuperscriptSize.y);
6504 SCALE_X(potm->otmptSuperscriptOffset.x);
6505 SCALE_Y(potm->otmptSuperscriptOffset.y);
6506 SCALE_Y(potm->otmsStrikeoutSize);
6507 SCALE_Y(potm->otmsStrikeoutPosition);
6508 SCALE_Y(potm->otmsUnderscoreSize);
6509 SCALE_Y(potm->otmsUnderscorePosition);
6511 #undef SCALE_X
6512 #undef SCALE_Y
6515 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6517 if(!font->potm)
6519 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6521 /* Make sure that the font has sane width/height ratio */
6522 if (font->aveWidth)
6524 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6526 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6527 font->aveWidth = 0;
6531 *ptm = font->potm->otmTextMetrics;
6532 scale_font_metrics(font, ptm);
6533 return TRUE;
6536 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6538 int i;
6540 for(i = 0; i < ft_face->num_charmaps; i++)
6542 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6543 return TRUE;
6545 return FALSE;
6548 static BOOL get_outline_text_metrics(GdiFont *font)
6550 BOOL ret = FALSE;
6551 FT_Face ft_face = font->ft_face;
6552 UINT needed, lenfam, lensty;
6553 TT_OS2 *pOS2;
6554 TT_HoriHeader *pHori;
6555 TT_Postscript *pPost;
6556 FT_Fixed x_scale, y_scale;
6557 WCHAR *family_nameW, *style_nameW;
6558 static const WCHAR spaceW[] = {' ', '\0'};
6559 char *cp;
6560 INT ascent, descent;
6562 TRACE("font=%p\n", font);
6564 if(!FT_IS_SCALABLE(ft_face))
6565 return FALSE;
6567 needed = sizeof(*font->potm);
6569 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6570 family_nameW = strdupW(font->name);
6572 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6573 * sizeof(WCHAR);
6574 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6575 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6576 style_nameW, lensty/sizeof(WCHAR));
6578 /* These names should be read from the TT name table */
6580 /* length of otmpFamilyName */
6581 needed += lenfam;
6583 /* length of otmpFaceName */
6584 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6585 needed += lenfam; /* just the family name */
6586 } else {
6587 needed += lenfam + lensty; /* family + " " + style */
6590 /* length of otmpStyleName */
6591 needed += lensty;
6593 /* length of otmpFullName */
6594 needed += lenfam + lensty;
6597 x_scale = ft_face->size->metrics.x_scale;
6598 y_scale = ft_face->size->metrics.y_scale;
6600 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6601 if(!pOS2) {
6602 FIXME("Can't find OS/2 table - not TT font?\n");
6603 goto end;
6606 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6607 if(!pHori) {
6608 FIXME("Can't find HHEA table - not TT font?\n");
6609 goto end;
6612 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6614 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6615 pOS2->usWinAscent, pOS2->usWinDescent,
6616 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6617 ft_face->ascender, ft_face->descender, ft_face->height,
6618 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6619 ft_face->bbox.yMax, ft_face->bbox.yMin);
6621 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6622 font->potm->otmSize = needed;
6624 #define TM font->potm->otmTextMetrics
6626 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6627 ascent = pHori->Ascender;
6628 descent = -pHori->Descender;
6629 } else {
6630 ascent = pOS2->usWinAscent;
6631 descent = pOS2->usWinDescent;
6634 if(font->yMax) {
6635 TM.tmAscent = font->yMax;
6636 TM.tmDescent = -font->yMin;
6637 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6638 } else {
6639 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6640 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6641 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6642 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6645 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6647 /* MSDN says:
6648 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6650 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6651 ((ascent + descent) -
6652 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6654 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6655 if (TM.tmAveCharWidth == 0) {
6656 TM.tmAveCharWidth = 1;
6658 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6659 TM.tmWeight = FW_REGULAR;
6660 if (font->fake_bold)
6661 TM.tmWeight = FW_BOLD;
6662 else
6664 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6666 if (pOS2->usWeightClass > FW_MEDIUM)
6667 TM.tmWeight = pOS2->usWeightClass;
6669 else if (pOS2->usWeightClass <= FW_MEDIUM)
6670 TM.tmWeight = pOS2->usWeightClass;
6672 TM.tmOverhang = 0;
6673 TM.tmDigitizedAspectX = 300;
6674 TM.tmDigitizedAspectY = 300;
6675 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6676 * symbol range to 0 - f0ff
6679 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6681 TM.tmFirstChar = 0;
6682 switch(GetACP())
6684 case 1257: /* Baltic */
6685 TM.tmLastChar = 0xf8fd;
6686 break;
6687 default:
6688 TM.tmLastChar = 0xf0ff;
6690 TM.tmBreakChar = 0x20;
6691 TM.tmDefaultChar = 0x1f;
6693 else
6695 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6696 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6698 if(pOS2->usFirstCharIndex <= 1)
6699 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6700 else if (pOS2->usFirstCharIndex > 0xff)
6701 TM.tmBreakChar = 0x20;
6702 else
6703 TM.tmBreakChar = pOS2->usFirstCharIndex;
6704 TM.tmDefaultChar = TM.tmBreakChar - 1;
6706 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6707 TM.tmUnderlined = font->underline;
6708 TM.tmStruckOut = font->strikeout;
6710 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6711 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6712 (pOS2->version == 0xFFFFU ||
6713 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6714 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6715 else
6716 TM.tmPitchAndFamily = 0;
6718 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6720 case PAN_FAMILY_SCRIPT:
6721 TM.tmPitchAndFamily |= FF_SCRIPT;
6722 break;
6724 case PAN_FAMILY_DECORATIVE:
6725 TM.tmPitchAndFamily |= FF_DECORATIVE;
6726 break;
6728 case PAN_ANY:
6729 case PAN_NO_FIT:
6730 case PAN_FAMILY_TEXT_DISPLAY:
6731 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6732 /* which is clearly not what the panose spec says. */
6733 default:
6734 if(TM.tmPitchAndFamily == 0 || /* fixed */
6735 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6736 TM.tmPitchAndFamily = FF_MODERN;
6737 else
6739 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6741 case PAN_ANY:
6742 case PAN_NO_FIT:
6743 default:
6744 TM.tmPitchAndFamily |= FF_DONTCARE;
6745 break;
6747 case PAN_SERIF_COVE:
6748 case PAN_SERIF_OBTUSE_COVE:
6749 case PAN_SERIF_SQUARE_COVE:
6750 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6751 case PAN_SERIF_SQUARE:
6752 case PAN_SERIF_THIN:
6753 case PAN_SERIF_BONE:
6754 case PAN_SERIF_EXAGGERATED:
6755 case PAN_SERIF_TRIANGLE:
6756 TM.tmPitchAndFamily |= FF_ROMAN;
6757 break;
6759 case PAN_SERIF_NORMAL_SANS:
6760 case PAN_SERIF_OBTUSE_SANS:
6761 case PAN_SERIF_PERP_SANS:
6762 case PAN_SERIF_FLARED:
6763 case PAN_SERIF_ROUNDED:
6764 TM.tmPitchAndFamily |= FF_SWISS;
6765 break;
6768 break;
6771 if(FT_IS_SCALABLE(ft_face))
6772 TM.tmPitchAndFamily |= TMPF_VECTOR;
6774 if(FT_IS_SFNT(ft_face))
6776 if (font->ntmFlags & NTM_PS_OPENTYPE)
6777 TM.tmPitchAndFamily |= TMPF_DEVICE;
6778 else
6779 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6782 TM.tmCharSet = font->charset;
6784 font->potm->otmFiller = 0;
6785 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6786 font->potm->otmfsSelection = pOS2->fsSelection;
6787 font->potm->otmfsType = pOS2->fsType;
6788 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6789 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6790 font->potm->otmItalicAngle = 0; /* POST table */
6791 font->potm->otmEMSquare = ft_face->units_per_EM;
6792 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6793 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6794 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6795 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6796 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6797 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6798 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6799 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6800 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6801 font->potm->otmMacAscent = TM.tmAscent;
6802 font->potm->otmMacDescent = -TM.tmDescent;
6803 font->potm->otmMacLineGap = font->potm->otmLineGap;
6804 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6805 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6806 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6807 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6808 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6809 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6810 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6811 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6812 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6813 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6814 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6815 if(!pPost) {
6816 font->potm->otmsUnderscoreSize = 0;
6817 font->potm->otmsUnderscorePosition = 0;
6818 } else {
6819 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6820 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6822 #undef TM
6824 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6825 cp = (char*)font->potm + sizeof(*font->potm);
6826 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6827 strcpyW((WCHAR*)cp, family_nameW);
6828 cp += lenfam;
6829 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6830 strcpyW((WCHAR*)cp, style_nameW);
6831 cp += lensty;
6832 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6833 strcpyW((WCHAR*)cp, family_nameW);
6834 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6835 strcatW((WCHAR*)cp, spaceW);
6836 strcatW((WCHAR*)cp, style_nameW);
6837 cp += lenfam + lensty;
6838 } else
6839 cp += lenfam;
6840 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6841 strcpyW((WCHAR*)cp, family_nameW);
6842 strcatW((WCHAR*)cp, spaceW);
6843 strcatW((WCHAR*)cp, style_nameW);
6844 ret = TRUE;
6846 end:
6847 HeapFree(GetProcessHeap(), 0, style_nameW);
6848 HeapFree(GetProcessHeap(), 0, family_nameW);
6849 return ret;
6852 /*************************************************************
6853 * freetype_GetGlyphOutline
6855 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6856 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6858 struct freetype_physdev *physdev = get_freetype_dev( dev );
6859 DWORD ret;
6861 if (!physdev->font)
6863 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6864 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6867 GDI_CheckNotLock();
6868 EnterCriticalSection( &freetype_cs );
6869 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6870 LeaveCriticalSection( &freetype_cs );
6871 return ret;
6874 /*************************************************************
6875 * freetype_GetTextMetrics
6877 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6879 struct freetype_physdev *physdev = get_freetype_dev( dev );
6880 BOOL ret;
6882 if (!physdev->font)
6884 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6885 return dev->funcs->pGetTextMetrics( dev, metrics );
6888 GDI_CheckNotLock();
6889 EnterCriticalSection( &freetype_cs );
6890 ret = get_text_metrics( physdev->font, metrics );
6891 LeaveCriticalSection( &freetype_cs );
6892 return ret;
6895 /*************************************************************
6896 * freetype_GetOutlineTextMetrics
6898 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6900 struct freetype_physdev *physdev = get_freetype_dev( dev );
6901 UINT ret = 0;
6903 if (!physdev->font)
6905 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6906 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6909 TRACE("font=%p\n", physdev->font);
6911 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6913 GDI_CheckNotLock();
6914 EnterCriticalSection( &freetype_cs );
6916 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6918 if(cbSize >= physdev->font->potm->otmSize)
6920 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6921 scale_outline_font_metrics(physdev->font, potm);
6923 ret = physdev->font->potm->otmSize;
6925 LeaveCriticalSection( &freetype_cs );
6926 return ret;
6929 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6931 HFONTLIST *hfontlist;
6932 child->font = alloc_font();
6933 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6934 if(!child->font->ft_face)
6936 free_font(child->font);
6937 child->font = NULL;
6938 return FALSE;
6941 child->font->font_desc = font->font_desc;
6942 child->font->ntmFlags = child->face->ntmFlags;
6943 child->font->orientation = font->orientation;
6944 child->font->scale_y = font->scale_y;
6945 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6946 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6947 child->font->name = strdupW(child->face->family->FamilyName);
6948 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6949 child->font->base_font = font;
6950 list_add_head(&child_font_list, &child->font->entry);
6951 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6952 return TRUE;
6955 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6957 FT_UInt g;
6958 CHILD_FONT *child_font;
6960 if(font->base_font)
6961 font = font->base_font;
6963 *linked_font = font;
6965 if((*glyph = get_glyph_index(font, c)))
6967 *glyph = get_GSUB_vert_glyph(font, *glyph);
6968 return TRUE;
6971 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6973 if(!child_font->font)
6974 if(!load_child_font(font, child_font))
6975 continue;
6977 if(!child_font->font->ft_face)
6978 continue;
6979 g = get_glyph_index(child_font->font, c);
6980 g = get_GSUB_vert_glyph(child_font->font, g);
6981 if(g)
6983 *glyph = g;
6984 *linked_font = child_font->font;
6985 return TRUE;
6988 return FALSE;
6991 /*************************************************************
6992 * freetype_GetCharWidth
6994 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6996 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6997 UINT c;
6998 GLYPHMETRICS gm;
6999 FT_UInt glyph_index;
7000 GdiFont *linked_font;
7001 struct freetype_physdev *physdev = get_freetype_dev( dev );
7003 if (!physdev->font)
7005 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7006 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7009 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7011 GDI_CheckNotLock();
7012 EnterCriticalSection( &freetype_cs );
7013 for(c = firstChar; c <= lastChar; c++) {
7014 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7015 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7016 &gm, 0, NULL, &identity);
7017 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
7019 LeaveCriticalSection( &freetype_cs );
7020 return TRUE;
7023 /*************************************************************
7024 * freetype_GetCharABCWidths
7026 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7028 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7029 UINT c;
7030 GLYPHMETRICS gm;
7031 FT_UInt glyph_index;
7032 GdiFont *linked_font;
7033 struct freetype_physdev *physdev = get_freetype_dev( dev );
7035 if (!physdev->font)
7037 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7038 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7041 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7043 GDI_CheckNotLock();
7044 EnterCriticalSection( &freetype_cs );
7046 for(c = firstChar; c <= lastChar; c++) {
7047 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7048 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7049 &gm, 0, NULL, &identity);
7050 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
7051 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
7052 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
7053 FONT_GM(linked_font,glyph_index)->bbx;
7055 LeaveCriticalSection( &freetype_cs );
7056 return TRUE;
7059 /*************************************************************
7060 * freetype_GetCharABCWidthsI
7062 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7064 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7065 UINT c;
7066 GLYPHMETRICS gm;
7067 FT_UInt glyph_index;
7068 GdiFont *linked_font;
7069 struct freetype_physdev *physdev = get_freetype_dev( dev );
7071 if (!physdev->font)
7073 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7074 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7077 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7078 return FALSE;
7080 GDI_CheckNotLock();
7081 EnterCriticalSection( &freetype_cs );
7083 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
7084 if (!pgi)
7085 for(c = firstChar; c < firstChar+count; c++) {
7086 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
7087 &gm, 0, NULL, &identity);
7088 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
7089 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
7090 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
7091 - FONT_GM(linked_font,c)->bbx;
7093 else
7094 for(c = 0; c < count; c++) {
7095 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
7096 &gm, 0, NULL, &identity);
7097 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
7098 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
7099 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
7100 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
7103 LeaveCriticalSection( &freetype_cs );
7104 return TRUE;
7107 /*************************************************************
7108 * freetype_GetTextExtentExPoint
7110 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7111 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7113 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7114 INT idx;
7115 INT nfit = 0, ext;
7116 GLYPHMETRICS gm;
7117 TEXTMETRICW tm;
7118 FT_UInt glyph_index;
7119 GdiFont *linked_font;
7120 struct freetype_physdev *physdev = get_freetype_dev( dev );
7122 if (!physdev->font)
7124 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7125 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7128 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7130 GDI_CheckNotLock();
7131 EnterCriticalSection( &freetype_cs );
7133 size->cx = 0;
7134 get_text_metrics( physdev->font, &tm );
7135 size->cy = tm.tmHeight;
7137 for(idx = 0; idx < count; idx++) {
7138 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7139 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7140 &gm, 0, NULL, &identity);
7141 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7142 ext = size->cx;
7143 if (! pnfit || ext <= max_ext) {
7144 ++nfit;
7145 if (dxs)
7146 dxs[idx] = ext;
7150 if (pnfit)
7151 *pnfit = nfit;
7153 LeaveCriticalSection( &freetype_cs );
7154 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7155 return TRUE;
7158 /*************************************************************
7159 * freetype_GetTextExtentExPointI
7161 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7162 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7164 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7165 INT idx;
7166 INT nfit = 0, ext;
7167 GLYPHMETRICS gm;
7168 TEXTMETRICW tm;
7169 struct freetype_physdev *physdev = get_freetype_dev( dev );
7171 if (!physdev->font)
7173 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7174 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7177 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7179 GDI_CheckNotLock();
7180 EnterCriticalSection( &freetype_cs );
7182 size->cx = 0;
7183 get_text_metrics(physdev->font, &tm);
7184 size->cy = tm.tmHeight;
7186 for(idx = 0; idx < count; idx++) {
7187 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7188 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7189 ext = size->cx;
7190 if (! pnfit || ext <= max_ext) {
7191 ++nfit;
7192 if (dxs)
7193 dxs[idx] = ext;
7197 if (pnfit)
7198 *pnfit = nfit;
7200 LeaveCriticalSection( &freetype_cs );
7201 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7202 return TRUE;
7205 /*************************************************************
7206 * freetype_GetFontData
7208 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7210 struct freetype_physdev *physdev = get_freetype_dev( dev );
7212 if (!physdev->font)
7214 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7215 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7218 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7219 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7220 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7222 return get_font_data( physdev->font, table, offset, buf, cbData );
7225 /*************************************************************
7226 * freetype_GetTextFace
7228 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7230 INT n;
7231 struct freetype_physdev *physdev = get_freetype_dev( dev );
7233 if (!physdev->font)
7235 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7236 return dev->funcs->pGetTextFace( dev, count, str );
7239 n = strlenW(physdev->font->name) + 1;
7240 if (str)
7242 lstrcpynW(str, physdev->font->name, count);
7243 n = min(count, n);
7245 return n;
7248 /*************************************************************
7249 * freetype_GetTextCharsetInfo
7251 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7253 struct freetype_physdev *physdev = get_freetype_dev( dev );
7255 if (!physdev->font)
7257 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7258 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7260 if (fs) *fs = physdev->font->fs;
7261 return physdev->font->charset;
7264 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7266 GdiFont *font = dc->gdiFont, *linked_font;
7267 struct list *first_hfont;
7268 BOOL ret;
7270 GDI_CheckNotLock();
7271 EnterCriticalSection( &freetype_cs );
7272 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7273 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7274 if(font == linked_font)
7275 *new_hfont = dc->hFont;
7276 else
7278 first_hfont = list_head(&linked_font->hfontlist);
7279 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7281 LeaveCriticalSection( &freetype_cs );
7282 return ret;
7285 /* Retrieve a list of supported Unicode ranges for a given font.
7286 * Can be called with NULL gs to calculate the buffer size. Returns
7287 * the number of ranges found.
7289 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7291 DWORD num_ranges = 0;
7293 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7295 FT_UInt glyph_code;
7296 FT_ULong char_code, char_code_prev;
7298 glyph_code = 0;
7299 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7301 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7302 face->num_glyphs, glyph_code, char_code);
7304 if (!glyph_code) return 0;
7306 if (gs)
7308 gs->ranges[0].wcLow = (USHORT)char_code;
7309 gs->ranges[0].cGlyphs = 0;
7310 gs->cGlyphsSupported = 0;
7313 num_ranges = 1;
7314 while (glyph_code)
7316 if (char_code < char_code_prev)
7318 ERR("expected increasing char code from FT_Get_Next_Char\n");
7319 return 0;
7321 if (char_code - char_code_prev > 1)
7323 num_ranges++;
7324 if (gs)
7326 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7327 gs->ranges[num_ranges - 1].cGlyphs = 1;
7328 gs->cGlyphsSupported++;
7331 else if (gs)
7333 gs->ranges[num_ranges - 1].cGlyphs++;
7334 gs->cGlyphsSupported++;
7336 char_code_prev = char_code;
7337 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7340 else
7341 FIXME("encoding %u not supported\n", face->charmap->encoding);
7343 return num_ranges;
7346 /*************************************************************
7347 * freetype_GetFontUnicodeRanges
7349 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7351 struct freetype_physdev *physdev = get_freetype_dev( dev );
7352 DWORD size, num_ranges;
7354 if (!physdev->font)
7356 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7357 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7360 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7361 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7362 if (glyphset)
7364 glyphset->cbThis = size;
7365 glyphset->cRanges = num_ranges;
7366 glyphset->flAccel = 0;
7368 return size;
7371 /*************************************************************
7372 * freetype_FontIsLinked
7374 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7376 struct freetype_physdev *physdev = get_freetype_dev( dev );
7377 BOOL ret;
7379 if (!physdev->font)
7381 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7382 return dev->funcs->pFontIsLinked( dev );
7385 GDI_CheckNotLock();
7386 EnterCriticalSection( &freetype_cs );
7387 ret = !list_empty(&physdev->font->child_fonts);
7388 LeaveCriticalSection( &freetype_cs );
7389 return ret;
7392 static BOOL is_hinting_enabled(void)
7394 /* Use the >= 2.2.0 function if available */
7395 if(pFT_Get_TrueType_Engine_Type)
7397 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
7398 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
7400 #ifdef FT_DRIVER_HAS_HINTER
7401 else
7403 FT_Module mod;
7405 /* otherwise if we've been compiled with < 2.2.0 headers
7406 use the internal macro */
7407 mod = pFT_Get_Module(library, "truetype");
7408 if(mod && FT_DRIVER_HAS_HINTER(mod))
7409 return TRUE;
7411 #endif
7413 return FALSE;
7416 static BOOL is_subpixel_rendering_enabled( void )
7418 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7419 return pFT_Library_SetLcdFilter &&
7420 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
7421 #else
7422 return FALSE;
7423 #endif
7426 /*************************************************************************
7427 * GetRasterizerCaps (GDI32.@)
7429 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7431 static int hinting = -1;
7432 static int subpixel = -1;
7434 if(hinting == -1)
7436 hinting = is_hinting_enabled();
7437 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7440 if ( subpixel == -1 )
7442 subpixel = is_subpixel_rendering_enabled();
7443 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7446 lprs->nSize = sizeof(RASTERIZER_STATUS);
7447 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7448 if ( subpixel )
7449 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7450 lprs->nLanguageID = 0;
7451 return TRUE;
7454 /*************************************************************
7455 * freetype_GdiRealizationInfo
7457 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7459 struct freetype_physdev *physdev = get_freetype_dev( dev );
7460 realization_info_t *info = ptr;
7462 if (!physdev->font)
7464 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7465 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7468 FIXME("(%p, %p): stub!\n", physdev->font, info);
7470 info->flags = 1;
7471 if(FT_IS_SCALABLE(physdev->font->ft_face))
7472 info->flags |= 2;
7474 info->cache_num = physdev->font->cache_num;
7475 info->unknown2 = -1;
7476 return TRUE;
7479 /*************************************************************************
7480 * Kerning support for TrueType fonts
7482 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7484 struct TT_kern_table
7486 USHORT version;
7487 USHORT nTables;
7490 struct TT_kern_subtable
7492 USHORT version;
7493 USHORT length;
7494 union
7496 USHORT word;
7497 struct
7499 USHORT horizontal : 1;
7500 USHORT minimum : 1;
7501 USHORT cross_stream: 1;
7502 USHORT override : 1;
7503 USHORT reserved1 : 4;
7504 USHORT format : 8;
7505 } bits;
7506 } coverage;
7509 struct TT_format0_kern_subtable
7511 USHORT nPairs;
7512 USHORT searchRange;
7513 USHORT entrySelector;
7514 USHORT rangeShift;
7517 struct TT_kern_pair
7519 USHORT left;
7520 USHORT right;
7521 short value;
7524 static DWORD parse_format0_kern_subtable(GdiFont *font,
7525 const struct TT_format0_kern_subtable *tt_f0_ks,
7526 const USHORT *glyph_to_char,
7527 KERNINGPAIR *kern_pair, DWORD cPairs)
7529 USHORT i, nPairs;
7530 const struct TT_kern_pair *tt_kern_pair;
7532 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7534 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7536 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7537 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7538 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7540 if (!kern_pair || !cPairs)
7541 return nPairs;
7543 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7545 nPairs = min(nPairs, cPairs);
7547 for (i = 0; i < nPairs; i++)
7549 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7550 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7551 /* this algorithm appears to better match what Windows does */
7552 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7553 if (kern_pair->iKernAmount < 0)
7555 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7556 kern_pair->iKernAmount -= font->ppem;
7558 else if (kern_pair->iKernAmount > 0)
7560 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7561 kern_pair->iKernAmount += font->ppem;
7563 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7565 TRACE("left %u right %u value %d\n",
7566 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7568 kern_pair++;
7570 TRACE("copied %u entries\n", nPairs);
7571 return nPairs;
7574 /*************************************************************
7575 * freetype_GetKerningPairs
7577 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7579 DWORD length;
7580 void *buf;
7581 const struct TT_kern_table *tt_kern_table;
7582 const struct TT_kern_subtable *tt_kern_subtable;
7583 USHORT i, nTables;
7584 USHORT *glyph_to_char;
7585 GdiFont *font;
7586 struct freetype_physdev *physdev = get_freetype_dev( dev );
7588 if (!(font = physdev->font))
7590 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7591 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7594 GDI_CheckNotLock();
7595 EnterCriticalSection( &freetype_cs );
7596 if (font->total_kern_pairs != (DWORD)-1)
7598 if (cPairs && kern_pair)
7600 cPairs = min(cPairs, font->total_kern_pairs);
7601 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7603 else cPairs = font->total_kern_pairs;
7605 LeaveCriticalSection( &freetype_cs );
7606 return cPairs;
7609 font->total_kern_pairs = 0;
7611 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7613 if (length == GDI_ERROR)
7615 TRACE("no kerning data in the font\n");
7616 LeaveCriticalSection( &freetype_cs );
7617 return 0;
7620 buf = HeapAlloc(GetProcessHeap(), 0, length);
7621 if (!buf)
7623 WARN("Out of memory\n");
7624 LeaveCriticalSection( &freetype_cs );
7625 return 0;
7628 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7630 /* build a glyph index to char code map */
7631 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7632 if (!glyph_to_char)
7634 WARN("Out of memory allocating a glyph index to char code map\n");
7635 HeapFree(GetProcessHeap(), 0, buf);
7636 LeaveCriticalSection( &freetype_cs );
7637 return 0;
7640 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7642 FT_UInt glyph_code;
7643 FT_ULong char_code;
7645 glyph_code = 0;
7646 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7648 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7649 font->ft_face->num_glyphs, glyph_code, char_code);
7651 while (glyph_code)
7653 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7655 /* FIXME: This doesn't match what Windows does: it does some fancy
7656 * things with duplicate glyph index to char code mappings, while
7657 * we just avoid overriding existing entries.
7659 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7660 glyph_to_char[glyph_code] = (USHORT)char_code;
7662 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7665 else
7667 ULONG n;
7669 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7670 for (n = 0; n <= 65535; n++)
7671 glyph_to_char[n] = (USHORT)n;
7674 tt_kern_table = buf;
7675 nTables = GET_BE_WORD(tt_kern_table->nTables);
7676 TRACE("version %u, nTables %u\n",
7677 GET_BE_WORD(tt_kern_table->version), nTables);
7679 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7681 for (i = 0; i < nTables; i++)
7683 struct TT_kern_subtable tt_kern_subtable_copy;
7685 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7686 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7687 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7689 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7690 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7691 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7693 /* According to the TrueType specification this is the only format
7694 * that will be properly interpreted by Windows and OS/2
7696 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7698 DWORD new_chunk, old_total = font->total_kern_pairs;
7700 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7701 glyph_to_char, NULL, 0);
7702 font->total_kern_pairs += new_chunk;
7704 if (!font->kern_pairs)
7705 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7706 font->total_kern_pairs * sizeof(*font->kern_pairs));
7707 else
7708 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7709 font->total_kern_pairs * sizeof(*font->kern_pairs));
7711 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7712 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7714 else
7715 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7717 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7720 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7721 HeapFree(GetProcessHeap(), 0, buf);
7723 if (cPairs && kern_pair)
7725 cPairs = min(cPairs, font->total_kern_pairs);
7726 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7728 else cPairs = font->total_kern_pairs;
7730 LeaveCriticalSection( &freetype_cs );
7731 return cPairs;
7734 static const struct gdi_dc_funcs freetype_funcs =
7736 NULL, /* pAbortDoc */
7737 NULL, /* pAbortPath */
7738 NULL, /* pAlphaBlend */
7739 NULL, /* pAngleArc */
7740 NULL, /* pArc */
7741 NULL, /* pArcTo */
7742 NULL, /* pBeginPath */
7743 NULL, /* pBlendImage */
7744 NULL, /* pChoosePixelFormat */
7745 NULL, /* pChord */
7746 NULL, /* pCloseFigure */
7747 NULL, /* pCopyBitmap */
7748 NULL, /* pCreateBitmap */
7749 NULL, /* pCreateCompatibleDC */
7750 freetype_CreateDC, /* pCreateDC */
7751 NULL, /* pDeleteBitmap */
7752 freetype_DeleteDC, /* pDeleteDC */
7753 NULL, /* pDeleteObject */
7754 NULL, /* pDescribePixelFormat */
7755 NULL, /* pDeviceCapabilities */
7756 NULL, /* pEllipse */
7757 NULL, /* pEndDoc */
7758 NULL, /* pEndPage */
7759 NULL, /* pEndPath */
7760 freetype_EnumFonts, /* pEnumFonts */
7761 NULL, /* pEnumICMProfiles */
7762 NULL, /* pExcludeClipRect */
7763 NULL, /* pExtDeviceMode */
7764 NULL, /* pExtEscape */
7765 NULL, /* pExtFloodFill */
7766 NULL, /* pExtSelectClipRgn */
7767 NULL, /* pExtTextOut */
7768 NULL, /* pFillPath */
7769 NULL, /* pFillRgn */
7770 NULL, /* pFlattenPath */
7771 freetype_FontIsLinked, /* pFontIsLinked */
7772 NULL, /* pFrameRgn */
7773 NULL, /* pGdiComment */
7774 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7775 NULL, /* pGetBoundsRect */
7776 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7777 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7778 freetype_GetCharWidth, /* pGetCharWidth */
7779 NULL, /* pGetDeviceCaps */
7780 NULL, /* pGetDeviceGammaRamp */
7781 freetype_GetFontData, /* pGetFontData */
7782 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7783 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7784 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7785 NULL, /* pGetICMProfile */
7786 NULL, /* pGetImage */
7787 freetype_GetKerningPairs, /* pGetKerningPairs */
7788 NULL, /* pGetNearestColor */
7789 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7790 NULL, /* pGetPixel */
7791 NULL, /* pGetPixelFormat */
7792 NULL, /* pGetSystemPaletteEntries */
7793 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7794 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7795 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7796 freetype_GetTextFace, /* pGetTextFace */
7797 freetype_GetTextMetrics, /* pGetTextMetrics */
7798 NULL, /* pGradientFill */
7799 NULL, /* pIntersectClipRect */
7800 NULL, /* pInvertRgn */
7801 NULL, /* pLineTo */
7802 NULL, /* pModifyWorldTransform */
7803 NULL, /* pMoveTo */
7804 NULL, /* pOffsetClipRgn */
7805 NULL, /* pOffsetViewportOrg */
7806 NULL, /* pOffsetWindowOrg */
7807 NULL, /* pPaintRgn */
7808 NULL, /* pPatBlt */
7809 NULL, /* pPie */
7810 NULL, /* pPolyBezier */
7811 NULL, /* pPolyBezierTo */
7812 NULL, /* pPolyDraw */
7813 NULL, /* pPolyPolygon */
7814 NULL, /* pPolyPolyline */
7815 NULL, /* pPolygon */
7816 NULL, /* pPolyline */
7817 NULL, /* pPolylineTo */
7818 NULL, /* pPutImage */
7819 NULL, /* pRealizeDefaultPalette */
7820 NULL, /* pRealizePalette */
7821 NULL, /* pRectangle */
7822 NULL, /* pResetDC */
7823 NULL, /* pRestoreDC */
7824 NULL, /* pRoundRect */
7825 NULL, /* pSaveDC */
7826 NULL, /* pScaleViewportExt */
7827 NULL, /* pScaleWindowExt */
7828 NULL, /* pSelectBitmap */
7829 NULL, /* pSelectBrush */
7830 NULL, /* pSelectClipPath */
7831 freetype_SelectFont, /* pSelectFont */
7832 NULL, /* pSelectPalette */
7833 NULL, /* pSelectPen */
7834 NULL, /* pSetArcDirection */
7835 NULL, /* pSetBkColor */
7836 NULL, /* pSetBkMode */
7837 NULL, /* pSetDCBrushColor */
7838 NULL, /* pSetDCPenColor */
7839 NULL, /* pSetDIBColorTable */
7840 NULL, /* pSetDIBitsToDevice */
7841 NULL, /* pSetDeviceClipping */
7842 NULL, /* pSetDeviceGammaRamp */
7843 NULL, /* pSetLayout */
7844 NULL, /* pSetMapMode */
7845 NULL, /* pSetMapperFlags */
7846 NULL, /* pSetPixel */
7847 NULL, /* pSetPixelFormat */
7848 NULL, /* pSetPolyFillMode */
7849 NULL, /* pSetROP2 */
7850 NULL, /* pSetRelAbs */
7851 NULL, /* pSetStretchBltMode */
7852 NULL, /* pSetTextAlign */
7853 NULL, /* pSetTextCharacterExtra */
7854 NULL, /* pSetTextColor */
7855 NULL, /* pSetTextJustification */
7856 NULL, /* pSetViewportExt */
7857 NULL, /* pSetViewportOrg */
7858 NULL, /* pSetWindowExt */
7859 NULL, /* pSetWindowOrg */
7860 NULL, /* pSetWorldTransform */
7861 NULL, /* pStartDoc */
7862 NULL, /* pStartPage */
7863 NULL, /* pStretchBlt */
7864 NULL, /* pStretchDIBits */
7865 NULL, /* pStrokeAndFillPath */
7866 NULL, /* pStrokePath */
7867 NULL, /* pSwapBuffers */
7868 NULL, /* pUnrealizePalette */
7869 NULL, /* pWidenPath */
7870 /* OpenGL not supported */
7873 #else /* HAVE_FREETYPE */
7875 /*************************************************************************/
7877 BOOL WineEngInit(void)
7879 return FALSE;
7881 BOOL WineEngDestroyFontInstance(HFONT hfont)
7883 return FALSE;
7886 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7888 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7889 return 1;
7892 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7894 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7895 return TRUE;
7898 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7900 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7901 return NULL;
7904 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7905 LPCWSTR font_file, LPCWSTR font_path )
7907 FIXME("stub\n");
7908 return FALSE;
7911 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7913 return FALSE;
7916 /*************************************************************************
7917 * GetRasterizerCaps (GDI32.@)
7919 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7921 lprs->nSize = sizeof(RASTERIZER_STATUS);
7922 lprs->wFlags = 0;
7923 lprs->nLanguageID = 0;
7924 return TRUE;
7927 #endif /* HAVE_FREETYPE */