gdi32: Separate face creation from face insertion.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob8a077a94f2644e878eda0132382c4d7486804427
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 const WCHAR *FamilyName;
282 const 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_italic_value[] = {'I','t','a','l','i','c',0};
488 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
489 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
491 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
501 struct font_mapping
503 struct list entry;
504 int refcount;
505 dev_t dev;
506 ino_t ino;
507 void *data;
508 size_t size;
511 static struct list mappings_list = LIST_INIT( mappings_list );
513 static CRITICAL_SECTION freetype_cs;
514 static CRITICAL_SECTION_DEBUG critsect_debug =
516 0, 0, &freetype_cs,
517 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
518 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback = FALSE;
527 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
528 static BOOL get_outline_text_metrics(GdiFont *font);
529 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
531 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
546 * Key Meaning
547 * FIXEDFON.FON FixedSys
548 * FONTS.FON System
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
562 * I have
563 * woafont=app850.fon
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
575 typedef struct {
576 DWORD version;
577 WORD ScriptList;
578 WORD FeatureList;
579 WORD LookupList;
580 } GSUB_Header;
582 typedef struct {
583 CHAR ScriptTag[4];
584 WORD Script;
585 } GSUB_ScriptRecord;
587 typedef struct {
588 WORD ScriptCount;
589 GSUB_ScriptRecord ScriptRecord[1];
590 } GSUB_ScriptList;
592 typedef struct {
593 CHAR LangSysTag[4];
594 WORD LangSys;
595 } GSUB_LangSysRecord;
597 typedef struct {
598 WORD DefaultLangSys;
599 WORD LangSysCount;
600 GSUB_LangSysRecord LangSysRecord[1];
601 } GSUB_Script;
603 typedef struct {
604 WORD LookupOrder; /* Reserved */
605 WORD ReqFeatureIndex;
606 WORD FeatureCount;
607 WORD FeatureIndex[1];
608 } GSUB_LangSys;
610 typedef struct {
611 CHAR FeatureTag[4];
612 WORD Feature;
613 } GSUB_FeatureRecord;
615 typedef struct {
616 WORD FeatureCount;
617 GSUB_FeatureRecord FeatureRecord[1];
618 } GSUB_FeatureList;
620 typedef struct {
621 WORD FeatureParams; /* Reserved */
622 WORD LookupCount;
623 WORD LookupListIndex[1];
624 } GSUB_Feature;
626 typedef struct {
627 WORD LookupCount;
628 WORD Lookup[1];
629 } GSUB_LookupList;
631 typedef struct {
632 WORD LookupType;
633 WORD LookupFlag;
634 WORD SubTableCount;
635 WORD SubTable[1];
636 } GSUB_LookupTable;
638 typedef struct {
639 WORD CoverageFormat;
640 WORD GlyphCount;
641 WORD GlyphArray[1];
642 } GSUB_CoverageFormat1;
644 typedef struct {
645 WORD Start;
646 WORD End;
647 WORD StartCoverageIndex;
648 } GSUB_RangeRecord;
650 typedef struct {
651 WORD CoverageFormat;
652 WORD RangeCount;
653 GSUB_RangeRecord RangeRecord[1];
654 } GSUB_CoverageFormat2;
656 typedef struct {
657 WORD SubstFormat; /* = 1 */
658 WORD Coverage;
659 WORD DeltaGlyphID;
660 } GSUB_SingleSubstFormat1;
662 typedef struct {
663 WORD SubstFormat; /* = 2 */
664 WORD Coverage;
665 WORD GlyphCount;
666 WORD Substitute[1];
667 }GSUB_SingleSubstFormat2;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
672 FSRef ref;
673 OSErr err;
674 static char cached_path[MAX_PATH];
675 static const char *wine = "/Wine", *fonts = "/Fonts";
677 if(*cached_path) return cached_path;
679 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
680 if(err != noErr)
682 WARN("can't create cached data folder\n");
683 return NULL;
685 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
686 if(err != noErr)
688 WARN("can't create cached data path\n");
689 *cached_path = '\0';
690 return NULL;
692 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
694 ERR("Could not create full path\n");
695 *cached_path = '\0';
696 return NULL;
698 strcat(cached_path, wine);
700 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
702 WARN("Couldn't mkdir %s\n", cached_path);
703 *cached_path = '\0';
704 return NULL;
706 strcat(cached_path, fonts);
707 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
709 WARN("Couldn't mkdir %s\n", cached_path);
710 *cached_path = '\0';
711 return NULL;
713 return cached_path;
716 /******************************************************************
717 * expand_mac_font
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
721 * find_cache_dir()).
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path)
729 FSRef ref;
730 SInt16 res_ref;
731 OSStatus s;
732 unsigned int idx;
733 const char *out_dir;
734 const char *filename;
735 int output_len;
736 struct {
737 char **array;
738 unsigned int size, max_size;
739 } ret;
741 TRACE("path %s\n", path);
743 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
744 if(s != noErr)
746 WARN("failed to get ref\n");
747 return NULL;
750 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
751 if(s != noErr)
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref = FSOpenResFile(&ref, fsRdPerm);
755 if(res_ref == -1)
757 TRACE("unable to open resource fork\n");
758 return NULL;
762 ret.size = 0;
763 ret.max_size = 10;
764 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
765 if(!ret.array)
767 CloseResFile(res_ref);
768 return NULL;
771 out_dir = find_cache_dir();
773 filename = strrchr(path, '/');
774 if(!filename) filename = path;
775 else filename++;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
780 UseResFile(res_ref);
781 idx = 1;
782 while(1)
784 FamRec *fam_rec;
785 unsigned short *num_faces_ptr, num_faces, face;
786 AsscEntry *assoc;
787 Handle fond;
788 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
790 fond = Get1IndResource(fond_res, idx);
791 if(!fond) break;
792 TRACE("got fond resource %d\n", idx);
793 HLock(fond);
795 fam_rec = *(FamRec**)fond;
796 num_faces_ptr = (unsigned short *)(fam_rec + 1);
797 num_faces = GET_BE_WORD(*num_faces_ptr);
798 num_faces++;
799 assoc = (AsscEntry*)(num_faces_ptr + 1);
800 TRACE("num faces %04x\n", num_faces);
801 for(face = 0; face < num_faces; face++, assoc++)
803 Handle sfnt;
804 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
805 unsigned short size, font_id;
806 char *output;
808 size = GET_BE_WORD(assoc->fontSize);
809 font_id = GET_BE_WORD(assoc->fontID);
810 if(size != 0)
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
813 continue;
816 TRACE("trying to load sfnt id %04x\n", font_id);
817 sfnt = GetResource(sfnt_res, font_id);
818 if(!sfnt)
820 TRACE("can't get sfnt resource %04x\n", font_id);
821 continue;
824 output = HeapAlloc(GetProcessHeap(), 0, output_len);
825 if(output)
827 int fd;
829 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
831 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
832 if(fd != -1 || errno == EEXIST)
834 if(fd != -1)
836 unsigned char *sfnt_data;
838 HLock(sfnt);
839 sfnt_data = *(unsigned char**)sfnt;
840 write(fd, sfnt_data, GetHandleSize(sfnt));
841 HUnlock(sfnt);
842 close(fd);
844 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
846 ret.max_size *= 2;
847 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
849 ret.array[ret.size++] = output;
851 else
853 WARN("unable to create %s\n", output);
854 HeapFree(GetProcessHeap(), 0, output);
857 ReleaseResource(sfnt);
859 HUnlock(fond);
860 ReleaseResource(fond);
861 idx++;
863 CloseResFile(res_ref);
865 return ret.array;
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed FT_FixedFromFloat(double f)
880 return f * 0x10000;
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
889 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
893 static const struct list *get_face_list_from_family(const Family *family)
895 if (!list_empty(&family->faces))
896 return &family->faces;
897 else
898 return family->replacement;
901 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
903 Family *family;
904 Face *face;
905 const char *file;
906 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
907 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
909 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
912 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
914 const struct list *face_list;
915 if(face_name && strcmpiW(face_name, family->FamilyName))
916 continue;
917 face_list = get_face_list_from_family(family);
918 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
920 if (!face->file)
921 continue;
922 file = strrchr(face->file, '/');
923 if(!file)
924 file = face->file;
925 else
926 file++;
927 if(!strcasecmp(file, file_nameA))
929 HeapFree(GetProcessHeap(), 0, file_nameA);
930 return face;
934 HeapFree(GetProcessHeap(), 0, file_nameA);
935 return NULL;
938 static Family *find_family_from_name(const WCHAR *name)
940 Family *family;
942 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
944 if(!strcmpiW(family->FamilyName, name))
945 return family;
948 return NULL;
951 static Family *find_family_from_any_name(const WCHAR *name)
953 Family *family;
955 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
957 if(!strcmpiW(family->FamilyName, name))
958 return family;
959 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
960 return family;
963 return NULL;
966 static void DumpSubstList(void)
968 FontSubst *psub;
970 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
972 if(psub->from.charset != -1 || psub->to.charset != -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
974 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
975 else
976 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
977 debugstr_w(psub->to.name));
979 return;
982 static LPWSTR strdupW(LPCWSTR p)
984 LPWSTR ret;
985 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
986 ret = HeapAlloc(GetProcessHeap(), 0, len);
987 memcpy(ret, p, len);
988 return ret;
991 static LPSTR strdupA(LPCSTR p)
993 LPSTR ret;
994 DWORD len = (strlen(p) + 1);
995 ret = HeapAlloc(GetProcessHeap(), 0, len);
996 memcpy(ret, p, len);
997 return ret;
1000 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1001 INT from_charset)
1003 FontSubst *element;
1005 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1007 if(!strcmpiW(element->from.name, from_name) &&
1008 (element->from.charset == from_charset ||
1009 element->from.charset == -1))
1010 return element;
1013 return NULL;
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1020 FontSubst *from_exist, *to_exist;
1022 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1024 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1026 list_remove(&from_exist->entry);
1027 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1028 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1029 HeapFree(GetProcessHeap(), 0, from_exist);
1030 from_exist = NULL;
1033 if(!from_exist)
1035 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1037 if(to_exist)
1039 HeapFree(GetProcessHeap(), 0, subst->to.name);
1040 subst->to.name = strdupW(to_exist->to.name);
1043 list_add_tail(subst_list, &subst->entry);
1045 return TRUE;
1048 HeapFree(GetProcessHeap(), 0, subst->from.name);
1049 HeapFree(GetProcessHeap(), 0, subst->to.name);
1050 HeapFree(GetProcessHeap(), 0, subst);
1051 return FALSE;
1054 static WCHAR *towstr(UINT cp, const char *str)
1056 int len;
1057 WCHAR *wstr;
1059 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1060 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1061 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1062 return wstr;
1065 static void split_subst_info(NameCs *nc, LPSTR str)
1067 CHAR *p = strrchr(str, ',');
1069 nc->charset = -1;
1070 if(p && *(p+1)) {
1071 nc->charset = strtol(p+1, NULL, 10);
1072 *p = '\0';
1074 nc->name = towstr(CP_ACP, str);
1077 static void LoadSubstList(void)
1079 FontSubst *psub;
1080 HKEY hkey;
1081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1082 LPSTR value;
1083 LPVOID data;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey) == ERROR_SUCCESS) {
1089 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1090 &valuelen, &datalen, NULL, NULL);
1092 valuelen++; /* returned value doesn't include room for '\0' */
1093 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1094 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1096 dlen = datalen;
1097 vlen = valuelen;
1098 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1099 &dlen) == ERROR_SUCCESS) {
1100 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1102 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1103 split_subst_info(&psub->from, value);
1104 split_subst_info(&psub->to, data);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1109 psub->to.charset == DEFAULT_CHARSET) {
1110 HeapFree(GetProcessHeap(), 0, psub->to.name);
1111 HeapFree(GetProcessHeap(), 0, psub->from.name);
1112 HeapFree(GetProcessHeap(), 0, psub);
1113 } else {
1114 add_font_subst(&font_subst_list, psub, 0);
1116 /* reset dlen and vlen */
1117 dlen = datalen;
1118 vlen = valuelen;
1120 HeapFree(GetProcessHeap(), 0, data);
1121 HeapFree(GetProcessHeap(), 0, value);
1122 RegCloseKey(hkey);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1137 FT_SfntName name;
1138 FT_UInt num_names, name_index;
1140 if(FT_IS_SFNT(ft_face))
1142 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1144 for(name_index = 0; name_index < num_names; name_index++)
1146 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1148 if((name.platform_id == req->platform_id) &&
1149 (name.encoding_id == req->encoding_id) &&
1150 (name.language_id == req->language_id) &&
1151 (name.name_id == req->name_id))
1153 req->string = name.string;
1154 req->string_len = name.string_len;
1155 return TRUE;
1160 req->string = NULL;
1161 req->string_len = 0;
1162 return FALSE;
1165 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1167 WCHAR *ret = NULL;
1168 FT_SfntName name;
1170 name.platform_id = TT_PLATFORM_MICROSOFT;
1171 name.encoding_id = TT_MS_ID_UNICODE_CS;
1172 name.language_id = language_id;
1173 name.name_id = name_id;
1175 if(get_name_table_entry(ft_face, &name))
1177 FT_UInt i;
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1181 for(i = 0; i < name.string_len / 2; i++)
1183 WORD *tmp = (WORD *)&name.string[i * 2];
1184 ret[i] = GET_BE_WORD(*tmp);
1186 ret[i] = 0;
1187 TRACE("Got localised name %s\n", debugstr_w(ret));
1190 return ret;
1193 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1195 DWORD type, needed;
1196 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1197 if(r != ERROR_SUCCESS) return r;
1198 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1199 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1202 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1204 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1207 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1209 DWORD needed;
1210 DWORD num_strikes, max_strike_key_len;
1212 /* If we have a File Name key then this is a real font, not just the parent
1213 key of a bunch of non-scalable strikes */
1214 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1216 DWORD italic, bold;
1217 Face *face;
1218 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1219 face->cached_enum_data = NULL;
1221 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1222 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1224 face->StyleName = strdupW(face_name);
1225 face->family = family;
1226 face->vertical = (family->FamilyName[0] == '@');
1228 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1230 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1231 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1232 face->FullName = fullName;
1234 else
1235 face->FullName = NULL;
1237 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1238 reg_load_dword(hkey_face, face_italic_value, &italic);
1239 reg_load_dword(hkey_face, face_bold_value, &bold);
1240 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1241 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1243 needed = sizeof(face->fs);
1244 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1246 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1248 face->scalable = TRUE;
1249 memset(&face->size, 0, sizeof(face->size));
1251 else
1253 face->scalable = FALSE;
1254 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1255 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1256 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1257 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1258 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1260 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1261 face->size.height, face->size.width, face->size.size >> 6,
1262 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1265 face->ntmFlags = 0;
1266 if (italic) face->ntmFlags |= NTM_ITALIC;
1267 if (bold) face->ntmFlags |= NTM_BOLD;
1268 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1270 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1271 face->fs.fsCsb[0], face->fs.fsCsb[1],
1272 face->fs.fsUsb[0], face->fs.fsUsb[1],
1273 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1275 if(!italic && !bold)
1276 list_add_head(&family->faces, &face->entry);
1277 else
1278 list_add_tail(&family->faces, &face->entry);
1280 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1283 /* do we have any bitmap strikes? */
1284 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1285 NULL, NULL, NULL, NULL);
1286 if(num_strikes != 0)
1288 WCHAR strike_name[10];
1289 DWORD strike_index = 0;
1291 needed = sizeof(strike_name) / sizeof(WCHAR);
1292 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1293 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1295 HKEY hkey_strike;
1296 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1297 load_face(hkey_strike, face_name, family);
1298 RegCloseKey(hkey_strike);
1299 needed = sizeof(strike_name) / sizeof(WCHAR);
1304 static void load_font_list_from_cache(HKEY hkey_font_cache)
1306 DWORD max_family_key_len, size;
1307 WCHAR *family_name;
1308 DWORD family_index = 0;
1309 Family *family;
1310 HKEY hkey_family;
1312 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1313 NULL, NULL, NULL, NULL);
1314 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1316 size = max_family_key_len + 1;
1317 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1318 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1320 WCHAR *english_family = NULL;
1321 DWORD face_index = 0;
1322 WCHAR *face_name;
1323 DWORD max_face_key_len;
1325 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1326 TRACE("opened family key %s\n", debugstr_w(family_name));
1327 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1329 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1330 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1333 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1334 family->FamilyName = strdupW(family_name);
1335 family->EnglishName = english_family;
1336 list_init(&family->faces);
1337 family->replacement = &family->faces;
1338 list_add_tail(&font_list, &family->entry);
1340 if(english_family)
1342 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1343 subst->from.name = strdupW(english_family);
1344 subst->from.charset = -1;
1345 subst->to.name = strdupW(family_name);
1346 subst->to.charset = -1;
1347 add_font_subst(&font_subst_list, subst, 0);
1350 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1351 NULL, NULL, NULL, NULL);
1353 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1354 size = max_face_key_len + 1;
1355 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1356 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1358 HKEY hkey_face;
1360 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1361 load_face(hkey_face, face_name, family);
1362 RegCloseKey(hkey_face);
1363 size = max_face_key_len + 1;
1365 HeapFree(GetProcessHeap(), 0, face_name);
1366 RegCloseKey(hkey_family);
1367 size = max_family_key_len + 1;
1370 HeapFree(GetProcessHeap(), 0, family_name);
1373 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1375 LONG ret;
1376 HKEY hkey_wine_fonts;
1378 /* We don't want to create the fonts key as volatile, so open this first */
1379 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1380 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1381 if(ret != ERROR_SUCCESS)
1383 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1384 return ret;
1387 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1388 KEY_ALL_ACCESS, NULL, hkey, disposition);
1389 RegCloseKey(hkey_wine_fonts);
1390 return ret;
1393 static void add_face_to_cache(Face *face)
1395 HKEY hkey_font_cache, hkey_family, hkey_face;
1396 WCHAR *face_key_name;
1398 create_font_cache_key(&hkey_font_cache, NULL);
1400 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1401 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1402 if(face->family->EnglishName)
1403 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1404 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1406 if(face->scalable)
1407 face_key_name = face->StyleName;
1408 else
1410 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1411 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1412 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1414 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1415 &hkey_face, NULL);
1416 if(!face->scalable)
1417 HeapFree(GetProcessHeap(), 0, face_key_name);
1419 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1420 if (face->FullName)
1421 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1422 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1424 reg_save_dword(hkey_face, face_index_value, face->face_index);
1425 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1426 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1427 reg_save_dword(hkey_face, face_version_value, face->font_version);
1428 reg_save_dword(hkey_face, face_external_value, face->external);
1430 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1432 if(!face->scalable)
1434 reg_save_dword(hkey_face, face_height_value, face->size.height);
1435 reg_save_dword(hkey_face, face_width_value, face->size.width);
1436 reg_save_dword(hkey_face, face_size_value, face->size.size);
1437 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1438 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1439 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1441 RegCloseKey(hkey_face);
1442 RegCloseKey(hkey_family);
1443 RegCloseKey(hkey_font_cache);
1446 static inline int TestStyles(DWORD flags, DWORD styles)
1448 return (flags & styles) == styles;
1451 static inline int style_order(Face *face)
1453 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1454 return 3;
1455 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1456 return 2;
1457 if (TestStyles(face->ntmFlags, NTM_BOLD))
1458 return 1;
1459 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1460 return 0;
1462 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1463 debugstr_w(face->family->FamilyName),
1464 debugstr_w(face->StyleName),
1465 face->ntmFlags);
1467 return 9999;
1470 static WCHAR *prepend_at(WCHAR *family)
1472 WCHAR *str;
1474 if (!family)
1475 return NULL;
1477 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1478 str[0] = '@';
1479 strcpyW(str + 1, family);
1480 HeapFree(GetProcessHeap(), 0, family);
1481 return str;
1484 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1486 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1487 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1489 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1490 if (!*name)
1492 *name = *english;
1493 *english = NULL;
1495 else if (!strcmpiW( *name, *english ))
1497 HeapFree( GetProcessHeap(), 0, *english );
1498 *english = NULL;
1501 if (vertical)
1503 *name = prepend_at( *name );
1504 *english = prepend_at( *english );
1508 /****************************************************************
1509 * NB This function stores the ptrs to the strings to save copying.
1510 * Don't free them after calling.
1512 static Family *create_family( WCHAR *name, WCHAR *english_name )
1514 Family *family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1515 family->FamilyName = name;
1516 family->EnglishName = english_name;
1517 list_init( &family->faces );
1518 family->replacement = &family->faces;
1520 return family;
1523 static Family *get_family( FT_Face ft_face, BOOL vertical )
1525 Family *family;
1526 WCHAR *name, *english_name;
1528 get_family_names( ft_face, &name, &english_name, vertical );
1530 family = find_family_from_name( name );
1532 if (!family)
1534 family = create_family( name, english_name );
1535 list_add_tail( &font_list, &family->entry );
1537 if (english_name)
1539 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1540 subst->from.name = strdupW( english_name );
1541 subst->from.charset = -1;
1542 subst->to.name = strdupW( name );
1543 subst->to.charset = -1;
1544 add_font_subst( &font_subst_list, subst, 0 );
1547 else
1549 HeapFree( GetProcessHeap(), 0, name );
1550 HeapFree( GetProcessHeap(), 0, english_name );
1553 return family;
1556 static inline FT_Fixed get_font_version( FT_Face ft_face )
1558 FT_Fixed version = 0;
1559 TT_Header *header;
1561 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1562 if (header) version = header->Font_Revision;
1564 return version;
1567 static inline DWORD get_ntm_flags( FT_Face ft_face )
1569 DWORD flags = 0;
1570 FT_ULong table_size = 0;
1572 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1573 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1574 if (flags == 0) flags = NTM_REGULAR;
1576 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1577 flags |= NTM_PS_OPENTYPE;
1579 return flags;
1582 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1584 int internal_leading = 0;
1585 FT_WinFNT_HeaderRec winfnt_header;
1587 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1588 internal_leading = winfnt_header.internal_leading;
1590 return internal_leading;
1593 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1595 TT_OS2 *os2;
1596 FT_UInt dummy;
1597 CHARSETINFO csi;
1598 FT_WinFNT_HeaderRec winfnt_header;
1599 int i;
1601 memset( fs, 0, sizeof(*fs) );
1603 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1604 if (os2)
1606 fs->fsUsb[0] = os2->ulUnicodeRange1;
1607 fs->fsUsb[1] = os2->ulUnicodeRange2;
1608 fs->fsUsb[2] = os2->ulUnicodeRange3;
1609 fs->fsUsb[3] = os2->ulUnicodeRange4;
1611 if (os2->version == 0)
1613 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1614 fs->fsCsb[0] = FS_LATIN1;
1615 else
1616 fs->fsCsb[0] = FS_SYMBOL;
1618 else
1620 fs->fsCsb[0] = os2->ulCodePageRange1;
1621 fs->fsCsb[1] = os2->ulCodePageRange2;
1624 else
1626 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1628 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1629 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1630 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1631 *fs = csi.fs;
1635 if (fs->fsCsb[0] == 0)
1637 /* let's see if we can find any interesting cmaps */
1638 for (i = 0; i < ft_face->num_charmaps; i++)
1640 switch (ft_face->charmaps[i]->encoding)
1642 case FT_ENCODING_UNICODE:
1643 case FT_ENCODING_APPLE_ROMAN:
1644 fs->fsCsb[0] |= FS_LATIN1;
1645 break;
1646 case FT_ENCODING_MS_SYMBOL:
1647 fs->fsCsb[0] |= FS_SYMBOL;
1648 break;
1649 default:
1650 break;
1656 static inline void free_face( Face *face )
1658 HeapFree( GetProcessHeap(), 0, face->file );
1659 HeapFree( GetProcessHeap(), 0, face->StyleName );
1660 HeapFree( GetProcessHeap(), 0, face->FullName );
1661 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1662 HeapFree( GetProcessHeap(), 0, face );
1665 #define ADDFONT_EXTERNAL_FONT 0x01
1666 #define ADDFONT_FORCE_BITMAP 0x02
1667 #define ADDFONT_ADD_TO_CACHE 0x04
1669 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1670 DWORD flags, BOOL vertical )
1672 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1673 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1675 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1676 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1677 if (file)
1679 face->file = strdupA( file );
1680 face->font_data_ptr = NULL;
1681 face->font_data_size = 0;
1683 else
1685 face->file = NULL;
1686 face->font_data_ptr = font_data_ptr;
1687 face->font_data_size = font_data_size;
1690 face->face_index = face_index;
1691 get_fontsig( ft_face, &face->fs );
1692 face->ntmFlags = get_ntm_flags( ft_face );
1693 face->font_version = get_font_version( ft_face );
1695 if (FT_IS_SCALABLE( ft_face ))
1697 memset( &face->size, 0, sizeof(face->size) );
1698 face->scalable = TRUE;
1700 else
1702 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1703 size->height, size->width, size->size >> 6,
1704 size->x_ppem >> 6, size->y_ppem >> 6);
1705 face->size.height = size->height;
1706 face->size.width = size->width;
1707 face->size.size = size->size;
1708 face->size.x_ppem = size->x_ppem;
1709 face->size.y_ppem = size->y_ppem;
1710 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1711 face->scalable = FALSE;
1714 face->vertical = vertical;
1715 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1716 face->family = NULL;
1717 face->cached_enum_data = NULL;
1719 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1720 face->fs.fsCsb[0], face->fs.fsCsb[1],
1721 face->fs.fsUsb[0], face->fs.fsUsb[1],
1722 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1724 return face;
1727 static inline BOOL faces_equal( Face *f1, Face *f2 )
1729 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1730 if (f1->scalable) return TRUE;
1731 if (f2->size.y_ppem != f2->size.y_ppem) return FALSE;
1732 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1735 static BOOL insert_face_in_family_list( Face *face, Family *family )
1737 Face *cursor;
1739 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1741 if (faces_equal( face, cursor ))
1743 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1744 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1745 cursor->font_version, face->font_version);
1747 if (face->font_version <= cursor->font_version)
1749 TRACE("Original font is newer so skipping this one\n");
1750 return FALSE;
1752 else
1754 TRACE("Replacing original with this one\n");
1755 list_add_before( &cursor->entry, &face->entry );
1756 face->family = family;
1757 list_remove( &cursor->entry);
1758 free_face( cursor );
1759 return TRUE;
1763 if (style_order( face ) < style_order( cursor )) break;
1766 list_add_before( &cursor->entry, &face->entry );
1767 face->family = family;
1768 return TRUE;
1771 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1772 FT_Long face_index, DWORD flags, BOOL vertical)
1774 Face *face;
1775 Family *family;
1777 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical );
1778 family = get_family( ft_face, vertical );
1779 if (!insert_face_in_family_list( face, family ))
1781 free_face( face );
1782 return;
1785 if (flags & ADDFONT_ADD_TO_CACHE)
1786 add_face_to_cache( face );
1788 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1789 debugstr_w(face->StyleName));
1792 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1794 FT_Face ft_face;
1795 TT_OS2 *pOS2;
1796 FT_Error err;
1797 FT_Long face_index = 0, num_faces;
1798 INT ret = 0;
1800 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1801 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1803 #ifdef HAVE_CARBON_CARBON_H
1804 if(file)
1806 char **mac_list = expand_mac_font(file);
1807 if(mac_list)
1809 BOOL had_one = FALSE;
1810 char **cursor;
1811 for(cursor = mac_list; *cursor; cursor++)
1813 had_one = TRUE;
1814 AddFontToList(*cursor, NULL, 0, flags);
1815 HeapFree(GetProcessHeap(), 0, *cursor);
1817 HeapFree(GetProcessHeap(), 0, mac_list);
1818 if(had_one)
1819 return 1;
1822 #endif /* HAVE_CARBON_CARBON_H */
1824 do {
1825 if (file)
1827 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1828 err = pFT_New_Face(library, file, face_index, &ft_face);
1829 } else
1831 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1832 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1835 if(err != 0) {
1836 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1837 return 0;
1840 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1841 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1842 pFT_Done_Face(ft_face);
1843 return 0;
1846 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1847 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1848 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1849 pFT_Done_Face(ft_face);
1850 return 0;
1853 if(FT_IS_SFNT(ft_face))
1855 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1856 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1857 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))
1859 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1860 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1861 pFT_Done_Face(ft_face);
1862 return 0;
1865 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1866 we don't want to load these. */
1867 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1869 FT_ULong len = 0;
1871 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1873 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1874 pFT_Done_Face(ft_face);
1875 return 0;
1880 if(!ft_face->family_name || !ft_face->style_name) {
1881 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1882 pFT_Done_Face(ft_face);
1883 return 0;
1886 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1888 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1889 pFT_Done_Face(ft_face);
1890 return 0;
1893 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1894 ++ret;
1896 if (FT_HAS_VERTICAL(ft_face))
1898 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1899 ++ret;
1902 num_faces = ft_face->num_faces;
1903 pFT_Done_Face(ft_face);
1904 } while(num_faces > ++face_index);
1905 return ret;
1908 static void DumpFontList(void)
1910 Family *family;
1911 Face *face;
1912 struct list *family_elem_ptr, *face_elem_ptr;
1914 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1915 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1916 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1917 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1918 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1919 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1920 if(!face->scalable)
1921 TRACE(" %d", face->size.height);
1922 TRACE("\n");
1925 return;
1928 /***********************************************************
1929 * The replacement list is a way to map an entire font
1930 * family onto another family. For example adding
1932 * [HKCU\Software\Wine\Fonts\Replacements]
1933 * "Wingdings"="Winedings"
1935 * would enumerate the Winedings font both as Winedings and
1936 * Wingdings. However if a real Wingdings font is present the
1937 * replacement does not take place.
1940 static void LoadReplaceList(void)
1942 HKEY hkey;
1943 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1944 LPWSTR value;
1945 LPVOID data;
1946 CHAR familyA[400];
1948 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1949 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1951 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1952 &valuelen, &datalen, NULL, NULL);
1954 valuelen++; /* returned value doesn't include room for '\0' */
1955 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1956 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1958 dlen = datalen;
1959 vlen = valuelen;
1960 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1961 &dlen) == ERROR_SUCCESS) {
1962 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1963 /* "NewName"="Oldname" */
1964 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1966 if(!find_family_from_any_name(value))
1968 Family * const family = find_family_from_any_name(data);
1969 if (family != NULL)
1971 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1972 if (new_family != NULL)
1974 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1975 new_family->FamilyName = strdupW(value);
1976 new_family->EnglishName = NULL;
1977 list_init(&new_family->faces);
1978 new_family->replacement = &family->faces;
1979 list_add_tail(&font_list, &new_family->entry);
1982 else
1984 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1987 else
1989 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1991 /* reset dlen and vlen */
1992 dlen = datalen;
1993 vlen = valuelen;
1995 HeapFree(GetProcessHeap(), 0, data);
1996 HeapFree(GetProcessHeap(), 0, value);
1997 RegCloseKey(hkey);
2001 static const WCHAR *font_links_list[] =
2003 Lucida_Sans_Unicode,
2004 Microsoft_Sans_Serif,
2005 Tahoma
2008 static const struct font_links_defaults_list
2010 /* Keyed off substitution for "MS Shell Dlg" */
2011 const WCHAR *shelldlg;
2012 /* Maximum of four substitutes, plus terminating NULL pointer */
2013 const WCHAR *substitutes[5];
2014 } font_links_defaults_list[] =
2016 /* Non East-Asian */
2017 { Tahoma, /* FIXME unverified ordering */
2018 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2020 /* Below lists are courtesy of
2021 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2023 /* Japanese */
2024 { MS_UI_Gothic,
2025 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2027 /* Chinese Simplified */
2028 { SimSun,
2029 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2031 /* Korean */
2032 { Gulim,
2033 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2035 /* Chinese Traditional */
2036 { PMingLiU,
2037 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2042 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2044 SYSTEM_LINKS *font_link;
2046 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2048 if(!strcmpiW(font_link->font_name, name))
2049 return font_link;
2052 return NULL;
2055 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2057 const WCHAR *value;
2058 int i;
2059 FontSubst *psub;
2060 Family *family;
2061 Face *face;
2062 const char *file;
2063 WCHAR *fileW;
2065 if (values)
2067 SYSTEM_LINKS *font_link;
2069 psub = get_font_subst(&font_subst_list, name, -1);
2070 /* Don't store fonts that are only substitutes for other fonts */
2071 if(psub)
2073 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2074 return;
2077 font_link = find_font_link(name);
2078 if (font_link == NULL)
2080 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2081 font_link->font_name = strdupW(name);
2082 list_init(&font_link->links);
2083 list_add_tail(&system_links, &font_link->entry);
2086 memset(&font_link->fs, 0, sizeof font_link->fs);
2087 for (i = 0; values[i] != NULL; i++)
2089 const struct list *face_list;
2090 CHILD_FONT *child_font;
2092 value = values[i];
2093 if (!strcmpiW(name,value))
2094 continue;
2095 psub = get_font_subst(&font_subst_list, value, -1);
2096 if(psub)
2097 value = psub->to.name;
2098 family = find_family_from_name(value);
2099 if (!family)
2100 continue;
2101 file = NULL;
2102 /* Use first extant filename for this Family */
2103 face_list = get_face_list_from_family(family);
2104 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2106 if (!face->file)
2107 continue;
2108 file = strrchr(face->file, '/');
2109 if (!file)
2110 file = face->file;
2111 else
2112 file++;
2113 break;
2115 if (!file)
2116 continue;
2117 fileW = towstr(CP_UNIXCP, file);
2119 face = find_face_from_filename(fileW, value);
2120 if(!face)
2122 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2123 continue;
2126 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2127 child_font->face = face;
2128 child_font->font = NULL;
2129 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2130 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2131 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2132 list_add_tail(&font_link->links, &child_font->entry);
2134 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2135 HeapFree(GetProcessHeap(), 0, fileW);
2141 /*************************************************************
2142 * init_system_links
2144 static BOOL init_system_links(void)
2146 HKEY hkey;
2147 BOOL ret = FALSE;
2148 DWORD type, max_val, max_data, val_len, data_len, index;
2149 WCHAR *value, *data;
2150 WCHAR *entry, *next;
2151 SYSTEM_LINKS *font_link, *system_font_link;
2152 CHILD_FONT *child_font;
2153 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2154 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2155 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2156 Face *face;
2157 FontSubst *psub;
2158 UINT i, j;
2160 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2162 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2163 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2164 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2165 val_len = max_val + 1;
2166 data_len = max_data;
2167 index = 0;
2168 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2170 psub = get_font_subst(&font_subst_list, value, -1);
2171 /* Don't store fonts that are only substitutes for other fonts */
2172 if(psub)
2174 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2175 goto next;
2177 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2178 font_link->font_name = strdupW(value);
2179 memset(&font_link->fs, 0, sizeof font_link->fs);
2180 list_init(&font_link->links);
2181 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2183 WCHAR *face_name;
2184 CHILD_FONT *child_font;
2186 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2188 next = entry + strlenW(entry) + 1;
2190 face_name = strchrW(entry, ',');
2191 if(face_name)
2193 *face_name++ = 0;
2194 while(isspaceW(*face_name))
2195 face_name++;
2197 psub = get_font_subst(&font_subst_list, face_name, -1);
2198 if(psub)
2199 face_name = psub->to.name;
2201 face = find_face_from_filename(entry, face_name);
2202 if(!face)
2204 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2205 continue;
2208 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2209 child_font->face = face;
2210 child_font->font = NULL;
2211 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2212 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2213 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2214 list_add_tail(&font_link->links, &child_font->entry);
2216 list_add_tail(&system_links, &font_link->entry);
2217 next:
2218 val_len = max_val + 1;
2219 data_len = max_data;
2222 HeapFree(GetProcessHeap(), 0, value);
2223 HeapFree(GetProcessHeap(), 0, data);
2224 RegCloseKey(hkey);
2228 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2229 if (!psub) {
2230 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2231 goto skip_internal;
2234 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2236 const FontSubst *psub2;
2237 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2239 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2241 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2242 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2244 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2245 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2247 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2249 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2253 skip_internal:
2255 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2256 that Tahoma has */
2258 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2259 system_font_link->font_name = strdupW(System);
2260 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2261 list_init(&system_font_link->links);
2263 face = find_face_from_filename(tahoma_ttf, Tahoma);
2264 if(face)
2266 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2267 child_font->face = face;
2268 child_font->font = NULL;
2269 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2270 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2271 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2272 list_add_tail(&system_font_link->links, &child_font->entry);
2274 font_link = find_font_link(Tahoma);
2275 if (font_link != NULL)
2277 CHILD_FONT *font_link_entry;
2278 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2280 CHILD_FONT *new_child;
2281 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2282 new_child->face = font_link_entry->face;
2283 new_child->font = NULL;
2284 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2285 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2286 list_add_tail(&system_font_link->links, &new_child->entry);
2289 list_add_tail(&system_links, &system_font_link->entry);
2290 return ret;
2293 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2295 DIR *dir;
2296 struct dirent *dent;
2297 char path[MAX_PATH];
2299 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2301 dir = opendir(dirname);
2302 if(!dir) {
2303 WARN("Can't open directory %s\n", debugstr_a(dirname));
2304 return FALSE;
2306 while((dent = readdir(dir)) != NULL) {
2307 struct stat statbuf;
2309 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2310 continue;
2312 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2314 sprintf(path, "%s/%s", dirname, dent->d_name);
2316 if(stat(path, &statbuf) == -1)
2318 WARN("Can't stat %s\n", debugstr_a(path));
2319 continue;
2321 if(S_ISDIR(statbuf.st_mode))
2322 ReadFontDir(path, external_fonts);
2323 else
2325 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2326 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2327 AddFontToList(path, NULL, 0, addfont_flags);
2330 closedir(dir);
2331 return TRUE;
2334 static void load_fontconfig_fonts(void)
2336 #ifdef SONAME_LIBFONTCONFIG
2337 void *fc_handle = NULL;
2338 FcConfig *config;
2339 FcPattern *pat;
2340 FcObjectSet *os;
2341 FcFontSet *fontset;
2342 int i, len;
2343 char *file;
2344 const char *ext;
2346 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2347 if(!fc_handle) {
2348 TRACE("Wine cannot find the fontconfig library (%s).\n",
2349 SONAME_LIBFONTCONFIG);
2350 return;
2352 #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;}
2353 LOAD_FUNCPTR(FcConfigGetCurrent);
2354 LOAD_FUNCPTR(FcFontList);
2355 LOAD_FUNCPTR(FcFontSetDestroy);
2356 LOAD_FUNCPTR(FcInit);
2357 LOAD_FUNCPTR(FcObjectSetAdd);
2358 LOAD_FUNCPTR(FcObjectSetCreate);
2359 LOAD_FUNCPTR(FcObjectSetDestroy);
2360 LOAD_FUNCPTR(FcPatternCreate);
2361 LOAD_FUNCPTR(FcPatternDestroy);
2362 LOAD_FUNCPTR(FcPatternGetBool);
2363 LOAD_FUNCPTR(FcPatternGetString);
2364 #undef LOAD_FUNCPTR
2366 if(!pFcInit()) return;
2368 config = pFcConfigGetCurrent();
2369 pat = pFcPatternCreate();
2370 os = pFcObjectSetCreate();
2371 pFcObjectSetAdd(os, FC_FILE);
2372 pFcObjectSetAdd(os, FC_SCALABLE);
2373 fontset = pFcFontList(config, pat, os);
2374 if(!fontset) return;
2375 for(i = 0; i < fontset->nfont; i++) {
2376 FcBool scalable;
2378 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2379 continue;
2380 TRACE("fontconfig: %s\n", file);
2382 /* We're just interested in OT/TT fonts for now, so this hack just
2383 picks up the scalable fonts without extensions .pf[ab] to save time
2384 loading every other font */
2386 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2388 TRACE("not scalable\n");
2389 continue;
2392 len = strlen( file );
2393 if(len < 4) continue;
2394 ext = &file[ len - 3 ];
2395 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2396 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2398 pFcFontSetDestroy(fontset);
2399 pFcObjectSetDestroy(os);
2400 pFcPatternDestroy(pat);
2401 sym_not_found:
2402 #endif
2403 return;
2406 static BOOL load_font_from_data_dir(LPCWSTR file)
2408 BOOL ret = FALSE;
2409 const char *data_dir = wine_get_data_dir();
2411 if (!data_dir) data_dir = wine_get_build_dir();
2413 if (data_dir)
2415 INT len;
2416 char *unix_name;
2418 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2420 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2422 strcpy(unix_name, data_dir);
2423 strcat(unix_name, "/fonts/");
2425 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2427 EnterCriticalSection( &freetype_cs );
2428 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2429 LeaveCriticalSection( &freetype_cs );
2430 HeapFree(GetProcessHeap(), 0, unix_name);
2432 return ret;
2435 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2437 static const WCHAR slashW[] = {'\\','\0'};
2438 BOOL ret = FALSE;
2439 WCHAR windowsdir[MAX_PATH];
2440 char *unixname;
2442 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2443 strcatW(windowsdir, fontsW);
2444 strcatW(windowsdir, slashW);
2445 strcatW(windowsdir, file);
2446 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2447 EnterCriticalSection( &freetype_cs );
2448 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2449 LeaveCriticalSection( &freetype_cs );
2450 HeapFree(GetProcessHeap(), 0, unixname);
2452 return ret;
2455 static void load_system_fonts(void)
2457 HKEY hkey;
2458 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2459 const WCHAR * const *value;
2460 DWORD dlen, type;
2461 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2462 char *unixname;
2464 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2465 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2466 strcatW(windowsdir, fontsW);
2467 for(value = SystemFontValues; *value; value++) {
2468 dlen = sizeof(data);
2469 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2470 type == REG_SZ) {
2471 BOOL added = FALSE;
2473 sprintfW(pathW, fmtW, windowsdir, data);
2474 if((unixname = wine_get_unix_file_name(pathW))) {
2475 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2476 HeapFree(GetProcessHeap(), 0, unixname);
2478 if (!added)
2479 load_font_from_data_dir(data);
2482 RegCloseKey(hkey);
2486 /*************************************************************
2488 * This adds registry entries for any externally loaded fonts
2489 * (fonts from fontconfig or FontDirs). It also deletes entries
2490 * of no longer existing fonts.
2493 static void update_reg_entries(void)
2495 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2496 LPWSTR valueW;
2497 DWORD len, len_fam;
2498 Family *family;
2499 Face *face;
2500 struct list *family_elem_ptr, *face_elem_ptr;
2501 WCHAR *file;
2502 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2503 static const WCHAR spaceW[] = {' ', '\0'};
2504 char *path;
2506 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2507 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2508 ERR("Can't create Windows font reg key\n");
2509 goto end;
2512 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2513 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2514 ERR("Can't create Windows font reg key\n");
2515 goto end;
2518 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2519 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2520 ERR("Can't create external font reg key\n");
2521 goto end;
2524 /* enumerate the fonts and add external ones to the two keys */
2526 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2527 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2528 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2529 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2530 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2531 if(!face->external) continue;
2532 len = len_fam;
2533 if (!(face->ntmFlags & NTM_REGULAR))
2534 len = len_fam + strlenW(face->StyleName) + 1;
2535 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2536 strcpyW(valueW, family->FamilyName);
2537 if(len != len_fam) {
2538 strcatW(valueW, spaceW);
2539 strcatW(valueW, face->StyleName);
2541 strcatW(valueW, TrueType);
2543 file = wine_get_dos_file_name(face->file);
2544 if(file)
2545 len = strlenW(file) + 1;
2546 else
2548 if((path = strrchr(face->file, '/')) == NULL)
2549 path = face->file;
2550 else
2551 path++;
2552 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2554 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2555 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2557 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2558 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2559 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2561 HeapFree(GetProcessHeap(), 0, file);
2562 HeapFree(GetProcessHeap(), 0, valueW);
2565 end:
2566 if(external_key) RegCloseKey(external_key);
2567 if(win9x_key) RegCloseKey(win9x_key);
2568 if(winnt_key) RegCloseKey(winnt_key);
2569 return;
2572 static void delete_external_font_keys(void)
2574 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2575 DWORD dlen, vlen, datalen, valuelen, i, type;
2576 LPWSTR valueW;
2577 LPVOID data;
2579 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2580 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2581 ERR("Can't create Windows font reg key\n");
2582 goto end;
2585 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2586 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2587 ERR("Can't create Windows font reg key\n");
2588 goto end;
2591 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2592 ERR("Can't create external font reg key\n");
2593 goto end;
2596 /* Delete all external fonts added last time */
2598 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2599 &valuelen, &datalen, NULL, NULL);
2600 valuelen++; /* returned value doesn't include room for '\0' */
2601 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2602 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2604 dlen = datalen * sizeof(WCHAR);
2605 vlen = valuelen;
2606 i = 0;
2607 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2608 &dlen) == ERROR_SUCCESS) {
2610 RegDeleteValueW(winnt_key, valueW);
2611 RegDeleteValueW(win9x_key, valueW);
2612 /* reset dlen and vlen */
2613 dlen = datalen;
2614 vlen = valuelen;
2616 HeapFree(GetProcessHeap(), 0, data);
2617 HeapFree(GetProcessHeap(), 0, valueW);
2619 /* Delete the old external fonts key */
2620 RegCloseKey(external_key);
2621 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2623 end:
2624 if(win9x_key) RegCloseKey(win9x_key);
2625 if(winnt_key) RegCloseKey(winnt_key);
2628 /*************************************************************
2629 * WineEngAddFontResourceEx
2632 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2634 INT ret = 0;
2636 GDI_CheckNotLock();
2638 if (ft_handle) /* do it only if we have freetype up and running */
2640 char *unixname;
2642 if(flags)
2643 FIXME("Ignoring flags %x\n", flags);
2645 if((unixname = wine_get_unix_file_name(file)))
2647 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2649 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2650 EnterCriticalSection( &freetype_cs );
2651 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2652 LeaveCriticalSection( &freetype_cs );
2653 HeapFree(GetProcessHeap(), 0, unixname);
2655 if (!ret && !strchrW(file, '\\')) {
2656 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2657 ret = load_font_from_winfonts_dir(file);
2658 if (!ret) {
2659 /* Try in datadir/fonts (or builddir/fonts),
2660 * needed for Magic the Gathering Online
2662 ret = load_font_from_data_dir(file);
2666 return ret;
2669 /*************************************************************
2670 * WineEngAddFontMemResourceEx
2673 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2675 GDI_CheckNotLock();
2677 if (ft_handle) /* do it only if we have freetype up and running */
2679 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2681 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2682 memcpy(pFontCopy, pbFont, cbFont);
2684 EnterCriticalSection( &freetype_cs );
2685 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2686 LeaveCriticalSection( &freetype_cs );
2688 if (*pcFonts == 0)
2690 TRACE("AddFontToList failed\n");
2691 HeapFree(GetProcessHeap(), 0, pFontCopy);
2692 return 0;
2694 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2695 * For now return something unique but quite random
2697 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2698 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2701 *pcFonts = 0;
2702 return 0;
2705 /*************************************************************
2706 * WineEngRemoveFontResourceEx
2709 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2711 GDI_CheckNotLock();
2712 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2713 return TRUE;
2716 static const struct nls_update_font_list
2718 UINT ansi_cp, oem_cp;
2719 const char *oem, *fixed, *system;
2720 const char *courier, *serif, *small, *sserif;
2721 /* these are for font substitutes */
2722 const char *shelldlg, *tmsrmn;
2723 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2724 *helv_0, *tmsrmn_0;
2725 const struct subst
2727 const char *from, *to;
2728 } arial_0, courier_new_0, times_new_roman_0;
2729 } nls_update_font_list[] =
2731 /* Latin 1 (United States) */
2732 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2733 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2734 "Tahoma","Times New Roman",
2735 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2736 { 0 }, { 0 }, { 0 }
2738 /* Latin 1 (Multilingual) */
2739 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2740 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2741 "Tahoma","Times New Roman", /* FIXME unverified */
2742 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2743 { 0 }, { 0 }, { 0 }
2745 /* Eastern Europe */
2746 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2747 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2748 "Tahoma","Times New Roman", /* FIXME unverified */
2749 "Fixedsys,238", "System,238",
2750 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2751 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2752 { "Arial CE,0", "Arial,238" },
2753 { "Courier New CE,0", "Courier New,238" },
2754 { "Times New Roman CE,0", "Times New Roman,238" }
2756 /* Cyrillic */
2757 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2758 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2759 "Tahoma","Times New Roman", /* FIXME unverified */
2760 "Fixedsys,204", "System,204",
2761 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2762 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2763 { "Arial Cyr,0", "Arial,204" },
2764 { "Courier New Cyr,0", "Courier New,204" },
2765 { "Times New Roman Cyr,0", "Times New Roman,204" }
2767 /* Greek */
2768 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2769 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2770 "Tahoma","Times New Roman", /* FIXME unverified */
2771 "Fixedsys,161", "System,161",
2772 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2773 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2774 { "Arial Greek,0", "Arial,161" },
2775 { "Courier New Greek,0", "Courier New,161" },
2776 { "Times New Roman Greek,0", "Times New Roman,161" }
2778 /* Turkish */
2779 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2780 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2781 "Tahoma","Times New Roman", /* FIXME unverified */
2782 "Fixedsys,162", "System,162",
2783 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2784 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2785 { "Arial Tur,0", "Arial,162" },
2786 { "Courier New Tur,0", "Courier New,162" },
2787 { "Times New Roman Tur,0", "Times New Roman,162" }
2789 /* Hebrew */
2790 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2791 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2792 "Tahoma","Times New Roman", /* FIXME unverified */
2793 "Fixedsys,177", "System,177",
2794 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2795 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2796 { 0 }, { 0 }, { 0 }
2798 /* Arabic */
2799 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2800 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2801 "Tahoma","Times New Roman", /* FIXME unverified */
2802 "Fixedsys,178", "System,178",
2803 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2804 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2805 { 0 }, { 0 }, { 0 }
2807 /* Baltic */
2808 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2809 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2810 "Tahoma","Times New Roman", /* FIXME unverified */
2811 "Fixedsys,186", "System,186",
2812 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2813 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2814 { "Arial Baltic,0", "Arial,186" },
2815 { "Courier New Baltic,0", "Courier New,186" },
2816 { "Times New Roman Baltic,0", "Times New Roman,186" }
2818 /* Vietnamese */
2819 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2820 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2821 "Tahoma","Times New Roman", /* FIXME unverified */
2822 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2823 { 0 }, { 0 }, { 0 }
2825 /* Thai */
2826 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2827 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2828 "Tahoma","Times New Roman", /* FIXME unverified */
2829 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2830 { 0 }, { 0 }, { 0 }
2832 /* Japanese */
2833 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2834 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2835 "MS UI Gothic","MS Serif",
2836 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2837 { 0 }, { 0 }, { 0 }
2839 /* Chinese Simplified */
2840 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2841 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2842 "SimSun", "NSimSun",
2843 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2844 { 0 }, { 0 }, { 0 }
2846 /* Korean */
2847 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2848 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2849 "Gulim", "Batang",
2850 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2851 { 0 }, { 0 }, { 0 }
2853 /* Chinese Traditional */
2854 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2855 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2856 "PMingLiU", "MingLiU",
2857 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2858 { 0 }, { 0 }, { 0 }
2862 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2864 return ( ansi_cp == 932 /* CP932 for Japanese */
2865 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2866 || ansi_cp == 949 /* CP949 for Korean */
2867 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2870 static inline HKEY create_fonts_NT_registry_key(void)
2872 HKEY hkey = 0;
2874 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2875 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2876 return hkey;
2879 static inline HKEY create_fonts_9x_registry_key(void)
2881 HKEY hkey = 0;
2883 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2884 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2885 return hkey;
2888 static inline HKEY create_config_fonts_registry_key(void)
2890 HKEY hkey = 0;
2892 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2893 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2894 return hkey;
2897 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2899 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2900 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2901 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2902 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2905 static void set_value_key(HKEY hkey, const char *name, const char *value)
2907 if (value)
2908 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2909 else if (name)
2910 RegDeleteValueA(hkey, name);
2913 static void update_font_info(void)
2915 char buf[40], cpbuf[40];
2916 DWORD len, type;
2917 HKEY hkey = 0;
2918 UINT i, ansi_cp = 0, oem_cp = 0;
2919 BOOL done = FALSE;
2921 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2922 return;
2924 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2925 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2926 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2927 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2928 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2930 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2931 if (is_dbcs_ansi_cp(ansi_cp))
2932 use_default_fallback = TRUE;
2934 len = sizeof(buf);
2935 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2937 if (!strcmp( buf, cpbuf )) /* already set correctly */
2939 RegCloseKey(hkey);
2940 return;
2942 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2944 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2946 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2947 RegCloseKey(hkey);
2949 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2951 HKEY hkey;
2953 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2954 nls_update_font_list[i].oem_cp == oem_cp)
2956 hkey = create_config_fonts_registry_key();
2957 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2958 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2959 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2960 RegCloseKey(hkey);
2962 hkey = create_fonts_NT_registry_key();
2963 add_font_list(hkey, &nls_update_font_list[i]);
2964 RegCloseKey(hkey);
2966 hkey = create_fonts_9x_registry_key();
2967 add_font_list(hkey, &nls_update_font_list[i]);
2968 RegCloseKey(hkey);
2970 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2972 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2973 strlen(nls_update_font_list[i].shelldlg)+1);
2974 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2975 strlen(nls_update_font_list[i].tmsrmn)+1);
2977 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2978 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2979 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2980 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2981 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2982 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2983 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2984 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2986 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2987 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2988 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2990 RegCloseKey(hkey);
2992 done = TRUE;
2994 else
2996 /* Delete the FontSubstitutes from other locales */
2997 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2999 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3000 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3001 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3002 RegCloseKey(hkey);
3006 if (!done)
3007 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3010 static BOOL init_freetype(void)
3012 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3013 if(!ft_handle) {
3014 WINE_MESSAGE(
3015 "Wine cannot find the FreeType font library. To enable Wine to\n"
3016 "use TrueType fonts please install a version of FreeType greater than\n"
3017 "or equal to 2.0.5.\n"
3018 "http://www.freetype.org\n");
3019 return FALSE;
3022 #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;}
3024 LOAD_FUNCPTR(FT_Done_Face)
3025 LOAD_FUNCPTR(FT_Get_Char_Index)
3026 LOAD_FUNCPTR(FT_Get_First_Char)
3027 LOAD_FUNCPTR(FT_Get_Module)
3028 LOAD_FUNCPTR(FT_Get_Next_Char)
3029 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3030 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3031 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3032 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3033 LOAD_FUNCPTR(FT_Init_FreeType)
3034 LOAD_FUNCPTR(FT_Library_Version)
3035 LOAD_FUNCPTR(FT_Load_Glyph)
3036 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3037 LOAD_FUNCPTR(FT_Matrix_Multiply)
3038 #ifndef FT_MULFIX_INLINED
3039 LOAD_FUNCPTR(FT_MulFix)
3040 #endif
3041 LOAD_FUNCPTR(FT_New_Face)
3042 LOAD_FUNCPTR(FT_New_Memory_Face)
3043 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3044 LOAD_FUNCPTR(FT_Outline_Transform)
3045 LOAD_FUNCPTR(FT_Outline_Translate)
3046 LOAD_FUNCPTR(FT_Render_Glyph)
3047 LOAD_FUNCPTR(FT_Select_Charmap)
3048 LOAD_FUNCPTR(FT_Set_Charmap)
3049 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3050 LOAD_FUNCPTR(FT_Vector_Transform)
3051 LOAD_FUNCPTR(FT_Vector_Unit)
3052 #undef LOAD_FUNCPTR
3053 /* Don't warn if these ones are missing */
3054 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3055 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3056 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3057 #endif
3059 if(pFT_Init_FreeType(&library) != 0) {
3060 ERR("Can't init FreeType library\n");
3061 wine_dlclose(ft_handle, NULL, 0);
3062 ft_handle = NULL;
3063 return FALSE;
3065 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3067 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3068 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3069 ((FT_Version.minor << 8) & 0x00ff00) |
3070 ((FT_Version.patch ) & 0x0000ff);
3072 font_driver = &freetype_funcs;
3073 return TRUE;
3075 sym_not_found:
3076 WINE_MESSAGE(
3077 "Wine cannot find certain functions that it needs inside the FreeType\n"
3078 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3079 "FreeType to at least version 2.1.4.\n"
3080 "http://www.freetype.org\n");
3081 wine_dlclose(ft_handle, NULL, 0);
3082 ft_handle = NULL;
3083 return FALSE;
3086 static void init_font_list(void)
3088 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3089 static const WCHAR pathW[] = {'P','a','t','h',0};
3090 HKEY hkey;
3091 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3092 WCHAR windowsdir[MAX_PATH];
3093 char *unixname;
3094 const char *home;
3095 const char *data_dir;
3097 delete_external_font_keys();
3099 /* load the system bitmap fonts */
3100 load_system_fonts();
3102 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3103 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3104 strcatW(windowsdir, fontsW);
3105 if((unixname = wine_get_unix_file_name(windowsdir)))
3107 ReadFontDir(unixname, FALSE);
3108 HeapFree(GetProcessHeap(), 0, unixname);
3111 /* load the system truetype fonts */
3112 data_dir = wine_get_data_dir();
3113 if (!data_dir) data_dir = wine_get_build_dir();
3114 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3116 strcpy(unixname, data_dir);
3117 strcat(unixname, "/fonts/");
3118 ReadFontDir(unixname, TRUE);
3119 HeapFree(GetProcessHeap(), 0, unixname);
3122 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3123 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3124 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3125 will skip these. */
3126 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3127 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3128 &hkey) == ERROR_SUCCESS)
3130 LPWSTR data, valueW;
3131 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3132 &valuelen, &datalen, NULL, NULL);
3134 valuelen++; /* returned value doesn't include room for '\0' */
3135 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3136 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3137 if (valueW && data)
3139 dlen = datalen * sizeof(WCHAR);
3140 vlen = valuelen;
3141 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3142 &dlen) == ERROR_SUCCESS)
3144 if(data[0] && (data[1] == ':'))
3146 if((unixname = wine_get_unix_file_name(data)))
3148 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3149 HeapFree(GetProcessHeap(), 0, unixname);
3152 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3154 WCHAR pathW[MAX_PATH];
3155 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3156 BOOL added = FALSE;
3158 sprintfW(pathW, fmtW, windowsdir, data);
3159 if((unixname = wine_get_unix_file_name(pathW)))
3161 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3162 HeapFree(GetProcessHeap(), 0, unixname);
3164 if (!added)
3165 load_font_from_data_dir(data);
3167 /* reset dlen and vlen */
3168 dlen = datalen;
3169 vlen = valuelen;
3172 HeapFree(GetProcessHeap(), 0, data);
3173 HeapFree(GetProcessHeap(), 0, valueW);
3174 RegCloseKey(hkey);
3177 load_fontconfig_fonts();
3179 /* then look in any directories that we've specified in the config file */
3180 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3181 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3183 DWORD len;
3184 LPWSTR valueW;
3185 LPSTR valueA, ptr;
3187 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3189 len += sizeof(WCHAR);
3190 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3191 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3193 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3194 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3195 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3196 TRACE( "got font path %s\n", debugstr_a(valueA) );
3197 ptr = valueA;
3198 while (ptr)
3200 LPSTR next = strchr( ptr, ':' );
3201 if (next) *next++ = 0;
3202 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3203 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3205 strcpy( unixname, home );
3206 strcat( unixname, ptr + 1 );
3207 ReadFontDir( unixname, TRUE );
3208 HeapFree( GetProcessHeap(), 0, unixname );
3210 else
3211 ReadFontDir( ptr, TRUE );
3212 ptr = next;
3214 HeapFree( GetProcessHeap(), 0, valueA );
3216 HeapFree( GetProcessHeap(), 0, valueW );
3218 RegCloseKey(hkey);
3221 #ifdef __APPLE__
3222 /* Mac default font locations. */
3223 ReadFontDir( "/Library/Fonts", TRUE );
3224 ReadFontDir( "/Network/Library/Fonts", TRUE );
3225 ReadFontDir( "/System/Library/Fonts", TRUE );
3226 if ((home = getenv( "HOME" )))
3228 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3229 strcpy( unixname, home );
3230 strcat( unixname, "/Library/Fonts" );
3231 ReadFontDir( unixname, TRUE);
3232 HeapFree( GetProcessHeap(), 0, unixname );
3234 #endif
3237 static BOOL move_to_front(const WCHAR *name)
3239 Family *family, *cursor2;
3240 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3242 if(!strcmpiW(family->FamilyName, name))
3244 list_remove(&family->entry);
3245 list_add_head(&font_list, &family->entry);
3246 return TRUE;
3249 return FALSE;
3252 static BOOL set_default(const WCHAR **name_list)
3254 while (*name_list)
3256 if (move_to_front(*name_list)) return TRUE;
3257 name_list++;
3260 return FALSE;
3263 static void reorder_font_list(void)
3265 set_default( default_serif_list );
3266 set_default( default_fixed_list );
3267 set_default( default_sans_list );
3270 /*************************************************************
3271 * WineEngInit
3273 * Initialize FreeType library and create a list of available faces
3275 BOOL WineEngInit(void)
3277 HKEY hkey_font_cache;
3278 DWORD disposition;
3279 HANDLE font_mutex;
3281 /* update locale dependent font info in registry */
3282 update_font_info();
3284 if(!init_freetype()) return FALSE;
3286 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3288 ERR("Failed to create font mutex\n");
3289 return FALSE;
3291 WaitForSingleObject(font_mutex, INFINITE);
3293 create_font_cache_key(&hkey_font_cache, &disposition);
3295 if(disposition == REG_CREATED_NEW_KEY)
3296 init_font_list();
3297 else
3298 load_font_list_from_cache(hkey_font_cache);
3300 RegCloseKey(hkey_font_cache);
3302 reorder_font_list();
3304 DumpFontList();
3305 LoadSubstList();
3306 DumpSubstList();
3307 LoadReplaceList();
3309 if(disposition == REG_CREATED_NEW_KEY)
3310 update_reg_entries();
3312 init_system_links();
3314 ReleaseMutex(font_mutex);
3315 return TRUE;
3319 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3321 TT_OS2 *pOS2;
3322 TT_HoriHeader *pHori;
3324 LONG ppem;
3326 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3327 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3329 if(height == 0) height = 16;
3331 /* Calc. height of EM square:
3333 * For +ve lfHeight we have
3334 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3335 * Re-arranging gives:
3336 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3338 * For -ve lfHeight we have
3339 * |lfHeight| = ppem
3340 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3341 * with il = winAscent + winDescent - units_per_em]
3345 if(height > 0) {
3346 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3347 ppem = MulDiv(ft_face->units_per_EM, height,
3348 pHori->Ascender - pHori->Descender);
3349 else
3350 ppem = MulDiv(ft_face->units_per_EM, height,
3351 pOS2->usWinAscent + pOS2->usWinDescent);
3353 else
3354 ppem = -height;
3356 return ppem;
3359 static struct font_mapping *map_font_file( const char *name )
3361 struct font_mapping *mapping;
3362 struct stat st;
3363 int fd;
3365 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3366 if (fstat( fd, &st ) == -1) goto error;
3368 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3370 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3372 mapping->refcount++;
3373 close( fd );
3374 return mapping;
3377 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3378 goto error;
3380 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3381 close( fd );
3383 if (mapping->data == MAP_FAILED)
3385 HeapFree( GetProcessHeap(), 0, mapping );
3386 return NULL;
3388 mapping->refcount = 1;
3389 mapping->dev = st.st_dev;
3390 mapping->ino = st.st_ino;
3391 mapping->size = st.st_size;
3392 list_add_tail( &mappings_list, &mapping->entry );
3393 return mapping;
3395 error:
3396 close( fd );
3397 return NULL;
3400 static void unmap_font_file( struct font_mapping *mapping )
3402 if (!--mapping->refcount)
3404 list_remove( &mapping->entry );
3405 munmap( mapping->data, mapping->size );
3406 HeapFree( GetProcessHeap(), 0, mapping );
3410 static LONG load_VDMX(GdiFont*, LONG);
3412 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3414 FT_Error err;
3415 FT_Face ft_face;
3416 void *data_ptr;
3417 DWORD data_size;
3419 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3421 if (face->file)
3423 if (!(font->mapping = map_font_file( face->file )))
3425 WARN("failed to map %s\n", debugstr_a(face->file));
3426 return 0;
3428 data_ptr = font->mapping->data;
3429 data_size = font->mapping->size;
3431 else
3433 data_ptr = face->font_data_ptr;
3434 data_size = face->font_data_size;
3437 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3438 if(err) {
3439 ERR("FT_New_Face rets %d\n", err);
3440 return 0;
3443 /* set it here, as load_VDMX needs it */
3444 font->ft_face = ft_face;
3446 if(FT_IS_SCALABLE(ft_face)) {
3447 /* load the VDMX table if we have one */
3448 font->ppem = load_VDMX(font, height);
3449 if(font->ppem == 0)
3450 font->ppem = calc_ppem_for_height(ft_face, height);
3451 TRACE("height %d => ppem %d\n", height, font->ppem);
3453 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3454 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3455 } else {
3456 font->ppem = height;
3457 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3458 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3460 return ft_face;
3464 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3466 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3467 a single face with the requested charset. The idea is to check if
3468 the selected font supports the current ANSI codepage, if it does
3469 return the corresponding charset, else return the first charset */
3471 CHARSETINFO csi;
3472 int acp = GetACP(), i;
3473 DWORD fs0;
3475 *cp = acp;
3476 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3478 const SYSTEM_LINKS *font_link;
3480 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3481 return csi.ciCharset;
3483 font_link = find_font_link(family_name);
3484 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3485 return csi.ciCharset;
3488 for(i = 0; i < 32; i++) {
3489 fs0 = 1L << i;
3490 if(face->fs.fsCsb[0] & fs0) {
3491 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3492 *cp = csi.ciACP;
3493 return csi.ciCharset;
3495 else
3496 FIXME("TCI failing on %x\n", fs0);
3500 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3501 face->fs.fsCsb[0], face->file);
3502 *cp = acp;
3503 return DEFAULT_CHARSET;
3506 static GdiFont *alloc_font(void)
3508 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3509 ret->gmsize = 1;
3510 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3511 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3512 ret->potm = NULL;
3513 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3514 ret->total_kern_pairs = (DWORD)-1;
3515 ret->kern_pairs = NULL;
3516 list_init(&ret->hfontlist);
3517 list_init(&ret->child_fonts);
3518 return ret;
3521 static void free_font(GdiFont *font)
3523 struct list *cursor, *cursor2;
3524 DWORD i;
3526 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3528 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3529 list_remove(cursor);
3530 if(child->font)
3531 free_font(child->font);
3532 HeapFree(GetProcessHeap(), 0, child);
3535 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3537 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3538 DeleteObject(hfontlist->hfont);
3539 list_remove(&hfontlist->entry);
3540 HeapFree(GetProcessHeap(), 0, hfontlist);
3543 if (font->ft_face) pFT_Done_Face(font->ft_face);
3544 if (font->mapping) unmap_font_file( font->mapping );
3545 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3546 HeapFree(GetProcessHeap(), 0, font->potm);
3547 HeapFree(GetProcessHeap(), 0, font->name);
3548 for (i = 0; i < font->gmsize; i++)
3549 HeapFree(GetProcessHeap(),0,font->gm[i]);
3550 HeapFree(GetProcessHeap(), 0, font->gm);
3551 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3552 HeapFree(GetProcessHeap(), 0, font);
3556 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3558 FT_Face ft_face = font->ft_face;
3559 FT_ULong len;
3560 FT_Error err;
3562 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3564 if(!buf)
3565 len = 0;
3566 else
3567 len = cbData;
3569 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3571 /* make sure value of len is the value freetype says it needs */
3572 if (buf && len)
3574 FT_ULong needed = 0;
3575 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3576 if( !err && needed < len) len = needed;
3578 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3579 if (err)
3581 TRACE("Can't find table %c%c%c%c\n",
3582 /* bytes were reversed */
3583 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3584 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3585 return GDI_ERROR;
3587 return len;
3590 /*************************************************************
3591 * load_VDMX
3593 * load the vdmx entry for the specified height
3596 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3597 ( ( (FT_ULong)_x4 << 24 ) | \
3598 ( (FT_ULong)_x3 << 16 ) | \
3599 ( (FT_ULong)_x2 << 8 ) | \
3600 (FT_ULong)_x1 )
3602 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3604 typedef struct {
3605 BYTE bCharSet;
3606 BYTE xRatio;
3607 BYTE yStartRatio;
3608 BYTE yEndRatio;
3609 } Ratios;
3611 typedef struct {
3612 WORD recs;
3613 BYTE startsz;
3614 BYTE endsz;
3615 } VDMX_group;
3617 static LONG load_VDMX(GdiFont *font, LONG height)
3619 WORD hdr[3], tmp;
3620 VDMX_group group;
3621 BYTE devXRatio, devYRatio;
3622 USHORT numRecs, numRatios;
3623 DWORD result, offset = -1;
3624 LONG ppem = 0;
3625 int i;
3627 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3629 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3630 return ppem;
3632 /* FIXME: need the real device aspect ratio */
3633 devXRatio = 1;
3634 devYRatio = 1;
3636 numRecs = GET_BE_WORD(hdr[1]);
3637 numRatios = GET_BE_WORD(hdr[2]);
3639 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3640 for(i = 0; i < numRatios; i++) {
3641 Ratios ratio;
3643 offset = (3 * 2) + (i * sizeof(Ratios));
3644 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3645 offset = -1;
3647 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3649 if((ratio.xRatio == 0 &&
3650 ratio.yStartRatio == 0 &&
3651 ratio.yEndRatio == 0) ||
3652 (devXRatio == ratio.xRatio &&
3653 devYRatio >= ratio.yStartRatio &&
3654 devYRatio <= ratio.yEndRatio))
3656 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3657 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3658 offset = GET_BE_WORD(tmp);
3659 break;
3663 if(offset == -1) {
3664 FIXME("No suitable ratio found\n");
3665 return ppem;
3668 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3669 USHORT recs;
3670 BYTE startsz, endsz;
3671 WORD *vTable;
3673 recs = GET_BE_WORD(group.recs);
3674 startsz = group.startsz;
3675 endsz = group.endsz;
3677 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3679 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3680 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3681 if(result == GDI_ERROR) {
3682 FIXME("Failed to retrieve vTable\n");
3683 goto end;
3686 if(height > 0) {
3687 for(i = 0; i < recs; i++) {
3688 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3689 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3690 ppem = GET_BE_WORD(vTable[i * 3]);
3692 if(yMax + -yMin == height) {
3693 font->yMax = yMax;
3694 font->yMin = yMin;
3695 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3696 break;
3698 if(yMax + -yMin > height) {
3699 if(--i < 0) {
3700 ppem = 0;
3701 goto end; /* failed */
3703 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3704 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3705 ppem = GET_BE_WORD(vTable[i * 3]);
3706 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3707 break;
3710 if(!font->yMax) {
3711 ppem = 0;
3712 TRACE("ppem not found for height %d\n", height);
3715 end:
3716 HeapFree(GetProcessHeap(), 0, vTable);
3719 return ppem;
3722 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3724 if(font->font_desc.hash != fd->hash) return TRUE;
3725 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3726 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3727 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3728 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3731 static void calc_hash(FONT_DESC *pfd)
3733 DWORD hash = 0, *ptr, two_chars;
3734 WORD *pwc;
3735 unsigned int i;
3737 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3738 hash ^= *ptr;
3739 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3740 hash ^= *ptr;
3741 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3742 two_chars = *ptr;
3743 pwc = (WCHAR *)&two_chars;
3744 if(!*pwc) break;
3745 *pwc = toupperW(*pwc);
3746 pwc++;
3747 *pwc = toupperW(*pwc);
3748 hash ^= two_chars;
3749 if(!*pwc) break;
3751 hash ^= !pfd->can_use_bitmap;
3752 pfd->hash = hash;
3753 return;
3756 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3758 GdiFont *ret;
3759 FONT_DESC fd;
3760 HFONTLIST *hflist;
3761 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3763 fd.lf = *plf;
3764 fd.matrix = *pmat;
3765 fd.can_use_bitmap = can_use_bitmap;
3766 calc_hash(&fd);
3768 /* try the child list */
3769 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3770 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3771 if(!fontcmp(ret, &fd)) {
3772 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3773 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3774 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3775 if(hflist->hfont == hfont)
3776 return ret;
3781 /* try the in-use list */
3782 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3783 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3784 if(!fontcmp(ret, &fd)) {
3785 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3786 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3787 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3788 if(hflist->hfont == hfont)
3789 return ret;
3791 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3792 hflist->hfont = hfont;
3793 list_add_head(&ret->hfontlist, &hflist->entry);
3794 return ret;
3798 /* then the unused list */
3799 font_elem_ptr = list_head(&unused_gdi_font_list);
3800 while(font_elem_ptr) {
3801 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3802 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3803 if(!fontcmp(ret, &fd)) {
3804 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3805 assert(list_empty(&ret->hfontlist));
3806 TRACE("Found %p in unused list\n", ret);
3807 list_remove(&ret->entry);
3808 list_add_head(&gdi_font_list, &ret->entry);
3809 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3810 hflist->hfont = hfont;
3811 list_add_head(&ret->hfontlist, &hflist->entry);
3812 return ret;
3815 return NULL;
3818 static void add_to_cache(GdiFont *font)
3820 static DWORD cache_num = 1;
3822 font->cache_num = cache_num++;
3823 list_add_head(&gdi_font_list, &font->entry);
3826 /*************************************************************
3827 * create_child_font_list
3829 static BOOL create_child_font_list(GdiFont *font)
3831 BOOL ret = FALSE;
3832 SYSTEM_LINKS *font_link;
3833 CHILD_FONT *font_link_entry, *new_child;
3834 FontSubst *psub;
3835 WCHAR* font_name;
3837 psub = get_font_subst(&font_subst_list, font->name, -1);
3838 font_name = psub ? psub->to.name : font->name;
3839 font_link = find_font_link(font_name);
3840 if (font_link != NULL)
3842 TRACE("found entry in system list\n");
3843 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3845 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3846 new_child->face = font_link_entry->face;
3847 new_child->font = NULL;
3848 list_add_tail(&font->child_fonts, &new_child->entry);
3849 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3851 ret = TRUE;
3854 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3855 * Sans Serif. This is how asian windows get default fallbacks for fonts
3857 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3858 font->charset != OEM_CHARSET &&
3859 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3861 font_link = find_font_link(szDefaultFallbackLink);
3862 if (font_link != NULL)
3864 TRACE("found entry in default fallback list\n");
3865 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3867 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3868 new_child->face = font_link_entry->face;
3869 new_child->font = NULL;
3870 list_add_tail(&font->child_fonts, &new_child->entry);
3871 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3873 ret = TRUE;
3877 return ret;
3880 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3882 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3884 if (pFT_Set_Charmap)
3886 FT_Int i;
3887 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3889 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3891 for (i = 0; i < ft_face->num_charmaps; i++)
3893 if (ft_face->charmaps[i]->encoding == encoding)
3895 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3896 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3898 switch (ft_face->charmaps[i]->platform_id)
3900 default:
3901 cmap_def = ft_face->charmaps[i];
3902 break;
3903 case 0: /* Apple Unicode */
3904 cmap0 = ft_face->charmaps[i];
3905 break;
3906 case 1: /* Macintosh */
3907 cmap1 = ft_face->charmaps[i];
3908 break;
3909 case 2: /* ISO */
3910 cmap2 = ft_face->charmaps[i];
3911 break;
3912 case 3: /* Microsoft */
3913 cmap3 = ft_face->charmaps[i];
3914 break;
3918 if (cmap3) /* prefer Microsoft cmap table */
3919 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3920 else if (cmap1)
3921 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3922 else if (cmap2)
3923 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3924 else if (cmap0)
3925 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3926 else if (cmap_def)
3927 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3929 return ft_err == FT_Err_Ok;
3932 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3936 /*************************************************************
3937 * freetype_CreateDC
3939 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3940 LPCWSTR output, const DEVMODEW *devmode )
3942 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3944 if (!physdev) return FALSE;
3945 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3946 return TRUE;
3950 /*************************************************************
3951 * freetype_DeleteDC
3953 static BOOL freetype_DeleteDC( PHYSDEV dev )
3955 struct freetype_physdev *physdev = get_freetype_dev( dev );
3956 HeapFree( GetProcessHeap(), 0, physdev );
3957 return TRUE;
3961 /*************************************************************
3962 * freetype_SelectFont
3964 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3966 struct freetype_physdev *physdev = get_freetype_dev( dev );
3967 GdiFont *ret;
3968 Face *face, *best, *best_bitmap;
3969 Family *family, *last_resort_family;
3970 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
3971 INT height, width = 0;
3972 unsigned int score = 0, new_score;
3973 signed int diff = 0, newdiff;
3974 BOOL bd, it, can_use_bitmap, want_vertical;
3975 LOGFONTW lf;
3976 CHARSETINFO csi;
3977 HFONTLIST *hflist;
3978 FMAT2 dcmat;
3979 FontSubst *psub = NULL;
3980 DC *dc = get_dc_ptr( dev->hdc );
3981 const SYSTEM_LINKS *font_link;
3983 if (!hfont) /* notification that the font has been changed by another driver */
3985 dc->gdiFont = NULL;
3986 physdev->font = NULL;
3987 release_dc_ptr( dc );
3988 return 0;
3991 GetObjectW( hfont, sizeof(lf), &lf );
3992 lf.lfWidth = abs(lf.lfWidth);
3994 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3996 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3997 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3998 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3999 lf.lfEscapement);
4001 if(dc->GraphicsMode == GM_ADVANCED)
4003 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4004 /* Try to avoid not necessary glyph transformations */
4005 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4007 lf.lfHeight *= fabs(dcmat.eM11);
4008 lf.lfWidth *= fabs(dcmat.eM11);
4009 dcmat.eM11 = dcmat.eM22 = 1.0;
4012 else
4014 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4015 font scaling abilities. */
4016 dcmat.eM11 = dcmat.eM22 = 1.0;
4017 dcmat.eM21 = dcmat.eM12 = 0;
4018 if (dc->vport2WorldValid)
4020 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4021 lf.lfOrientation = -lf.lfOrientation;
4022 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4023 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4027 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4028 dcmat.eM21, dcmat.eM22);
4030 GDI_CheckNotLock();
4031 EnterCriticalSection( &freetype_cs );
4033 /* check the cache first */
4034 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4035 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4036 goto done;
4039 if(list_empty(&font_list)) /* No fonts installed */
4041 TRACE("No fonts installed\n");
4042 goto done;
4045 TRACE("not in cache\n");
4046 ret = alloc_font();
4048 ret->font_desc.matrix = dcmat;
4049 ret->font_desc.lf = lf;
4050 ret->font_desc.can_use_bitmap = can_use_bitmap;
4051 calc_hash(&ret->font_desc);
4052 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4053 hflist->hfont = hfont;
4054 list_add_head(&ret->hfontlist, &hflist->entry);
4056 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4057 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4058 original value lfCharSet. Note this is a special case for
4059 Symbol and doesn't happen at least for "Wingdings*" */
4061 if(!strcmpiW(lf.lfFaceName, SymbolW))
4062 lf.lfCharSet = SYMBOL_CHARSET;
4064 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4065 switch(lf.lfCharSet) {
4066 case DEFAULT_CHARSET:
4067 csi.fs.fsCsb[0] = 0;
4068 break;
4069 default:
4070 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4071 csi.fs.fsCsb[0] = 0;
4072 break;
4076 family = NULL;
4077 if(lf.lfFaceName[0] != '\0') {
4078 CHILD_FONT *font_link_entry;
4079 LPWSTR FaceName = lf.lfFaceName;
4081 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4083 if(psub) {
4084 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4085 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4086 if (psub->to.charset != -1)
4087 lf.lfCharSet = psub->to.charset;
4090 /* We want a match on name and charset or just name if
4091 charset was DEFAULT_CHARSET. If the latter then
4092 we fixup the returned charset later in get_nearest_charset
4093 where we'll either use the charset of the current ansi codepage
4094 or if that's unavailable the first charset that the font supports.
4096 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4097 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4098 if (!strcmpiW(family->FamilyName, FaceName) ||
4099 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4101 font_link = find_font_link(family->FamilyName);
4102 face_list = get_face_list_from_family(family);
4103 LIST_FOR_EACH(face_elem_ptr, face_list) {
4104 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4105 if (!(face->scalable || can_use_bitmap))
4106 continue;
4107 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4108 goto found;
4109 if (font_link != NULL &&
4110 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4111 goto found;
4112 if (!csi.fs.fsCsb[0])
4113 goto found;
4118 /* Search by full face name. */
4119 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4120 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4121 face_list = get_face_list_from_family(family);
4122 LIST_FOR_EACH(face_elem_ptr, face_list) {
4123 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4124 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4125 (face->scalable || can_use_bitmap))
4127 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4128 goto found_face;
4129 font_link = find_font_link(family->FamilyName);
4130 if (font_link != NULL &&
4131 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4132 goto found_face;
4138 * Try check the SystemLink list first for a replacement font.
4139 * We may find good replacements there.
4141 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4143 if(!strcmpiW(font_link->font_name, FaceName) ||
4144 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4146 TRACE("found entry in system list\n");
4147 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4149 const SYSTEM_LINKS *links;
4151 face = font_link_entry->face;
4152 if (!(face->scalable || can_use_bitmap))
4153 continue;
4154 family = face->family;
4155 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4156 goto found;
4157 links = find_font_link(family->FamilyName);
4158 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4159 goto found;
4165 psub = NULL; /* substitution is no more relevant */
4167 /* If requested charset was DEFAULT_CHARSET then try using charset
4168 corresponding to the current ansi codepage */
4169 if (!csi.fs.fsCsb[0])
4171 INT acp = GetACP();
4172 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4173 FIXME("TCI failed on codepage %d\n", acp);
4174 csi.fs.fsCsb[0] = 0;
4175 } else
4176 lf.lfCharSet = csi.ciCharset;
4179 want_vertical = (lf.lfFaceName[0] == '@');
4181 /* Face families are in the top 4 bits of lfPitchAndFamily,
4182 so mask with 0xF0 before testing */
4184 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4185 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4186 strcpyW(lf.lfFaceName, defFixed);
4187 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4188 strcpyW(lf.lfFaceName, defSerif);
4189 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4190 strcpyW(lf.lfFaceName, defSans);
4191 else
4192 strcpyW(lf.lfFaceName, defSans);
4193 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4194 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4195 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4196 font_link = find_font_link(family->FamilyName);
4197 face_list = get_face_list_from_family(family);
4198 LIST_FOR_EACH(face_elem_ptr, face_list) {
4199 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4200 if (!(face->scalable || can_use_bitmap))
4201 continue;
4202 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4203 goto found;
4204 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4205 goto found;
4210 last_resort_family = NULL;
4211 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4212 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4213 font_link = find_font_link(family->FamilyName);
4214 face_list = get_face_list_from_family(family);
4215 LIST_FOR_EACH(face_elem_ptr, face_list) {
4216 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4217 if(face->vertical == want_vertical &&
4218 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4219 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4220 if(face->scalable)
4221 goto found;
4222 if(can_use_bitmap && !last_resort_family)
4223 last_resort_family = family;
4228 if(last_resort_family) {
4229 family = last_resort_family;
4230 csi.fs.fsCsb[0] = 0;
4231 goto found;
4234 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4235 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4236 face_list = get_face_list_from_family(family);
4237 LIST_FOR_EACH(face_elem_ptr, face_list) {
4238 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4239 if(face->scalable && face->vertical == want_vertical) {
4240 csi.fs.fsCsb[0] = 0;
4241 WARN("just using first face for now\n");
4242 goto found;
4244 if(can_use_bitmap && !last_resort_family)
4245 last_resort_family = family;
4248 if(!last_resort_family) {
4249 FIXME("can't find a single appropriate font - bailing\n");
4250 free_font(ret);
4251 ret = NULL;
4252 goto done;
4255 WARN("could only find a bitmap font - this will probably look awful!\n");
4256 family = last_resort_family;
4257 csi.fs.fsCsb[0] = 0;
4259 found:
4260 it = lf.lfItalic ? 1 : 0;
4261 bd = lf.lfWeight > 550 ? 1 : 0;
4263 height = lf.lfHeight;
4265 face = best = best_bitmap = NULL;
4266 font_link = find_font_link(family->FamilyName);
4267 face_list = get_face_list_from_family(family);
4268 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4270 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4271 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4272 !csi.fs.fsCsb[0])
4274 BOOL italic, bold;
4276 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4277 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4278 new_score = (italic ^ it) + (bold ^ bd);
4279 if(!best || new_score <= score)
4281 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4282 italic, bold, it, bd);
4283 score = new_score;
4284 best = face;
4285 if(best->scalable && score == 0) break;
4286 if(!best->scalable)
4288 if(height > 0)
4289 newdiff = height - (signed int)(best->size.height);
4290 else
4291 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4292 if(!best_bitmap || new_score < score ||
4293 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4295 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4296 diff = newdiff;
4297 best_bitmap = best;
4298 if(score == 0 && diff == 0) break;
4304 if(best)
4305 face = best->scalable ? best : best_bitmap;
4306 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4307 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4309 found_face:
4310 height = lf.lfHeight;
4312 ret->fs = face->fs;
4314 if(csi.fs.fsCsb[0]) {
4315 ret->charset = lf.lfCharSet;
4316 ret->codepage = csi.ciACP;
4318 else
4319 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4321 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4322 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4324 ret->aveWidth = height ? lf.lfWidth : 0;
4326 if(!face->scalable) {
4327 /* Windows uses integer scaling factors for bitmap fonts */
4328 INT scale, scaled_height;
4329 GdiFont *cachedfont;
4331 /* FIXME: rotation of bitmap fonts is ignored */
4332 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4333 if (ret->aveWidth)
4334 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4335 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4336 dcmat.eM11 = dcmat.eM22 = 1.0;
4337 /* As we changed the matrix, we need to search the cache for the font again,
4338 * otherwise we might explode the cache. */
4339 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4340 TRACE("Found cached font after non-scalable matrix rescale!\n");
4341 free_font( ret );
4342 ret = cachedfont;
4343 goto done;
4345 calc_hash(&ret->font_desc);
4347 if (height != 0) height = diff;
4348 height += face->size.height;
4350 scale = (height + face->size.height - 1) / face->size.height;
4351 scaled_height = scale * face->size.height;
4352 /* Only jump to the next height if the difference <= 25% original height */
4353 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4354 /* The jump between unscaled and doubled is delayed by 1 */
4355 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4356 ret->scale_y = scale;
4358 width = face->size.x_ppem >> 6;
4359 height = face->size.y_ppem >> 6;
4361 else
4362 ret->scale_y = 1.0;
4363 TRACE("font scale y: %f\n", ret->scale_y);
4365 ret->ft_face = OpenFontFace(ret, face, width, height);
4367 if (!ret->ft_face)
4369 free_font( ret );
4370 ret = NULL;
4371 goto done;
4374 ret->ntmFlags = face->ntmFlags;
4376 if (ret->charset == SYMBOL_CHARSET &&
4377 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4378 /* No ops */
4380 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4381 /* No ops */
4383 else {
4384 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4387 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4388 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4389 ret->underline = lf.lfUnderline ? 0xff : 0;
4390 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4391 create_child_font_list(ret);
4393 if (face->vertical) /* We need to try to load the GSUB table */
4395 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4396 if (length != GDI_ERROR)
4398 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4399 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4400 TRACE("Loaded GSUB table of %i bytes\n",length);
4404 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4406 add_to_cache(ret);
4407 done:
4408 if (ret)
4410 dc->gdiFont = ret;
4411 physdev->font = ret;
4413 LeaveCriticalSection( &freetype_cs );
4414 release_dc_ptr( dc );
4415 return ret ? hfont : 0;
4418 static void dump_gdi_font_list(void)
4420 GdiFont *gdiFont;
4421 struct list *elem_ptr;
4423 TRACE("---------- gdiFont Cache ----------\n");
4424 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4425 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4426 TRACE("gdiFont=%p %s %d\n",
4427 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4430 TRACE("---------- Unused gdiFont Cache ----------\n");
4431 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4432 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4433 TRACE("gdiFont=%p %s %d\n",
4434 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4437 TRACE("---------- Child gdiFont Cache ----------\n");
4438 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4439 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4440 TRACE("gdiFont=%p %s %d\n",
4441 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4445 /*************************************************************
4446 * WineEngDestroyFontInstance
4448 * free the gdiFont associated with this handle
4451 BOOL WineEngDestroyFontInstance(HFONT handle)
4453 GdiFont *gdiFont;
4454 HFONTLIST *hflist;
4455 BOOL ret = FALSE;
4456 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4457 int i = 0;
4459 GDI_CheckNotLock();
4460 EnterCriticalSection( &freetype_cs );
4462 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4464 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4465 while(hfontlist_elem_ptr) {
4466 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4467 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4468 if(hflist->hfont == handle) {
4469 TRACE("removing child font %p from child list\n", gdiFont);
4470 list_remove(&gdiFont->entry);
4471 LeaveCriticalSection( &freetype_cs );
4472 return TRUE;
4477 TRACE("destroying hfont=%p\n", handle);
4478 if(TRACE_ON(font))
4479 dump_gdi_font_list();
4481 font_elem_ptr = list_head(&gdi_font_list);
4482 while(font_elem_ptr) {
4483 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4484 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4486 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4487 while(hfontlist_elem_ptr) {
4488 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4489 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4490 if(hflist->hfont == handle) {
4491 list_remove(&hflist->entry);
4492 HeapFree(GetProcessHeap(), 0, hflist);
4493 ret = TRUE;
4496 if(list_empty(&gdiFont->hfontlist)) {
4497 TRACE("Moving to Unused list\n");
4498 list_remove(&gdiFont->entry);
4499 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4504 font_elem_ptr = list_head(&unused_gdi_font_list);
4505 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4506 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4507 while(font_elem_ptr) {
4508 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4509 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4510 TRACE("freeing %p\n", gdiFont);
4511 list_remove(&gdiFont->entry);
4512 free_font(gdiFont);
4514 LeaveCriticalSection( &freetype_cs );
4515 return ret;
4518 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4520 HRSRC rsrc;
4521 HGLOBAL hMem;
4522 WCHAR *p;
4523 int i;
4525 id += IDS_FIRST_SCRIPT;
4526 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4527 if (!rsrc) return 0;
4528 hMem = LoadResource( gdi32_module, rsrc );
4529 if (!hMem) return 0;
4531 p = LockResource( hMem );
4532 id &= 0x000f;
4533 while (id--) p += *p + 1;
4535 i = min(LF_FACESIZE - 1, *p);
4536 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4537 buffer[i] = 0;
4538 return i;
4542 /***************************************************
4543 * create_enum_charset_list
4545 * This function creates charset enumeration list because in DEFAULT_CHARSET
4546 * case, the ANSI codepage's charset takes precedence over other charsets.
4547 * This function works as a filter other than DEFAULT_CHARSET case.
4549 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4551 CHARSETINFO csi;
4552 DWORD n = 0;
4554 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4555 csi.fs.fsCsb[0] != 0) {
4556 list->element[n].mask = csi.fs.fsCsb[0];
4557 list->element[n].charset = csi.ciCharset;
4558 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4559 n++;
4561 else { /* charset is DEFAULT_CHARSET or invalid. */
4562 INT acp, i;
4564 /* Set the current codepage's charset as the first element. */
4565 acp = GetACP();
4566 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4567 csi.fs.fsCsb[0] != 0) {
4568 list->element[n].mask = csi.fs.fsCsb[0];
4569 list->element[n].charset = csi.ciCharset;
4570 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4571 n++;
4574 /* Fill out left elements. */
4575 for (i = 0; i < 32; i++) {
4576 FONTSIGNATURE fs;
4577 fs.fsCsb[0] = 1L << i;
4578 fs.fsCsb[1] = 0;
4579 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4580 continue; /* skip, already added. */
4581 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4582 continue; /* skip, this is an invalid fsCsb bit. */
4584 list->element[n].mask = fs.fsCsb[0];
4585 list->element[n].charset = csi.ciCharset;
4586 load_script_name( i, list->element[n].name );
4587 n++;
4590 list->total = n;
4592 return n;
4595 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4596 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4598 GdiFont *font;
4599 LONG width, height;
4601 if (face->cached_enum_data)
4603 TRACE("Cached\n");
4604 *pelf = face->cached_enum_data->elf;
4605 *pntm = face->cached_enum_data->ntm;
4606 *ptype = face->cached_enum_data->type;
4607 return;
4610 font = alloc_font();
4612 if(face->scalable) {
4613 height = -2048; /* 2048 is the most common em size */
4614 width = 0;
4615 } else {
4616 height = face->size.y_ppem >> 6;
4617 width = face->size.x_ppem >> 6;
4619 font->scale_y = 1.0;
4621 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4623 free_font(font);
4624 return;
4627 font->name = strdupW(face->family->FamilyName);
4628 font->ntmFlags = face->ntmFlags;
4630 if (get_outline_text_metrics(font))
4632 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4634 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4636 lstrcpynW(pelf->elfLogFont.lfFaceName,
4637 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4638 LF_FACESIZE);
4639 lstrcpynW(pelf->elfFullName,
4640 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4641 LF_FULLFACESIZE);
4642 lstrcpynW(pelf->elfStyle,
4643 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4644 LF_FACESIZE);
4646 else
4648 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4650 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4652 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4653 if (face->FullName)
4654 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4655 else
4656 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4657 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4660 pntm->ntmTm.ntmFlags = face->ntmFlags;
4661 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4662 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4663 pntm->ntmFontSig = face->fs;
4665 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4667 pelf->elfLogFont.lfEscapement = 0;
4668 pelf->elfLogFont.lfOrientation = 0;
4669 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4670 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4671 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4672 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4673 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4674 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4675 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4676 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4677 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4678 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4679 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4681 *ptype = 0;
4682 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4683 *ptype |= TRUETYPE_FONTTYPE;
4684 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4685 *ptype |= DEVICE_FONTTYPE;
4686 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4687 *ptype |= RASTER_FONTTYPE;
4689 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4690 if (face->cached_enum_data)
4692 face->cached_enum_data->elf = *pelf;
4693 face->cached_enum_data->ntm = *pntm;
4694 face->cached_enum_data->type = *ptype;
4697 free_font(font);
4700 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
4702 static const WCHAR spaceW[] = { ' ', 0 };
4704 strcpyW(full_name, family_name);
4705 strcatW(full_name, spaceW);
4706 strcatW(full_name, style_name);
4709 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4711 const struct list *face_list, *face_elem_ptr;
4713 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4715 face_list = get_face_list_from_family(family);
4716 LIST_FOR_EACH(face_elem_ptr, face_list)
4718 WCHAR full_family_name[LF_FULLFACESIZE];
4719 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4721 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4723 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4724 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4725 continue;
4728 create_full_name(full_family_name, family->FamilyName, face->StyleName);
4729 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4732 return FALSE;
4735 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
4737 WCHAR full_family_name[LF_FULLFACESIZE];
4739 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
4741 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4743 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4744 debugstr_w(family_name), debugstr_w(face->StyleName));
4745 return FALSE;
4748 create_full_name(full_family_name, family_name, face->StyleName);
4749 return !strcmpiW(lf->lfFaceName, full_family_name);
4752 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
4753 FONTENUMPROCW proc, LPARAM lparam)
4755 ENUMLOGFONTEXW elf;
4756 NEWTEXTMETRICEXW ntm;
4757 DWORD type = 0;
4758 int i;
4760 GetEnumStructs(face, &elf, &ntm, &type);
4761 for(i = 0; i < list->total; i++) {
4762 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4763 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4764 load_script_name( IDS_OEM_DOS, elf.elfScript );
4765 i = list->total; /* break out of loop after enumeration */
4766 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4767 continue;
4768 else {
4769 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4770 strcpyW(elf.elfScript, list->element[i].name);
4771 if (!elf.elfScript[0])
4772 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4774 /* Font Replacement */
4775 if (family != face->family)
4777 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
4778 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
4780 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4781 debugstr_w(elf.elfLogFont.lfFaceName),
4782 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4783 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4784 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4785 ntm.ntmTm.ntmFlags);
4786 /* release section before callback (FIXME) */
4787 LeaveCriticalSection( &freetype_cs );
4788 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4789 EnterCriticalSection( &freetype_cs );
4791 return TRUE;
4794 /*************************************************************
4795 * freetype_EnumFonts
4797 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4799 Family *family;
4800 Face *face;
4801 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4802 LOGFONTW lf;
4803 struct enum_charset_list enum_charsets;
4805 if (!plf)
4807 lf.lfCharSet = DEFAULT_CHARSET;
4808 lf.lfPitchAndFamily = 0;
4809 lf.lfFaceName[0] = 0;
4810 plf = &lf;
4813 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4815 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4817 GDI_CheckNotLock();
4818 EnterCriticalSection( &freetype_cs );
4819 if(plf->lfFaceName[0]) {
4820 FontSubst *psub;
4821 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4823 if(psub) {
4824 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4825 debugstr_w(psub->to.name));
4826 lf = *plf;
4827 strcpyW(lf.lfFaceName, psub->to.name);
4828 plf = &lf;
4831 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4832 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4833 if(family_matches(family, plf)) {
4834 face_list = get_face_list_from_family(family);
4835 LIST_FOR_EACH(face_elem_ptr, face_list) {
4836 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4837 if (!face_matches(family->FamilyName, face, plf)) continue;
4838 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4842 } else {
4843 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4844 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4845 face_list = get_face_list_from_family(family);
4846 face_elem_ptr = list_head(face_list);
4847 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4848 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4851 LeaveCriticalSection( &freetype_cs );
4852 return TRUE;
4855 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4857 pt->x.value = vec->x >> 6;
4858 pt->x.fract = (vec->x & 0x3f) << 10;
4859 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4860 pt->y.value = vec->y >> 6;
4861 pt->y.fract = (vec->y & 0x3f) << 10;
4862 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4863 return;
4866 /***************************************************
4867 * According to the MSDN documentation on WideCharToMultiByte,
4868 * certain codepages cannot set the default_used parameter.
4869 * This returns TRUE if the codepage can set that parameter, false else
4870 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4872 static BOOL codepage_sets_default_used(UINT codepage)
4874 switch (codepage)
4876 case CP_UTF7:
4877 case CP_UTF8:
4878 case CP_SYMBOL:
4879 return FALSE;
4880 default:
4881 return TRUE;
4886 * GSUB Table handling functions
4889 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4891 const GSUB_CoverageFormat1* cf1;
4893 cf1 = table;
4895 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4897 int count = GET_BE_WORD(cf1->GlyphCount);
4898 int i;
4899 TRACE("Coverage Format 1, %i glyphs\n",count);
4900 for (i = 0; i < count; i++)
4901 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4902 return i;
4903 return -1;
4905 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4907 const GSUB_CoverageFormat2* cf2;
4908 int i;
4909 int count;
4910 cf2 = (const GSUB_CoverageFormat2*)cf1;
4912 count = GET_BE_WORD(cf2->RangeCount);
4913 TRACE("Coverage Format 2, %i ranges\n",count);
4914 for (i = 0; i < count; i++)
4916 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4917 return -1;
4918 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4919 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4921 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4922 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4925 return -1;
4927 else
4928 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4930 return -1;
4933 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4935 const GSUB_ScriptList *script;
4936 const GSUB_Script *deflt = NULL;
4937 int i;
4938 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4940 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4941 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4943 const GSUB_Script *scr;
4944 int offset;
4946 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4947 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4949 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4950 return scr;
4951 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4952 deflt = scr;
4954 return deflt;
4957 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4959 int i;
4960 int offset;
4961 const GSUB_LangSys *Lang;
4963 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4965 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4967 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4968 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4970 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4971 return Lang;
4973 offset = GET_BE_WORD(script->DefaultLangSys);
4974 if (offset)
4976 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4977 return Lang;
4979 return NULL;
4982 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4984 int i;
4985 const GSUB_FeatureList *feature;
4986 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4988 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4989 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4991 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4992 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4994 const GSUB_Feature *feat;
4995 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4996 return feat;
4999 return NULL;
5002 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5004 int i;
5005 int offset;
5006 const GSUB_LookupList *lookup;
5007 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5009 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5010 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5012 const GSUB_LookupTable *look;
5013 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5014 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5015 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5016 if (GET_BE_WORD(look->LookupType) != 1)
5017 FIXME("We only handle SubType 1\n");
5018 else
5020 int j;
5022 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5024 const GSUB_SingleSubstFormat1 *ssf1;
5025 offset = GET_BE_WORD(look->SubTable[j]);
5026 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5027 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5029 int offset = GET_BE_WORD(ssf1->Coverage);
5030 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5031 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5033 TRACE(" Glyph 0x%x ->",glyph);
5034 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5035 TRACE(" 0x%x\n",glyph);
5038 else
5040 const GSUB_SingleSubstFormat2 *ssf2;
5041 INT index;
5042 INT offset;
5044 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5045 offset = GET_BE_WORD(ssf1->Coverage);
5046 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5047 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5048 TRACE(" Coverage index %i\n",index);
5049 if (index != -1)
5051 TRACE(" Glyph is 0x%x ->",glyph);
5052 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5053 TRACE("0x%x\n",glyph);
5059 return glyph;
5062 static const char* get_opentype_script(const GdiFont *font)
5065 * I am not sure if this is the correct way to generate our script tag
5068 switch (font->charset)
5070 case ANSI_CHARSET: return "latn";
5071 case BALTIC_CHARSET: return "latn"; /* ?? */
5072 case CHINESEBIG5_CHARSET: return "hani";
5073 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5074 case GB2312_CHARSET: return "hani";
5075 case GREEK_CHARSET: return "grek";
5076 case HANGUL_CHARSET: return "hang";
5077 case RUSSIAN_CHARSET: return "cyrl";
5078 case SHIFTJIS_CHARSET: return "kana";
5079 case TURKISH_CHARSET: return "latn"; /* ?? */
5080 case VIETNAMESE_CHARSET: return "latn";
5081 case JOHAB_CHARSET: return "latn"; /* ?? */
5082 case ARABIC_CHARSET: return "arab";
5083 case HEBREW_CHARSET: return "hebr";
5084 case THAI_CHARSET: return "thai";
5085 default: return "latn";
5089 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5091 const GSUB_Header *header;
5092 const GSUB_Script *script;
5093 const GSUB_LangSys *language;
5094 const GSUB_Feature *feature;
5096 if (!font->GSUB_Table)
5097 return glyph;
5099 header = font->GSUB_Table;
5101 script = GSUB_get_script_table(header, get_opentype_script(font));
5102 if (!script)
5104 TRACE("Script not found\n");
5105 return glyph;
5107 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5108 if (!language)
5110 TRACE("Language not found\n");
5111 return glyph;
5113 feature = GSUB_get_feature(header, language, "vrt2");
5114 if (!feature)
5115 feature = GSUB_get_feature(header, language, "vert");
5116 if (!feature)
5118 TRACE("vrt2/vert feature not found\n");
5119 return glyph;
5121 return GSUB_apply_feature(header, feature, glyph);
5124 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5126 FT_UInt glyphId;
5128 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5129 WCHAR wc = (WCHAR)glyph;
5130 BOOL default_used;
5131 BOOL *default_used_pointer;
5132 FT_UInt ret;
5133 char buf;
5134 default_used_pointer = NULL;
5135 default_used = FALSE;
5136 if (codepage_sets_default_used(font->codepage))
5137 default_used_pointer = &default_used;
5138 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5139 ret = 0;
5140 else
5141 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5142 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5143 return ret;
5146 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5148 if (glyph < 0x100) glyph += 0xf000;
5149 /* there is a number of old pre-Unicode "broken" TTFs, which
5150 do have symbols at U+00XX instead of U+f0XX */
5151 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5152 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5154 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5156 return glyphId;
5159 /*************************************************************
5160 * freetype_GetGlyphIndices
5162 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5164 struct freetype_physdev *physdev = get_freetype_dev( dev );
5165 int i;
5166 WORD default_char;
5167 BOOL got_default = FALSE;
5169 if (!physdev->font)
5171 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5172 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5175 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5177 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5178 got_default = TRUE;
5181 GDI_CheckNotLock();
5182 EnterCriticalSection( &freetype_cs );
5184 for(i = 0; i < count; i++)
5186 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5187 if (pgi[i] == 0)
5189 if (!got_default)
5191 if (FT_IS_SFNT(physdev->font->ft_face))
5193 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5194 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5196 else
5198 TEXTMETRICW textm;
5199 get_text_metrics(physdev->font, &textm);
5200 default_char = textm.tmDefaultChar;
5202 got_default = TRUE;
5204 pgi[i] = default_char;
5207 LeaveCriticalSection( &freetype_cs );
5208 return count;
5211 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5213 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5214 return !memcmp(matrix, &identity, sizeof(FMAT2));
5217 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5219 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5220 return !memcmp(matrix, &identity, sizeof(MAT2));
5223 static inline BYTE get_max_level( UINT format )
5225 switch( format )
5227 case GGO_GRAY2_BITMAP: return 4;
5228 case GGO_GRAY4_BITMAP: return 16;
5229 case GGO_GRAY8_BITMAP: return 64;
5231 return 255;
5234 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5236 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5237 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5238 const MAT2* lpmat)
5240 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5241 FT_Face ft_face = incoming_font->ft_face;
5242 GdiFont *font = incoming_font;
5243 FT_UInt glyph_index;
5244 DWORD width, height, pitch, needed = 0;
5245 FT_Bitmap ft_bitmap;
5246 FT_Error err;
5247 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5248 FT_Angle angle = 0;
5249 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5250 double widthRatio = 1.0;
5251 FT_Matrix transMat = identityMat;
5252 FT_Matrix transMatUnrotated;
5253 BOOL needsTransform = FALSE;
5254 BOOL tategaki = (font->GSUB_Table != NULL);
5255 UINT original_index;
5257 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5258 buflen, buf, lpmat);
5260 TRACE("font transform %f %f %f %f\n",
5261 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5262 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5264 if(format & GGO_GLYPH_INDEX) {
5265 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5266 original_index = glyph;
5267 format &= ~GGO_GLYPH_INDEX;
5268 } else {
5269 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5270 ft_face = font->ft_face;
5271 original_index = glyph_index;
5274 if(format & GGO_UNHINTED) {
5275 load_flags |= FT_LOAD_NO_HINTING;
5276 format &= ~GGO_UNHINTED;
5279 /* tategaki never appears to happen to lower glyph index */
5280 if (glyph_index < TATEGAKI_LOWER_BOUND )
5281 tategaki = FALSE;
5283 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5284 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5285 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5286 font->gmsize * sizeof(GM*));
5287 } else {
5288 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5289 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5291 *lpgm = FONT_GM(font,original_index)->gm;
5292 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5293 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5294 lpgm->gmCellIncX, lpgm->gmCellIncY);
5295 return 1; /* FIXME */
5299 if (!font->gm[original_index / GM_BLOCK_SIZE])
5300 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5302 /* Scaling factor */
5303 if (font->aveWidth)
5305 TEXTMETRICW tm;
5307 get_text_metrics(font, &tm);
5309 widthRatio = (double)font->aveWidth;
5310 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5312 else
5313 widthRatio = font->scale_y;
5315 /* Scaling transform */
5316 if (widthRatio != 1.0 || font->scale_y != 1.0)
5318 FT_Matrix scaleMat;
5319 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5320 scaleMat.xy = 0;
5321 scaleMat.yx = 0;
5322 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5324 pFT_Matrix_Multiply(&scaleMat, &transMat);
5325 needsTransform = TRUE;
5328 /* Slant transform */
5329 if (font->fake_italic) {
5330 FT_Matrix slantMat;
5332 slantMat.xx = (1 << 16);
5333 slantMat.xy = ((1 << 16) >> 2);
5334 slantMat.yx = 0;
5335 slantMat.yy = (1 << 16);
5336 pFT_Matrix_Multiply(&slantMat, &transMat);
5337 needsTransform = TRUE;
5340 /* Rotation transform */
5341 transMatUnrotated = transMat;
5342 if(font->orientation && !tategaki) {
5343 FT_Matrix rotationMat;
5344 FT_Vector vecAngle;
5345 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5346 pFT_Vector_Unit(&vecAngle, angle);
5347 rotationMat.xx = vecAngle.x;
5348 rotationMat.xy = -vecAngle.y;
5349 rotationMat.yx = -rotationMat.xy;
5350 rotationMat.yy = rotationMat.xx;
5352 pFT_Matrix_Multiply(&rotationMat, &transMat);
5353 needsTransform = TRUE;
5356 /* World transform */
5357 if (!is_identity_FMAT2(&font->font_desc.matrix))
5359 FT_Matrix worldMat;
5360 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5361 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5362 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5363 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5364 pFT_Matrix_Multiply(&worldMat, &transMat);
5365 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5366 needsTransform = TRUE;
5369 /* Extra transformation specified by caller */
5370 if (!is_identity_MAT2(lpmat))
5372 FT_Matrix extraMat;
5373 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5374 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5375 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5376 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5377 pFT_Matrix_Multiply(&extraMat, &transMat);
5378 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5379 needsTransform = TRUE;
5382 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5383 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5384 format == GGO_GRAY8_BITMAP))
5386 load_flags |= FT_LOAD_NO_BITMAP;
5389 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5391 if(err) {
5392 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5393 return GDI_ERROR;
5396 if(!needsTransform) {
5397 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5398 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5399 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5401 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5402 bottom = (ft_face->glyph->metrics.horiBearingY -
5403 ft_face->glyph->metrics.height) & -64;
5404 lpgm->gmCellIncX = adv;
5405 lpgm->gmCellIncY = 0;
5406 } else {
5407 INT xc, yc;
5408 FT_Vector vec;
5410 left = right = 0;
5412 for(xc = 0; xc < 2; xc++) {
5413 for(yc = 0; yc < 2; yc++) {
5414 vec.x = (ft_face->glyph->metrics.horiBearingX +
5415 xc * ft_face->glyph->metrics.width);
5416 vec.y = ft_face->glyph->metrics.horiBearingY -
5417 yc * ft_face->glyph->metrics.height;
5418 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5419 pFT_Vector_Transform(&vec, &transMat);
5420 if(xc == 0 && yc == 0) {
5421 left = right = vec.x;
5422 top = bottom = vec.y;
5423 } else {
5424 if(vec.x < left) left = vec.x;
5425 else if(vec.x > right) right = vec.x;
5426 if(vec.y < bottom) bottom = vec.y;
5427 else if(vec.y > top) top = vec.y;
5431 left = left & -64;
5432 right = (right + 63) & -64;
5433 bottom = bottom & -64;
5434 top = (top + 63) & -64;
5436 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5437 vec.x = ft_face->glyph->metrics.horiAdvance;
5438 vec.y = 0;
5439 pFT_Vector_Transform(&vec, &transMat);
5440 lpgm->gmCellIncX = (vec.x+63) >> 6;
5441 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5443 vec.x = ft_face->glyph->metrics.horiAdvance;
5444 vec.y = 0;
5445 pFT_Vector_Transform(&vec, &transMatUnrotated);
5446 adv = (vec.x+63) >> 6;
5449 lsb = left >> 6;
5450 bbx = (right - left) >> 6;
5451 lpgm->gmBlackBoxX = (right - left) >> 6;
5452 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5453 lpgm->gmptGlyphOrigin.x = left >> 6;
5454 lpgm->gmptGlyphOrigin.y = top >> 6;
5456 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5457 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5458 lpgm->gmCellIncX, lpgm->gmCellIncY);
5460 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5461 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5463 FONT_GM(font,original_index)->gm = *lpgm;
5464 FONT_GM(font,original_index)->adv = adv;
5465 FONT_GM(font,original_index)->lsb = lsb;
5466 FONT_GM(font,original_index)->bbx = bbx;
5467 FONT_GM(font,original_index)->init = TRUE;
5470 if(format == GGO_METRICS)
5472 return 1; /* FIXME */
5475 if(ft_face->glyph->format != ft_glyph_format_outline &&
5476 (format == GGO_NATIVE || format == GGO_BEZIER))
5478 TRACE("loaded a bitmap\n");
5479 return GDI_ERROR;
5482 switch(format) {
5483 case GGO_BITMAP:
5484 width = lpgm->gmBlackBoxX;
5485 height = lpgm->gmBlackBoxY;
5486 pitch = ((width + 31) >> 5) << 2;
5487 needed = pitch * height;
5489 if(!buf || !buflen) break;
5491 switch(ft_face->glyph->format) {
5492 case ft_glyph_format_bitmap:
5494 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5495 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5496 INT h = ft_face->glyph->bitmap.rows;
5497 while(h--) {
5498 memcpy(dst, src, w);
5499 src += ft_face->glyph->bitmap.pitch;
5500 dst += pitch;
5502 break;
5505 case ft_glyph_format_outline:
5506 ft_bitmap.width = width;
5507 ft_bitmap.rows = height;
5508 ft_bitmap.pitch = pitch;
5509 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5510 ft_bitmap.buffer = buf;
5512 if(needsTransform)
5513 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5515 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5517 /* Note: FreeType will only set 'black' bits for us. */
5518 memset(buf, 0, needed);
5519 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5520 break;
5522 default:
5523 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5524 return GDI_ERROR;
5526 break;
5528 case GGO_GRAY2_BITMAP:
5529 case GGO_GRAY4_BITMAP:
5530 case GGO_GRAY8_BITMAP:
5531 case WINE_GGO_GRAY16_BITMAP:
5533 unsigned int max_level, row, col;
5534 BYTE *start, *ptr;
5536 width = lpgm->gmBlackBoxX;
5537 height = lpgm->gmBlackBoxY;
5538 pitch = (width + 3) / 4 * 4;
5539 needed = pitch * height;
5541 if(!buf || !buflen) break;
5543 max_level = get_max_level( format );
5545 switch(ft_face->glyph->format) {
5546 case ft_glyph_format_bitmap:
5548 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5549 INT h = ft_face->glyph->bitmap.rows;
5550 INT x;
5551 memset( buf, 0, needed );
5552 while(h--) {
5553 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5554 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5555 src += ft_face->glyph->bitmap.pitch;
5556 dst += pitch;
5558 return needed;
5560 case ft_glyph_format_outline:
5562 ft_bitmap.width = width;
5563 ft_bitmap.rows = height;
5564 ft_bitmap.pitch = pitch;
5565 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5566 ft_bitmap.buffer = buf;
5568 if(needsTransform)
5569 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5571 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5573 memset(ft_bitmap.buffer, 0, buflen);
5575 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5577 if (max_level != 255)
5579 for (row = 0, start = buf; row < height; row++)
5581 for (col = 0, ptr = start; col < width; col++, ptr++)
5582 *ptr = (((int)*ptr) * max_level + 128) / 256;
5583 start += pitch;
5586 return needed;
5589 default:
5590 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5591 return GDI_ERROR;
5593 break;
5596 case WINE_GGO_HRGB_BITMAP:
5597 case WINE_GGO_HBGR_BITMAP:
5598 case WINE_GGO_VRGB_BITMAP:
5599 case WINE_GGO_VBGR_BITMAP:
5600 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5602 switch (ft_face->glyph->format)
5604 case FT_GLYPH_FORMAT_BITMAP:
5606 BYTE *src, *dst;
5607 INT src_pitch, x;
5609 width = lpgm->gmBlackBoxX;
5610 height = lpgm->gmBlackBoxY;
5611 pitch = width * 4;
5612 needed = pitch * height;
5614 if (!buf || !buflen) break;
5616 memset(buf, 0, buflen);
5617 dst = buf;
5618 src = ft_face->glyph->bitmap.buffer;
5619 src_pitch = ft_face->glyph->bitmap.pitch;
5621 height = min( height, ft_face->glyph->bitmap.rows );
5622 while ( height-- )
5624 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5626 if ( src[x / 8] & masks[x % 8] )
5627 ((unsigned int *)dst)[x] = ~0u;
5629 src += src_pitch;
5630 dst += pitch;
5633 break;
5636 case FT_GLYPH_FORMAT_OUTLINE:
5638 unsigned int *dst;
5639 BYTE *src;
5640 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5641 INT x_shift, y_shift;
5642 BOOL rgb;
5643 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5644 FT_Render_Mode render_mode =
5645 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5646 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5648 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5650 if ( render_mode == FT_RENDER_MODE_LCD)
5652 lpgm->gmBlackBoxX += 2;
5653 lpgm->gmptGlyphOrigin.x -= 1;
5655 else
5657 lpgm->gmBlackBoxY += 2;
5658 lpgm->gmptGlyphOrigin.y += 1;
5662 width = lpgm->gmBlackBoxX;
5663 height = lpgm->gmBlackBoxY;
5664 pitch = width * 4;
5665 needed = pitch * height;
5667 if (!buf || !buflen) break;
5669 memset(buf, 0, buflen);
5670 dst = buf;
5671 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5673 if ( needsTransform )
5674 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5676 if ( pFT_Library_SetLcdFilter )
5677 pFT_Library_SetLcdFilter( library, lcdfilter );
5678 pFT_Render_Glyph (ft_face->glyph, render_mode);
5680 src = ft_face->glyph->bitmap.buffer;
5681 src_pitch = ft_face->glyph->bitmap.pitch;
5682 src_width = ft_face->glyph->bitmap.width;
5683 src_height = ft_face->glyph->bitmap.rows;
5685 if ( render_mode == FT_RENDER_MODE_LCD)
5687 rgb_interval = 1;
5688 hmul = 3;
5689 vmul = 1;
5691 else
5693 rgb_interval = src_pitch;
5694 hmul = 1;
5695 vmul = 3;
5698 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5699 if ( x_shift < 0 ) x_shift = 0;
5700 if ( x_shift + (src_width / hmul) > width )
5701 x_shift = width - (src_width / hmul);
5703 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5704 if ( y_shift < 0 ) y_shift = 0;
5705 if ( y_shift + (src_height / vmul) > height )
5706 y_shift = height - (src_height / vmul);
5708 dst += x_shift + y_shift * ( pitch / 4 );
5709 while ( src_height )
5711 for ( x = 0; x < src_width / hmul; x++ )
5713 if ( rgb )
5715 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5716 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5717 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5718 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5720 else
5722 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5723 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5724 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5725 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5728 src += src_pitch * vmul;
5729 dst += pitch / 4;
5730 src_height -= vmul;
5733 break;
5736 default:
5737 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5738 return GDI_ERROR;
5741 break;
5743 #else
5744 return GDI_ERROR;
5745 #endif
5747 case GGO_NATIVE:
5749 int contour, point = 0, first_pt;
5750 FT_Outline *outline = &ft_face->glyph->outline;
5751 TTPOLYGONHEADER *pph;
5752 TTPOLYCURVE *ppc;
5753 DWORD pph_start, cpfx, type;
5755 if(buflen == 0) buf = NULL;
5757 if (needsTransform && buf) {
5758 pFT_Outline_Transform(outline, &transMat);
5761 for(contour = 0; contour < outline->n_contours; contour++) {
5762 pph_start = needed;
5763 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5764 first_pt = point;
5765 if(buf) {
5766 pph->dwType = TT_POLYGON_TYPE;
5767 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5769 needed += sizeof(*pph);
5770 point++;
5771 while(point <= outline->contours[contour]) {
5772 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5773 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5774 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5775 cpfx = 0;
5776 do {
5777 if(buf)
5778 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5779 cpfx++;
5780 point++;
5781 } while(point <= outline->contours[contour] &&
5782 (outline->tags[point] & FT_Curve_Tag_On) ==
5783 (outline->tags[point-1] & FT_Curve_Tag_On));
5784 /* At the end of a contour Windows adds the start point, but
5785 only for Beziers */
5786 if(point > outline->contours[contour] &&
5787 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5788 if(buf)
5789 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5790 cpfx++;
5791 } else if(point <= outline->contours[contour] &&
5792 outline->tags[point] & FT_Curve_Tag_On) {
5793 /* add closing pt for bezier */
5794 if(buf)
5795 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5796 cpfx++;
5797 point++;
5799 if(buf) {
5800 ppc->wType = type;
5801 ppc->cpfx = cpfx;
5803 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5805 if(buf)
5806 pph->cb = needed - pph_start;
5808 break;
5810 case GGO_BEZIER:
5812 /* Convert the quadratic Beziers to cubic Beziers.
5813 The parametric eqn for a cubic Bezier is, from PLRM:
5814 r(t) = at^3 + bt^2 + ct + r0
5815 with the control points:
5816 r1 = r0 + c/3
5817 r2 = r1 + (c + b)/3
5818 r3 = r0 + c + b + a
5820 A quadratic Bezier has the form:
5821 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5823 So equating powers of t leads to:
5824 r1 = 2/3 p1 + 1/3 p0
5825 r2 = 2/3 p1 + 1/3 p2
5826 and of course r0 = p0, r3 = p2
5829 int contour, point = 0, first_pt;
5830 FT_Outline *outline = &ft_face->glyph->outline;
5831 TTPOLYGONHEADER *pph;
5832 TTPOLYCURVE *ppc;
5833 DWORD pph_start, cpfx, type;
5834 FT_Vector cubic_control[4];
5835 if(buflen == 0) buf = NULL;
5837 if (needsTransform && buf) {
5838 pFT_Outline_Transform(outline, &transMat);
5841 for(contour = 0; contour < outline->n_contours; contour++) {
5842 pph_start = needed;
5843 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5844 first_pt = point;
5845 if(buf) {
5846 pph->dwType = TT_POLYGON_TYPE;
5847 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5849 needed += sizeof(*pph);
5850 point++;
5851 while(point <= outline->contours[contour]) {
5852 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5853 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5854 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5855 cpfx = 0;
5856 do {
5857 if(type == TT_PRIM_LINE) {
5858 if(buf)
5859 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5860 cpfx++;
5861 point++;
5862 } else {
5863 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5864 so cpfx = 3n */
5866 /* FIXME: Possible optimization in endpoint calculation
5867 if there are two consecutive curves */
5868 cubic_control[0] = outline->points[point-1];
5869 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5870 cubic_control[0].x += outline->points[point].x + 1;
5871 cubic_control[0].y += outline->points[point].y + 1;
5872 cubic_control[0].x >>= 1;
5873 cubic_control[0].y >>= 1;
5875 if(point+1 > outline->contours[contour])
5876 cubic_control[3] = outline->points[first_pt];
5877 else {
5878 cubic_control[3] = outline->points[point+1];
5879 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5880 cubic_control[3].x += outline->points[point].x + 1;
5881 cubic_control[3].y += outline->points[point].y + 1;
5882 cubic_control[3].x >>= 1;
5883 cubic_control[3].y >>= 1;
5886 /* r1 = 1/3 p0 + 2/3 p1
5887 r2 = 1/3 p2 + 2/3 p1 */
5888 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5889 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5890 cubic_control[2] = cubic_control[1];
5891 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5892 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5893 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5894 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5895 if(buf) {
5896 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5897 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5898 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5900 cpfx += 3;
5901 point++;
5903 } while(point <= outline->contours[contour] &&
5904 (outline->tags[point] & FT_Curve_Tag_On) ==
5905 (outline->tags[point-1] & FT_Curve_Tag_On));
5906 /* At the end of a contour Windows adds the start point,
5907 but only for Beziers and we've already done that.
5909 if(point <= outline->contours[contour] &&
5910 outline->tags[point] & FT_Curve_Tag_On) {
5911 /* This is the closing pt of a bezier, but we've already
5912 added it, so just inc point and carry on */
5913 point++;
5915 if(buf) {
5916 ppc->wType = type;
5917 ppc->cpfx = cpfx;
5919 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5921 if(buf)
5922 pph->cb = needed - pph_start;
5924 break;
5927 default:
5928 FIXME("Unsupported format %d\n", format);
5929 return GDI_ERROR;
5931 return needed;
5934 static BOOL get_bitmap_text_metrics(GdiFont *font)
5936 FT_Face ft_face = font->ft_face;
5937 FT_WinFNT_HeaderRec winfnt_header;
5938 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5939 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5940 font->potm->otmSize = size;
5942 #define TM font->potm->otmTextMetrics
5943 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5945 TM.tmHeight = winfnt_header.pixel_height;
5946 TM.tmAscent = winfnt_header.ascent;
5947 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5948 TM.tmInternalLeading = winfnt_header.internal_leading;
5949 TM.tmExternalLeading = winfnt_header.external_leading;
5950 TM.tmAveCharWidth = winfnt_header.avg_width;
5951 TM.tmMaxCharWidth = winfnt_header.max_width;
5952 TM.tmWeight = winfnt_header.weight;
5953 TM.tmOverhang = 0;
5954 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5955 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5956 TM.tmFirstChar = winfnt_header.first_char;
5957 TM.tmLastChar = winfnt_header.last_char;
5958 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5959 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5960 TM.tmItalic = winfnt_header.italic;
5961 TM.tmUnderlined = font->underline;
5962 TM.tmStruckOut = font->strikeout;
5963 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5964 TM.tmCharSet = winfnt_header.charset;
5966 else
5968 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5969 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5970 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5971 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5972 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5973 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5974 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5975 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5976 TM.tmOverhang = 0;
5977 TM.tmDigitizedAspectX = 96; /* FIXME */
5978 TM.tmDigitizedAspectY = 96; /* FIXME */
5979 TM.tmFirstChar = 1;
5980 TM.tmLastChar = 255;
5981 TM.tmDefaultChar = 32;
5982 TM.tmBreakChar = 32;
5983 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5984 TM.tmUnderlined = font->underline;
5985 TM.tmStruckOut = font->strikeout;
5986 /* NB inverted meaning of TMPF_FIXED_PITCH */
5987 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5988 TM.tmCharSet = font->charset;
5990 #undef TM
5992 return TRUE;
5996 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5998 double scale_x, scale_y;
6000 if (font->aveWidth)
6002 scale_x = (double)font->aveWidth;
6003 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6005 else
6006 scale_x = font->scale_y;
6008 scale_x *= fabs(font->font_desc.matrix.eM11);
6009 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6011 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6012 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6014 SCALE_Y(ptm->tmHeight);
6015 SCALE_Y(ptm->tmAscent);
6016 SCALE_Y(ptm->tmDescent);
6017 SCALE_Y(ptm->tmInternalLeading);
6018 SCALE_Y(ptm->tmExternalLeading);
6019 SCALE_Y(ptm->tmOverhang);
6021 SCALE_X(ptm->tmAveCharWidth);
6022 SCALE_X(ptm->tmMaxCharWidth);
6024 #undef SCALE_X
6025 #undef SCALE_Y
6028 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6030 double scale_x, scale_y;
6032 if (font->aveWidth)
6034 scale_x = (double)font->aveWidth;
6035 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6037 else
6038 scale_x = font->scale_y;
6040 scale_x *= fabs(font->font_desc.matrix.eM11);
6041 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6043 scale_font_metrics(font, &potm->otmTextMetrics);
6045 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6046 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6048 SCALE_Y(potm->otmAscent);
6049 SCALE_Y(potm->otmDescent);
6050 SCALE_Y(potm->otmLineGap);
6051 SCALE_Y(potm->otmsCapEmHeight);
6052 SCALE_Y(potm->otmsXHeight);
6053 SCALE_Y(potm->otmrcFontBox.top);
6054 SCALE_Y(potm->otmrcFontBox.bottom);
6055 SCALE_X(potm->otmrcFontBox.left);
6056 SCALE_X(potm->otmrcFontBox.right);
6057 SCALE_Y(potm->otmMacAscent);
6058 SCALE_Y(potm->otmMacDescent);
6059 SCALE_Y(potm->otmMacLineGap);
6060 SCALE_X(potm->otmptSubscriptSize.x);
6061 SCALE_Y(potm->otmptSubscriptSize.y);
6062 SCALE_X(potm->otmptSubscriptOffset.x);
6063 SCALE_Y(potm->otmptSubscriptOffset.y);
6064 SCALE_X(potm->otmptSuperscriptSize.x);
6065 SCALE_Y(potm->otmptSuperscriptSize.y);
6066 SCALE_X(potm->otmptSuperscriptOffset.x);
6067 SCALE_Y(potm->otmptSuperscriptOffset.y);
6068 SCALE_Y(potm->otmsStrikeoutSize);
6069 SCALE_Y(potm->otmsStrikeoutPosition);
6070 SCALE_Y(potm->otmsUnderscoreSize);
6071 SCALE_Y(potm->otmsUnderscorePosition);
6073 #undef SCALE_X
6074 #undef SCALE_Y
6077 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6079 if(!font->potm)
6081 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6083 /* Make sure that the font has sane width/height ratio */
6084 if (font->aveWidth)
6086 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6088 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6089 font->aveWidth = 0;
6093 *ptm = font->potm->otmTextMetrics;
6094 scale_font_metrics(font, ptm);
6095 return TRUE;
6098 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6100 int i;
6102 for(i = 0; i < ft_face->num_charmaps; i++)
6104 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6105 return TRUE;
6107 return FALSE;
6110 static BOOL get_outline_text_metrics(GdiFont *font)
6112 BOOL ret = FALSE;
6113 FT_Face ft_face = font->ft_face;
6114 UINT needed, lenfam, lensty;
6115 TT_OS2 *pOS2;
6116 TT_HoriHeader *pHori;
6117 TT_Postscript *pPost;
6118 FT_Fixed x_scale, y_scale;
6119 WCHAR *family_nameW, *style_nameW;
6120 static const WCHAR spaceW[] = {' ', '\0'};
6121 char *cp;
6122 INT ascent, descent;
6124 TRACE("font=%p\n", font);
6126 if(!FT_IS_SCALABLE(ft_face))
6127 return FALSE;
6129 needed = sizeof(*font->potm);
6131 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6132 family_nameW = strdupW(font->name);
6134 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6135 * sizeof(WCHAR);
6136 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6137 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6138 style_nameW, lensty/sizeof(WCHAR));
6140 /* These names should be read from the TT name table */
6142 /* length of otmpFamilyName */
6143 needed += lenfam;
6145 /* length of otmpFaceName */
6146 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6147 needed += lenfam; /* just the family name */
6148 } else {
6149 needed += lenfam + lensty; /* family + " " + style */
6152 /* length of otmpStyleName */
6153 needed += lensty;
6155 /* length of otmpFullName */
6156 needed += lenfam + lensty;
6159 x_scale = ft_face->size->metrics.x_scale;
6160 y_scale = ft_face->size->metrics.y_scale;
6162 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6163 if(!pOS2) {
6164 FIXME("Can't find OS/2 table - not TT font?\n");
6165 goto end;
6168 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6169 if(!pHori) {
6170 FIXME("Can't find HHEA table - not TT font?\n");
6171 goto end;
6174 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6176 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",
6177 pOS2->usWinAscent, pOS2->usWinDescent,
6178 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6179 ft_face->ascender, ft_face->descender, ft_face->height,
6180 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6181 ft_face->bbox.yMax, ft_face->bbox.yMin);
6183 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6184 font->potm->otmSize = needed;
6186 #define TM font->potm->otmTextMetrics
6188 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6189 ascent = pHori->Ascender;
6190 descent = -pHori->Descender;
6191 } else {
6192 ascent = pOS2->usWinAscent;
6193 descent = pOS2->usWinDescent;
6196 if(font->yMax) {
6197 TM.tmAscent = font->yMax;
6198 TM.tmDescent = -font->yMin;
6199 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6200 } else {
6201 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6202 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6203 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6204 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6207 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6209 /* MSDN says:
6210 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6212 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6213 ((ascent + descent) -
6214 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6216 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6217 if (TM.tmAveCharWidth == 0) {
6218 TM.tmAveCharWidth = 1;
6220 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6221 TM.tmWeight = FW_REGULAR;
6222 if (font->fake_bold)
6223 TM.tmWeight = FW_BOLD;
6224 else
6226 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6228 if (pOS2->usWeightClass > FW_MEDIUM)
6229 TM.tmWeight = pOS2->usWeightClass;
6231 else if (pOS2->usWeightClass <= FW_MEDIUM)
6232 TM.tmWeight = pOS2->usWeightClass;
6234 TM.tmOverhang = 0;
6235 TM.tmDigitizedAspectX = 300;
6236 TM.tmDigitizedAspectY = 300;
6237 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6238 * symbol range to 0 - f0ff
6241 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6243 TM.tmFirstChar = 0;
6244 switch(GetACP())
6246 case 1257: /* Baltic */
6247 TM.tmLastChar = 0xf8fd;
6248 break;
6249 default:
6250 TM.tmLastChar = 0xf0ff;
6252 TM.tmBreakChar = 0x20;
6253 TM.tmDefaultChar = 0x1f;
6255 else
6257 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6258 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6260 if(pOS2->usFirstCharIndex <= 1)
6261 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6262 else if (pOS2->usFirstCharIndex > 0xff)
6263 TM.tmBreakChar = 0x20;
6264 else
6265 TM.tmBreakChar = pOS2->usFirstCharIndex;
6266 TM.tmDefaultChar = TM.tmBreakChar - 1;
6268 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6269 TM.tmUnderlined = font->underline;
6270 TM.tmStruckOut = font->strikeout;
6272 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6273 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6274 (pOS2->version == 0xFFFFU ||
6275 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6276 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6277 else
6278 TM.tmPitchAndFamily = 0;
6280 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6282 case PAN_FAMILY_SCRIPT:
6283 TM.tmPitchAndFamily |= FF_SCRIPT;
6284 break;
6286 case PAN_FAMILY_DECORATIVE:
6287 TM.tmPitchAndFamily |= FF_DECORATIVE;
6288 break;
6290 case PAN_ANY:
6291 case PAN_NO_FIT:
6292 case PAN_FAMILY_TEXT_DISPLAY:
6293 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6294 /* which is clearly not what the panose spec says. */
6295 default:
6296 if(TM.tmPitchAndFamily == 0 || /* fixed */
6297 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6298 TM.tmPitchAndFamily = FF_MODERN;
6299 else
6301 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6303 case PAN_ANY:
6304 case PAN_NO_FIT:
6305 default:
6306 TM.tmPitchAndFamily |= FF_DONTCARE;
6307 break;
6309 case PAN_SERIF_COVE:
6310 case PAN_SERIF_OBTUSE_COVE:
6311 case PAN_SERIF_SQUARE_COVE:
6312 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6313 case PAN_SERIF_SQUARE:
6314 case PAN_SERIF_THIN:
6315 case PAN_SERIF_BONE:
6316 case PAN_SERIF_EXAGGERATED:
6317 case PAN_SERIF_TRIANGLE:
6318 TM.tmPitchAndFamily |= FF_ROMAN;
6319 break;
6321 case PAN_SERIF_NORMAL_SANS:
6322 case PAN_SERIF_OBTUSE_SANS:
6323 case PAN_SERIF_PERP_SANS:
6324 case PAN_SERIF_FLARED:
6325 case PAN_SERIF_ROUNDED:
6326 TM.tmPitchAndFamily |= FF_SWISS;
6327 break;
6330 break;
6333 if(FT_IS_SCALABLE(ft_face))
6334 TM.tmPitchAndFamily |= TMPF_VECTOR;
6336 if(FT_IS_SFNT(ft_face))
6338 if (font->ntmFlags & NTM_PS_OPENTYPE)
6339 TM.tmPitchAndFamily |= TMPF_DEVICE;
6340 else
6341 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6344 TM.tmCharSet = font->charset;
6346 font->potm->otmFiller = 0;
6347 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6348 font->potm->otmfsSelection = pOS2->fsSelection;
6349 font->potm->otmfsType = pOS2->fsType;
6350 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6351 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6352 font->potm->otmItalicAngle = 0; /* POST table */
6353 font->potm->otmEMSquare = ft_face->units_per_EM;
6354 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6355 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6356 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6357 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6358 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6359 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6360 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6361 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6362 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6363 font->potm->otmMacAscent = TM.tmAscent;
6364 font->potm->otmMacDescent = -TM.tmDescent;
6365 font->potm->otmMacLineGap = font->potm->otmLineGap;
6366 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6367 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6368 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6369 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6370 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6371 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6372 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6373 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6374 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6375 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6376 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6377 if(!pPost) {
6378 font->potm->otmsUnderscoreSize = 0;
6379 font->potm->otmsUnderscorePosition = 0;
6380 } else {
6381 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6382 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6384 #undef TM
6386 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6387 cp = (char*)font->potm + sizeof(*font->potm);
6388 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6389 strcpyW((WCHAR*)cp, family_nameW);
6390 cp += lenfam;
6391 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6392 strcpyW((WCHAR*)cp, style_nameW);
6393 cp += lensty;
6394 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6395 strcpyW((WCHAR*)cp, family_nameW);
6396 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6397 strcatW((WCHAR*)cp, spaceW);
6398 strcatW((WCHAR*)cp, style_nameW);
6399 cp += lenfam + lensty;
6400 } else
6401 cp += lenfam;
6402 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6403 strcpyW((WCHAR*)cp, family_nameW);
6404 strcatW((WCHAR*)cp, spaceW);
6405 strcatW((WCHAR*)cp, style_nameW);
6406 ret = TRUE;
6408 end:
6409 HeapFree(GetProcessHeap(), 0, style_nameW);
6410 HeapFree(GetProcessHeap(), 0, family_nameW);
6411 return ret;
6414 /*************************************************************
6415 * freetype_GetGlyphOutline
6417 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6418 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6420 struct freetype_physdev *physdev = get_freetype_dev( dev );
6421 DWORD ret;
6423 if (!physdev->font)
6425 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6426 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6429 GDI_CheckNotLock();
6430 EnterCriticalSection( &freetype_cs );
6431 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6432 LeaveCriticalSection( &freetype_cs );
6433 return ret;
6436 /*************************************************************
6437 * freetype_GetTextMetrics
6439 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6441 struct freetype_physdev *physdev = get_freetype_dev( dev );
6442 BOOL ret;
6444 if (!physdev->font)
6446 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6447 return dev->funcs->pGetTextMetrics( dev, metrics );
6450 GDI_CheckNotLock();
6451 EnterCriticalSection( &freetype_cs );
6452 ret = get_text_metrics( physdev->font, metrics );
6453 LeaveCriticalSection( &freetype_cs );
6454 return ret;
6457 /*************************************************************
6458 * freetype_GetOutlineTextMetrics
6460 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6462 struct freetype_physdev *physdev = get_freetype_dev( dev );
6463 UINT ret = 0;
6465 if (!physdev->font)
6467 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6468 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6471 TRACE("font=%p\n", physdev->font);
6473 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6475 GDI_CheckNotLock();
6476 EnterCriticalSection( &freetype_cs );
6478 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6480 if(cbSize >= physdev->font->potm->otmSize)
6482 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6483 scale_outline_font_metrics(physdev->font, potm);
6485 ret = physdev->font->potm->otmSize;
6487 LeaveCriticalSection( &freetype_cs );
6488 return ret;
6491 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6493 HFONTLIST *hfontlist;
6494 child->font = alloc_font();
6495 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6496 if(!child->font->ft_face)
6498 free_font(child->font);
6499 child->font = NULL;
6500 return FALSE;
6503 child->font->font_desc = font->font_desc;
6504 child->font->ntmFlags = child->face->ntmFlags;
6505 child->font->orientation = font->orientation;
6506 child->font->scale_y = font->scale_y;
6507 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6508 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6509 child->font->name = strdupW(child->face->family->FamilyName);
6510 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6511 child->font->base_font = font;
6512 list_add_head(&child_font_list, &child->font->entry);
6513 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6514 return TRUE;
6517 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6519 FT_UInt g;
6520 CHILD_FONT *child_font;
6522 if(font->base_font)
6523 font = font->base_font;
6525 *linked_font = font;
6527 if((*glyph = get_glyph_index(font, c)))
6529 *glyph = get_GSUB_vert_glyph(font, *glyph);
6530 return TRUE;
6533 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6535 if(!child_font->font)
6536 if(!load_child_font(font, child_font))
6537 continue;
6539 if(!child_font->font->ft_face)
6540 continue;
6541 g = get_glyph_index(child_font->font, c);
6542 g = get_GSUB_vert_glyph(child_font->font, g);
6543 if(g)
6545 *glyph = g;
6546 *linked_font = child_font->font;
6547 return TRUE;
6550 return FALSE;
6553 /*************************************************************
6554 * freetype_GetCharWidth
6556 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6558 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6559 UINT c;
6560 GLYPHMETRICS gm;
6561 FT_UInt glyph_index;
6562 GdiFont *linked_font;
6563 struct freetype_physdev *physdev = get_freetype_dev( dev );
6565 if (!physdev->font)
6567 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6568 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6571 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6573 GDI_CheckNotLock();
6574 EnterCriticalSection( &freetype_cs );
6575 for(c = firstChar; c <= lastChar; c++) {
6576 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6577 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6578 &gm, 0, NULL, &identity);
6579 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6581 LeaveCriticalSection( &freetype_cs );
6582 return TRUE;
6585 /*************************************************************
6586 * freetype_GetCharABCWidths
6588 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6590 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6591 UINT c;
6592 GLYPHMETRICS gm;
6593 FT_UInt glyph_index;
6594 GdiFont *linked_font;
6595 struct freetype_physdev *physdev = get_freetype_dev( dev );
6597 if (!physdev->font)
6599 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6600 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6603 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6605 GDI_CheckNotLock();
6606 EnterCriticalSection( &freetype_cs );
6608 for(c = firstChar; c <= lastChar; c++) {
6609 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6610 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6611 &gm, 0, NULL, &identity);
6612 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6613 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6614 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6615 FONT_GM(linked_font,glyph_index)->bbx;
6617 LeaveCriticalSection( &freetype_cs );
6618 return TRUE;
6621 /*************************************************************
6622 * freetype_GetCharABCWidthsI
6624 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6626 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6627 UINT c;
6628 GLYPHMETRICS gm;
6629 FT_UInt glyph_index;
6630 GdiFont *linked_font;
6631 struct freetype_physdev *physdev = get_freetype_dev( dev );
6633 if (!physdev->font)
6635 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6636 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6639 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6640 return FALSE;
6642 GDI_CheckNotLock();
6643 EnterCriticalSection( &freetype_cs );
6645 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6646 if (!pgi)
6647 for(c = firstChar; c < firstChar+count; c++) {
6648 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6649 &gm, 0, NULL, &identity);
6650 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6651 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6652 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6653 - FONT_GM(linked_font,c)->bbx;
6655 else
6656 for(c = 0; c < count; c++) {
6657 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6658 &gm, 0, NULL, &identity);
6659 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6660 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6661 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6662 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6665 LeaveCriticalSection( &freetype_cs );
6666 return TRUE;
6669 /*************************************************************
6670 * freetype_GetTextExtentExPoint
6672 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6673 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6675 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6676 INT idx;
6677 INT nfit = 0, ext;
6678 GLYPHMETRICS gm;
6679 TEXTMETRICW tm;
6680 FT_UInt glyph_index;
6681 GdiFont *linked_font;
6682 struct freetype_physdev *physdev = get_freetype_dev( dev );
6684 if (!physdev->font)
6686 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6687 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6690 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6692 GDI_CheckNotLock();
6693 EnterCriticalSection( &freetype_cs );
6695 size->cx = 0;
6696 get_text_metrics( physdev->font, &tm );
6697 size->cy = tm.tmHeight;
6699 for(idx = 0; idx < count; idx++) {
6700 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6701 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6702 &gm, 0, NULL, &identity);
6703 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6704 ext = size->cx;
6705 if (! pnfit || ext <= max_ext) {
6706 ++nfit;
6707 if (dxs)
6708 dxs[idx] = ext;
6712 if (pnfit)
6713 *pnfit = nfit;
6715 LeaveCriticalSection( &freetype_cs );
6716 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6717 return TRUE;
6720 /*************************************************************
6721 * freetype_GetTextExtentExPointI
6723 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6724 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6726 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6727 INT idx;
6728 INT nfit = 0, ext;
6729 GLYPHMETRICS gm;
6730 TEXTMETRICW tm;
6731 struct freetype_physdev *physdev = get_freetype_dev( dev );
6733 if (!physdev->font)
6735 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6736 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6739 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6741 GDI_CheckNotLock();
6742 EnterCriticalSection( &freetype_cs );
6744 size->cx = 0;
6745 get_text_metrics(physdev->font, &tm);
6746 size->cy = tm.tmHeight;
6748 for(idx = 0; idx < count; idx++) {
6749 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6750 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6751 ext = size->cx;
6752 if (! pnfit || ext <= max_ext) {
6753 ++nfit;
6754 if (dxs)
6755 dxs[idx] = ext;
6759 if (pnfit)
6760 *pnfit = nfit;
6762 LeaveCriticalSection( &freetype_cs );
6763 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6764 return TRUE;
6767 /*************************************************************
6768 * freetype_GetFontData
6770 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6772 struct freetype_physdev *physdev = get_freetype_dev( dev );
6774 if (!physdev->font)
6776 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6777 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6780 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6781 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6782 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6784 return get_font_data( physdev->font, table, offset, buf, cbData );
6787 /*************************************************************
6788 * freetype_GetTextFace
6790 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6792 INT n;
6793 struct freetype_physdev *physdev = get_freetype_dev( dev );
6795 if (!physdev->font)
6797 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6798 return dev->funcs->pGetTextFace( dev, count, str );
6801 n = strlenW(physdev->font->name) + 1;
6802 if (str)
6804 lstrcpynW(str, physdev->font->name, count);
6805 n = min(count, n);
6807 return n;
6810 /*************************************************************
6811 * freetype_GetTextCharsetInfo
6813 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6815 struct freetype_physdev *physdev = get_freetype_dev( dev );
6817 if (!physdev->font)
6819 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6820 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6822 if (fs) *fs = physdev->font->fs;
6823 return physdev->font->charset;
6826 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6828 GdiFont *font = dc->gdiFont, *linked_font;
6829 struct list *first_hfont;
6830 BOOL ret;
6832 GDI_CheckNotLock();
6833 EnterCriticalSection( &freetype_cs );
6834 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6835 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6836 if(font == linked_font)
6837 *new_hfont = dc->hFont;
6838 else
6840 first_hfont = list_head(&linked_font->hfontlist);
6841 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6843 LeaveCriticalSection( &freetype_cs );
6844 return ret;
6847 /* Retrieve a list of supported Unicode ranges for a given font.
6848 * Can be called with NULL gs to calculate the buffer size. Returns
6849 * the number of ranges found.
6851 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6853 DWORD num_ranges = 0;
6855 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6857 FT_UInt glyph_code;
6858 FT_ULong char_code, char_code_prev;
6860 glyph_code = 0;
6861 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6863 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6864 face->num_glyphs, glyph_code, char_code);
6866 if (!glyph_code) return 0;
6868 if (gs)
6870 gs->ranges[0].wcLow = (USHORT)char_code;
6871 gs->ranges[0].cGlyphs = 0;
6872 gs->cGlyphsSupported = 0;
6875 num_ranges = 1;
6876 while (glyph_code)
6878 if (char_code < char_code_prev)
6880 ERR("expected increasing char code from FT_Get_Next_Char\n");
6881 return 0;
6883 if (char_code - char_code_prev > 1)
6885 num_ranges++;
6886 if (gs)
6888 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6889 gs->ranges[num_ranges - 1].cGlyphs = 1;
6890 gs->cGlyphsSupported++;
6893 else if (gs)
6895 gs->ranges[num_ranges - 1].cGlyphs++;
6896 gs->cGlyphsSupported++;
6898 char_code_prev = char_code;
6899 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6902 else
6903 FIXME("encoding %u not supported\n", face->charmap->encoding);
6905 return num_ranges;
6908 /*************************************************************
6909 * freetype_GetFontUnicodeRanges
6911 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6913 struct freetype_physdev *physdev = get_freetype_dev( dev );
6914 DWORD size, num_ranges;
6916 if (!physdev->font)
6918 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6919 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6922 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6923 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6924 if (glyphset)
6926 glyphset->cbThis = size;
6927 glyphset->cRanges = num_ranges;
6928 glyphset->flAccel = 0;
6930 return size;
6933 /*************************************************************
6934 * freetype_FontIsLinked
6936 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6938 struct freetype_physdev *physdev = get_freetype_dev( dev );
6939 BOOL ret;
6941 if (!physdev->font)
6943 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6944 return dev->funcs->pFontIsLinked( dev );
6947 GDI_CheckNotLock();
6948 EnterCriticalSection( &freetype_cs );
6949 ret = !list_empty(&physdev->font->child_fonts);
6950 LeaveCriticalSection( &freetype_cs );
6951 return ret;
6954 static BOOL is_hinting_enabled(void)
6956 /* Use the >= 2.2.0 function if available */
6957 if(pFT_Get_TrueType_Engine_Type)
6959 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6960 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6962 #ifdef FT_DRIVER_HAS_HINTER
6963 else
6965 FT_Module mod;
6967 /* otherwise if we've been compiled with < 2.2.0 headers
6968 use the internal macro */
6969 mod = pFT_Get_Module(library, "truetype");
6970 if(mod && FT_DRIVER_HAS_HINTER(mod))
6971 return TRUE;
6973 #endif
6975 return FALSE;
6978 static BOOL is_subpixel_rendering_enabled( void )
6980 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6981 return pFT_Library_SetLcdFilter &&
6982 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6983 #else
6984 return FALSE;
6985 #endif
6988 /*************************************************************************
6989 * GetRasterizerCaps (GDI32.@)
6991 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6993 static int hinting = -1;
6994 static int subpixel = -1;
6996 if(hinting == -1)
6998 hinting = is_hinting_enabled();
6999 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7002 if ( subpixel == -1 )
7004 subpixel = is_subpixel_rendering_enabled();
7005 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7008 lprs->nSize = sizeof(RASTERIZER_STATUS);
7009 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7010 if ( subpixel )
7011 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7012 lprs->nLanguageID = 0;
7013 return TRUE;
7016 /*************************************************************
7017 * freetype_GdiRealizationInfo
7019 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7021 struct freetype_physdev *physdev = get_freetype_dev( dev );
7022 realization_info_t *info = ptr;
7024 if (!physdev->font)
7026 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7027 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7030 FIXME("(%p, %p): stub!\n", physdev->font, info);
7032 info->flags = 1;
7033 if(FT_IS_SCALABLE(physdev->font->ft_face))
7034 info->flags |= 2;
7036 info->cache_num = physdev->font->cache_num;
7037 info->unknown2 = -1;
7038 return TRUE;
7041 /*************************************************************************
7042 * Kerning support for TrueType fonts
7044 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7046 struct TT_kern_table
7048 USHORT version;
7049 USHORT nTables;
7052 struct TT_kern_subtable
7054 USHORT version;
7055 USHORT length;
7056 union
7058 USHORT word;
7059 struct
7061 USHORT horizontal : 1;
7062 USHORT minimum : 1;
7063 USHORT cross_stream: 1;
7064 USHORT override : 1;
7065 USHORT reserved1 : 4;
7066 USHORT format : 8;
7067 } bits;
7068 } coverage;
7071 struct TT_format0_kern_subtable
7073 USHORT nPairs;
7074 USHORT searchRange;
7075 USHORT entrySelector;
7076 USHORT rangeShift;
7079 struct TT_kern_pair
7081 USHORT left;
7082 USHORT right;
7083 short value;
7086 static DWORD parse_format0_kern_subtable(GdiFont *font,
7087 const struct TT_format0_kern_subtable *tt_f0_ks,
7088 const USHORT *glyph_to_char,
7089 KERNINGPAIR *kern_pair, DWORD cPairs)
7091 USHORT i, nPairs;
7092 const struct TT_kern_pair *tt_kern_pair;
7094 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7096 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7098 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7099 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7100 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7102 if (!kern_pair || !cPairs)
7103 return nPairs;
7105 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7107 nPairs = min(nPairs, cPairs);
7109 for (i = 0; i < nPairs; i++)
7111 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7112 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7113 /* this algorithm appears to better match what Windows does */
7114 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7115 if (kern_pair->iKernAmount < 0)
7117 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7118 kern_pair->iKernAmount -= font->ppem;
7120 else if (kern_pair->iKernAmount > 0)
7122 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7123 kern_pair->iKernAmount += font->ppem;
7125 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7127 TRACE("left %u right %u value %d\n",
7128 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7130 kern_pair++;
7132 TRACE("copied %u entries\n", nPairs);
7133 return nPairs;
7136 /*************************************************************
7137 * freetype_GetKerningPairs
7139 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7141 DWORD length;
7142 void *buf;
7143 const struct TT_kern_table *tt_kern_table;
7144 const struct TT_kern_subtable *tt_kern_subtable;
7145 USHORT i, nTables;
7146 USHORT *glyph_to_char;
7147 GdiFont *font;
7148 struct freetype_physdev *physdev = get_freetype_dev( dev );
7150 if (!(font = physdev->font))
7152 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7153 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7156 GDI_CheckNotLock();
7157 EnterCriticalSection( &freetype_cs );
7158 if (font->total_kern_pairs != (DWORD)-1)
7160 if (cPairs && kern_pair)
7162 cPairs = min(cPairs, font->total_kern_pairs);
7163 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7165 else cPairs = font->total_kern_pairs;
7167 LeaveCriticalSection( &freetype_cs );
7168 return cPairs;
7171 font->total_kern_pairs = 0;
7173 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7175 if (length == GDI_ERROR)
7177 TRACE("no kerning data in the font\n");
7178 LeaveCriticalSection( &freetype_cs );
7179 return 0;
7182 buf = HeapAlloc(GetProcessHeap(), 0, length);
7183 if (!buf)
7185 WARN("Out of memory\n");
7186 LeaveCriticalSection( &freetype_cs );
7187 return 0;
7190 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7192 /* build a glyph index to char code map */
7193 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7194 if (!glyph_to_char)
7196 WARN("Out of memory allocating a glyph index to char code map\n");
7197 HeapFree(GetProcessHeap(), 0, buf);
7198 LeaveCriticalSection( &freetype_cs );
7199 return 0;
7202 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7204 FT_UInt glyph_code;
7205 FT_ULong char_code;
7207 glyph_code = 0;
7208 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7210 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7211 font->ft_face->num_glyphs, glyph_code, char_code);
7213 while (glyph_code)
7215 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7217 /* FIXME: This doesn't match what Windows does: it does some fancy
7218 * things with duplicate glyph index to char code mappings, while
7219 * we just avoid overriding existing entries.
7221 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7222 glyph_to_char[glyph_code] = (USHORT)char_code;
7224 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7227 else
7229 ULONG n;
7231 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7232 for (n = 0; n <= 65535; n++)
7233 glyph_to_char[n] = (USHORT)n;
7236 tt_kern_table = buf;
7237 nTables = GET_BE_WORD(tt_kern_table->nTables);
7238 TRACE("version %u, nTables %u\n",
7239 GET_BE_WORD(tt_kern_table->version), nTables);
7241 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7243 for (i = 0; i < nTables; i++)
7245 struct TT_kern_subtable tt_kern_subtable_copy;
7247 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7248 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7249 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7251 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7252 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7253 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7255 /* According to the TrueType specification this is the only format
7256 * that will be properly interpreted by Windows and OS/2
7258 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7260 DWORD new_chunk, old_total = font->total_kern_pairs;
7262 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7263 glyph_to_char, NULL, 0);
7264 font->total_kern_pairs += new_chunk;
7266 if (!font->kern_pairs)
7267 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7268 font->total_kern_pairs * sizeof(*font->kern_pairs));
7269 else
7270 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7271 font->total_kern_pairs * sizeof(*font->kern_pairs));
7273 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7274 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7276 else
7277 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7279 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7282 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7283 HeapFree(GetProcessHeap(), 0, buf);
7285 if (cPairs && kern_pair)
7287 cPairs = min(cPairs, font->total_kern_pairs);
7288 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7290 else cPairs = font->total_kern_pairs;
7292 LeaveCriticalSection( &freetype_cs );
7293 return cPairs;
7296 static const struct gdi_dc_funcs freetype_funcs =
7298 NULL, /* pAbortDoc */
7299 NULL, /* pAbortPath */
7300 NULL, /* pAlphaBlend */
7301 NULL, /* pAngleArc */
7302 NULL, /* pArc */
7303 NULL, /* pArcTo */
7304 NULL, /* pBeginPath */
7305 NULL, /* pBlendImage */
7306 NULL, /* pChoosePixelFormat */
7307 NULL, /* pChord */
7308 NULL, /* pCloseFigure */
7309 NULL, /* pCopyBitmap */
7310 NULL, /* pCreateBitmap */
7311 NULL, /* pCreateCompatibleDC */
7312 freetype_CreateDC, /* pCreateDC */
7313 NULL, /* pDeleteBitmap */
7314 freetype_DeleteDC, /* pDeleteDC */
7315 NULL, /* pDeleteObject */
7316 NULL, /* pDescribePixelFormat */
7317 NULL, /* pDeviceCapabilities */
7318 NULL, /* pEllipse */
7319 NULL, /* pEndDoc */
7320 NULL, /* pEndPage */
7321 NULL, /* pEndPath */
7322 freetype_EnumFonts, /* pEnumFonts */
7323 NULL, /* pEnumICMProfiles */
7324 NULL, /* pExcludeClipRect */
7325 NULL, /* pExtDeviceMode */
7326 NULL, /* pExtEscape */
7327 NULL, /* pExtFloodFill */
7328 NULL, /* pExtSelectClipRgn */
7329 NULL, /* pExtTextOut */
7330 NULL, /* pFillPath */
7331 NULL, /* pFillRgn */
7332 NULL, /* pFlattenPath */
7333 freetype_FontIsLinked, /* pFontIsLinked */
7334 NULL, /* pFrameRgn */
7335 NULL, /* pGdiComment */
7336 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7337 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7338 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7339 freetype_GetCharWidth, /* pGetCharWidth */
7340 NULL, /* pGetDeviceCaps */
7341 NULL, /* pGetDeviceGammaRamp */
7342 freetype_GetFontData, /* pGetFontData */
7343 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7344 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7345 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7346 NULL, /* pGetICMProfile */
7347 NULL, /* pGetImage */
7348 freetype_GetKerningPairs, /* pGetKerningPairs */
7349 NULL, /* pGetNearestColor */
7350 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7351 NULL, /* pGetPixel */
7352 NULL, /* pGetPixelFormat */
7353 NULL, /* pGetSystemPaletteEntries */
7354 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7355 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7356 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7357 freetype_GetTextFace, /* pGetTextFace */
7358 freetype_GetTextMetrics, /* pGetTextMetrics */
7359 NULL, /* pGradientFill */
7360 NULL, /* pIntersectClipRect */
7361 NULL, /* pInvertRgn */
7362 NULL, /* pLineTo */
7363 NULL, /* pModifyWorldTransform */
7364 NULL, /* pMoveTo */
7365 NULL, /* pOffsetClipRgn */
7366 NULL, /* pOffsetViewportOrg */
7367 NULL, /* pOffsetWindowOrg */
7368 NULL, /* pPaintRgn */
7369 NULL, /* pPatBlt */
7370 NULL, /* pPie */
7371 NULL, /* pPolyBezier */
7372 NULL, /* pPolyBezierTo */
7373 NULL, /* pPolyDraw */
7374 NULL, /* pPolyPolygon */
7375 NULL, /* pPolyPolyline */
7376 NULL, /* pPolygon */
7377 NULL, /* pPolyline */
7378 NULL, /* pPolylineTo */
7379 NULL, /* pPutImage */
7380 NULL, /* pRealizeDefaultPalette */
7381 NULL, /* pRealizePalette */
7382 NULL, /* pRectangle */
7383 NULL, /* pResetDC */
7384 NULL, /* pRestoreDC */
7385 NULL, /* pRoundRect */
7386 NULL, /* pSaveDC */
7387 NULL, /* pScaleViewportExt */
7388 NULL, /* pScaleWindowExt */
7389 NULL, /* pSelectBitmap */
7390 NULL, /* pSelectBrush */
7391 NULL, /* pSelectClipPath */
7392 freetype_SelectFont, /* pSelectFont */
7393 NULL, /* pSelectPalette */
7394 NULL, /* pSelectPen */
7395 NULL, /* pSetArcDirection */
7396 NULL, /* pSetBkColor */
7397 NULL, /* pSetBkMode */
7398 NULL, /* pSetDCBrushColor */
7399 NULL, /* pSetDCPenColor */
7400 NULL, /* pSetDIBColorTable */
7401 NULL, /* pSetDIBitsToDevice */
7402 NULL, /* pSetDeviceClipping */
7403 NULL, /* pSetDeviceGammaRamp */
7404 NULL, /* pSetLayout */
7405 NULL, /* pSetMapMode */
7406 NULL, /* pSetMapperFlags */
7407 NULL, /* pSetPixel */
7408 NULL, /* pSetPixelFormat */
7409 NULL, /* pSetPolyFillMode */
7410 NULL, /* pSetROP2 */
7411 NULL, /* pSetRelAbs */
7412 NULL, /* pSetStretchBltMode */
7413 NULL, /* pSetTextAlign */
7414 NULL, /* pSetTextCharacterExtra */
7415 NULL, /* pSetTextColor */
7416 NULL, /* pSetTextJustification */
7417 NULL, /* pSetViewportExt */
7418 NULL, /* pSetViewportOrg */
7419 NULL, /* pSetWindowExt */
7420 NULL, /* pSetWindowOrg */
7421 NULL, /* pSetWorldTransform */
7422 NULL, /* pStartDoc */
7423 NULL, /* pStartPage */
7424 NULL, /* pStretchBlt */
7425 NULL, /* pStretchDIBits */
7426 NULL, /* pStrokeAndFillPath */
7427 NULL, /* pStrokePath */
7428 NULL, /* pSwapBuffers */
7429 NULL, /* pUnrealizePalette */
7430 NULL, /* pWidenPath */
7431 /* OpenGL not supported */
7434 #else /* HAVE_FREETYPE */
7436 /*************************************************************************/
7438 BOOL WineEngInit(void)
7440 return FALSE;
7442 BOOL WineEngDestroyFontInstance(HFONT hfont)
7444 return FALSE;
7447 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7449 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7450 return 1;
7453 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7455 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7456 return TRUE;
7459 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7461 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7462 return NULL;
7465 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7467 return FALSE;
7470 /*************************************************************************
7471 * GetRasterizerCaps (GDI32.@)
7473 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7475 lprs->nSize = sizeof(RASTERIZER_STATUS);
7476 lprs->wFlags = 0;
7477 lprs->nLanguageID = 0;
7478 return TRUE;
7481 #endif /* HAVE_FREETYPE */