gdi32: Add a helper to retrieve the ntm flags.
[wine.git] / dlls / gdi32 / freetype.c
blob446175ecc1d717f1fd6cef3214e3363b361f73d9
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 int StyleOrdering(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 /* Add a style of face to a font family using an ordering of the list such
1471 that regular fonts come before bold and italic, and single styles come
1472 before compound styles. */
1473 static void AddFaceToFamily(Face *face, Family *family)
1475 struct list *entry;
1477 LIST_FOR_EACH( entry, &family->faces )
1479 Face *ent = LIST_ENTRY(entry, Face, entry);
1480 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1482 list_add_before( entry, &face->entry );
1485 static WCHAR *prepend_at(WCHAR *family)
1487 WCHAR *str;
1489 if (!family)
1490 return NULL;
1492 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1493 str[0] = '@';
1494 strcpyW(str + 1, family);
1495 HeapFree(GetProcessHeap(), 0, family);
1496 return str;
1499 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1501 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1502 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1504 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1505 if (!*name)
1507 *name = *english;
1508 *english = NULL;
1510 else if (!strcmpiW( *name, *english ))
1512 HeapFree( GetProcessHeap(), 0, *english );
1513 *english = NULL;
1516 if (vertical)
1518 *name = prepend_at( *name );
1519 *english = prepend_at( *english );
1523 /****************************************************************
1524 * NB This function stores the ptrs to the strings to save copying.
1525 * Don't free them after calling.
1527 static Family *create_family( WCHAR *name, WCHAR *english_name )
1529 Family *family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1530 family->FamilyName = name;
1531 family->EnglishName = english_name;
1532 list_init( &family->faces );
1533 family->replacement = &family->faces;
1535 return family;
1538 static Family *get_family( FT_Face ft_face, BOOL vertical )
1540 Family *family;
1541 WCHAR *name, *english_name;
1543 get_family_names( ft_face, &name, &english_name, vertical );
1545 family = find_family_from_name( name );
1547 if (!family)
1549 family = create_family( name, english_name );
1550 list_add_tail( &font_list, &family->entry );
1552 if (english_name)
1554 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1555 subst->from.name = strdupW( english_name );
1556 subst->from.charset = -1;
1557 subst->to.name = strdupW( name );
1558 subst->to.charset = -1;
1559 add_font_subst( &font_subst_list, subst, 0 );
1562 else
1564 HeapFree( GetProcessHeap(), 0, name );
1565 HeapFree( GetProcessHeap(), 0, english_name );
1568 return family;
1571 static inline FT_Fixed get_font_version( FT_Face ft_face )
1573 FT_Fixed version = 0;
1574 TT_Header *header;
1576 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1577 if (header) version = header->Font_Revision;
1579 return version;
1582 static inline DWORD get_ntm_flags( FT_Face ft_face )
1584 DWORD flags = 0;
1585 FT_ULong table_size = 0;
1587 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1588 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1589 if (flags == 0) flags = NTM_REGULAR;
1591 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1592 flags |= NTM_PS_OPENTYPE;
1594 return flags;
1597 #define ADDFONT_EXTERNAL_FONT 0x01
1598 #define ADDFONT_FORCE_BITMAP 0x02
1599 #define ADDFONT_ADD_TO_CACHE 0x04
1601 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size, FT_Long face_index, DWORD flags, BOOL vertical)
1603 int bitmap_num = 0;
1604 Family *family;
1605 WCHAR *StyleW;
1607 do {
1608 TT_OS2 *pOS2;
1609 Face *face;
1610 struct list *face_elem_ptr;
1611 FT_WinFNT_HeaderRec winfnt_header;
1612 int internal_leading;
1613 FONTSIGNATURE fs;
1614 My_FT_Bitmap_Size *size = NULL;
1615 FT_Fixed version;
1617 if(!FT_IS_SCALABLE(ft_face))
1618 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1620 family = get_family( ft_face, vertical );
1622 StyleW = towstr(CP_ACP, ft_face->style_name);
1624 internal_leading = 0;
1625 memset(&fs, 0, sizeof(fs));
1627 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1628 if(pOS2) {
1629 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1630 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1631 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1632 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1633 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1634 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1635 if(pOS2->version == 0) {
1636 FT_UInt dummy;
1638 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1639 fs.fsCsb[0] |= FS_LATIN1;
1640 else
1641 fs.fsCsb[0] |= FS_SYMBOL;
1644 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1645 CHARSETINFO csi;
1646 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1647 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1648 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1649 fs = csi.fs;
1650 internal_leading = winfnt_header.internal_leading;
1653 version = get_font_version( ft_face );
1654 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1655 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1656 if(!strcmpiW(face->StyleName, StyleW) &&
1657 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1658 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1659 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1660 face->font_version, version);
1661 if(version <= face->font_version) {
1662 TRACE("Original font is newer so skipping this one\n");
1663 HeapFree(GetProcessHeap(), 0, StyleW);
1664 return;
1665 } else {
1666 TRACE("Replacing original with this one\n");
1667 list_remove(&face->entry);
1668 HeapFree(GetProcessHeap(), 0, face->file);
1669 HeapFree(GetProcessHeap(), 0, face->StyleName);
1670 HeapFree(GetProcessHeap(), 0, face->FullName);
1671 HeapFree(GetProcessHeap(), 0, face);
1672 break;
1676 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1677 face->cached_enum_data = NULL;
1678 face->StyleName = StyleW;
1679 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1680 if (file)
1682 face->file = strdupA(file);
1683 face->font_data_ptr = NULL;
1684 face->font_data_size = 0;
1686 else
1688 face->file = NULL;
1689 face->font_data_ptr = font_data_ptr;
1690 face->font_data_size = font_data_size;
1692 face->face_index = face_index;
1693 face->ntmFlags = get_ntm_flags( ft_face );
1694 face->font_version = version;
1695 face->family = family;
1696 face->vertical = vertical;
1697 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1698 face->fs = fs;
1700 if(FT_IS_SCALABLE(ft_face)) {
1701 memset(&face->size, 0, sizeof(face->size));
1702 face->scalable = TRUE;
1703 } else {
1704 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1705 size->height, size->width, size->size >> 6,
1706 size->x_ppem >> 6, size->y_ppem >> 6);
1707 face->size.height = size->height;
1708 face->size.width = size->width;
1709 face->size.size = size->size;
1710 face->size.x_ppem = size->x_ppem;
1711 face->size.y_ppem = size->y_ppem;
1712 face->size.internal_leading = internal_leading;
1713 face->scalable = FALSE;
1716 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1717 face->fs.fsCsb[0], face->fs.fsCsb[1],
1718 face->fs.fsUsb[0], face->fs.fsUsb[1],
1719 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1721 if(face->fs.fsCsb[0] == 0)
1723 int i;
1725 /* let's see if we can find any interesting cmaps */
1726 for(i = 0; i < ft_face->num_charmaps; i++) {
1727 switch(ft_face->charmaps[i]->encoding) {
1728 case FT_ENCODING_UNICODE:
1729 case FT_ENCODING_APPLE_ROMAN:
1730 face->fs.fsCsb[0] |= FS_LATIN1;
1731 break;
1732 case FT_ENCODING_MS_SYMBOL:
1733 face->fs.fsCsb[0] |= FS_SYMBOL;
1734 break;
1735 default:
1736 break;
1741 if(flags & ADDFONT_ADD_TO_CACHE)
1742 add_face_to_cache(face);
1744 AddFaceToFamily(face, family);
1746 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1748 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1749 debugstr_w(StyleW));
1752 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1754 FT_Face ft_face;
1755 TT_OS2 *pOS2;
1756 FT_Error err;
1757 FT_Long face_index = 0, num_faces;
1758 INT ret = 0;
1760 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1761 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1763 #ifdef HAVE_CARBON_CARBON_H
1764 if(file)
1766 char **mac_list = expand_mac_font(file);
1767 if(mac_list)
1769 BOOL had_one = FALSE;
1770 char **cursor;
1771 for(cursor = mac_list; *cursor; cursor++)
1773 had_one = TRUE;
1774 AddFontToList(*cursor, NULL, 0, flags);
1775 HeapFree(GetProcessHeap(), 0, *cursor);
1777 HeapFree(GetProcessHeap(), 0, mac_list);
1778 if(had_one)
1779 return 1;
1782 #endif /* HAVE_CARBON_CARBON_H */
1784 do {
1785 if (file)
1787 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1788 err = pFT_New_Face(library, file, face_index, &ft_face);
1789 } else
1791 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1792 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1795 if(err != 0) {
1796 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1797 return 0;
1800 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*/
1801 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1802 pFT_Done_Face(ft_face);
1803 return 0;
1806 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1807 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1808 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1809 pFT_Done_Face(ft_face);
1810 return 0;
1813 if(FT_IS_SFNT(ft_face))
1815 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1816 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1817 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))
1819 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1820 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1821 pFT_Done_Face(ft_face);
1822 return 0;
1825 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1826 we don't want to load these. */
1827 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1829 FT_ULong len = 0;
1831 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1833 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1834 pFT_Done_Face(ft_face);
1835 return 0;
1840 if(!ft_face->family_name || !ft_face->style_name) {
1841 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1842 pFT_Done_Face(ft_face);
1843 return 0;
1846 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1848 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1849 pFT_Done_Face(ft_face);
1850 return 0;
1853 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1854 ++ret;
1856 if (FT_HAS_VERTICAL(ft_face))
1858 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1859 ++ret;
1862 num_faces = ft_face->num_faces;
1863 pFT_Done_Face(ft_face);
1864 } while(num_faces > ++face_index);
1865 return ret;
1868 static void DumpFontList(void)
1870 Family *family;
1871 Face *face;
1872 struct list *family_elem_ptr, *face_elem_ptr;
1874 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1875 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1876 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1877 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1878 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1879 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1880 if(!face->scalable)
1881 TRACE(" %d", face->size.height);
1882 TRACE("\n");
1885 return;
1888 /***********************************************************
1889 * The replacement list is a way to map an entire font
1890 * family onto another family. For example adding
1892 * [HKCU\Software\Wine\Fonts\Replacements]
1893 * "Wingdings"="Winedings"
1895 * would enumerate the Winedings font both as Winedings and
1896 * Wingdings. However if a real Wingdings font is present the
1897 * replacement does not take place.
1900 static void LoadReplaceList(void)
1902 HKEY hkey;
1903 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1904 LPWSTR value;
1905 LPVOID data;
1906 CHAR familyA[400];
1908 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1909 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1911 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1912 &valuelen, &datalen, NULL, NULL);
1914 valuelen++; /* returned value doesn't include room for '\0' */
1915 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1916 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1918 dlen = datalen;
1919 vlen = valuelen;
1920 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1921 &dlen) == ERROR_SUCCESS) {
1922 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1923 /* "NewName"="Oldname" */
1924 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1926 if(!find_family_from_any_name(value))
1928 Family * const family = find_family_from_any_name(data);
1929 if (family != NULL)
1931 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1932 if (new_family != NULL)
1934 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1935 new_family->FamilyName = strdupW(value);
1936 new_family->EnglishName = NULL;
1937 list_init(&new_family->faces);
1938 new_family->replacement = &family->faces;
1939 list_add_tail(&font_list, &new_family->entry);
1942 else
1944 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1947 else
1949 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1951 /* reset dlen and vlen */
1952 dlen = datalen;
1953 vlen = valuelen;
1955 HeapFree(GetProcessHeap(), 0, data);
1956 HeapFree(GetProcessHeap(), 0, value);
1957 RegCloseKey(hkey);
1961 static const WCHAR *font_links_list[] =
1963 Lucida_Sans_Unicode,
1964 Microsoft_Sans_Serif,
1965 Tahoma
1968 static const struct font_links_defaults_list
1970 /* Keyed off substitution for "MS Shell Dlg" */
1971 const WCHAR *shelldlg;
1972 /* Maximum of four substitutes, plus terminating NULL pointer */
1973 const WCHAR *substitutes[5];
1974 } font_links_defaults_list[] =
1976 /* Non East-Asian */
1977 { Tahoma, /* FIXME unverified ordering */
1978 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
1980 /* Below lists are courtesy of
1981 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1983 /* Japanese */
1984 { MS_UI_Gothic,
1985 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
1987 /* Chinese Simplified */
1988 { SimSun,
1989 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
1991 /* Korean */
1992 { Gulim,
1993 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
1995 /* Chinese Traditional */
1996 { PMingLiU,
1997 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2002 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2004 SYSTEM_LINKS *font_link;
2006 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2008 if(!strcmpiW(font_link->font_name, name))
2009 return font_link;
2012 return NULL;
2015 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2017 const WCHAR *value;
2018 int i;
2019 FontSubst *psub;
2020 Family *family;
2021 Face *face;
2022 const char *file;
2023 WCHAR *fileW;
2025 if (values)
2027 SYSTEM_LINKS *font_link;
2029 psub = get_font_subst(&font_subst_list, name, -1);
2030 /* Don't store fonts that are only substitutes for other fonts */
2031 if(psub)
2033 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2034 return;
2037 font_link = find_font_link(name);
2038 if (font_link == NULL)
2040 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2041 font_link->font_name = strdupW(name);
2042 list_init(&font_link->links);
2043 list_add_tail(&system_links, &font_link->entry);
2046 memset(&font_link->fs, 0, sizeof font_link->fs);
2047 for (i = 0; values[i] != NULL; i++)
2049 const struct list *face_list;
2050 CHILD_FONT *child_font;
2052 value = values[i];
2053 if (!strcmpiW(name,value))
2054 continue;
2055 psub = get_font_subst(&font_subst_list, value, -1);
2056 if(psub)
2057 value = psub->to.name;
2058 family = find_family_from_name(value);
2059 if (!family)
2060 continue;
2061 file = NULL;
2062 /* Use first extant filename for this Family */
2063 face_list = get_face_list_from_family(family);
2064 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2066 if (!face->file)
2067 continue;
2068 file = strrchr(face->file, '/');
2069 if (!file)
2070 file = face->file;
2071 else
2072 file++;
2073 break;
2075 if (!file)
2076 continue;
2077 fileW = towstr(CP_UNIXCP, file);
2079 face = find_face_from_filename(fileW, value);
2080 if(!face)
2082 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2083 continue;
2086 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2087 child_font->face = face;
2088 child_font->font = NULL;
2089 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2090 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2091 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2092 list_add_tail(&font_link->links, &child_font->entry);
2094 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2095 HeapFree(GetProcessHeap(), 0, fileW);
2101 /*************************************************************
2102 * init_system_links
2104 static BOOL init_system_links(void)
2106 HKEY hkey;
2107 BOOL ret = FALSE;
2108 DWORD type, max_val, max_data, val_len, data_len, index;
2109 WCHAR *value, *data;
2110 WCHAR *entry, *next;
2111 SYSTEM_LINKS *font_link, *system_font_link;
2112 CHILD_FONT *child_font;
2113 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2114 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2115 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2116 Face *face;
2117 FontSubst *psub;
2118 UINT i, j;
2120 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2122 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2123 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2124 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2125 val_len = max_val + 1;
2126 data_len = max_data;
2127 index = 0;
2128 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2130 psub = get_font_subst(&font_subst_list, value, -1);
2131 /* Don't store fonts that are only substitutes for other fonts */
2132 if(psub)
2134 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2135 goto next;
2137 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2138 font_link->font_name = strdupW(value);
2139 memset(&font_link->fs, 0, sizeof font_link->fs);
2140 list_init(&font_link->links);
2141 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2143 WCHAR *face_name;
2144 CHILD_FONT *child_font;
2146 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2148 next = entry + strlenW(entry) + 1;
2150 face_name = strchrW(entry, ',');
2151 if(face_name)
2153 *face_name++ = 0;
2154 while(isspaceW(*face_name))
2155 face_name++;
2157 psub = get_font_subst(&font_subst_list, face_name, -1);
2158 if(psub)
2159 face_name = psub->to.name;
2161 face = find_face_from_filename(entry, face_name);
2162 if(!face)
2164 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2165 continue;
2168 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2169 child_font->face = face;
2170 child_font->font = NULL;
2171 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2172 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2173 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2174 list_add_tail(&font_link->links, &child_font->entry);
2176 list_add_tail(&system_links, &font_link->entry);
2177 next:
2178 val_len = max_val + 1;
2179 data_len = max_data;
2182 HeapFree(GetProcessHeap(), 0, value);
2183 HeapFree(GetProcessHeap(), 0, data);
2184 RegCloseKey(hkey);
2188 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2189 if (!psub) {
2190 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2191 goto skip_internal;
2194 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2196 const FontSubst *psub2;
2197 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2199 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2201 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2202 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2204 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2205 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2207 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2209 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2213 skip_internal:
2215 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2216 that Tahoma has */
2218 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2219 system_font_link->font_name = strdupW(System);
2220 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2221 list_init(&system_font_link->links);
2223 face = find_face_from_filename(tahoma_ttf, Tahoma);
2224 if(face)
2226 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2227 child_font->face = face;
2228 child_font->font = NULL;
2229 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2230 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2231 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2232 list_add_tail(&system_font_link->links, &child_font->entry);
2234 font_link = find_font_link(Tahoma);
2235 if (font_link != NULL)
2237 CHILD_FONT *font_link_entry;
2238 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2240 CHILD_FONT *new_child;
2241 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2242 new_child->face = font_link_entry->face;
2243 new_child->font = NULL;
2244 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2245 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2246 list_add_tail(&system_font_link->links, &new_child->entry);
2249 list_add_tail(&system_links, &system_font_link->entry);
2250 return ret;
2253 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2255 DIR *dir;
2256 struct dirent *dent;
2257 char path[MAX_PATH];
2259 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2261 dir = opendir(dirname);
2262 if(!dir) {
2263 WARN("Can't open directory %s\n", debugstr_a(dirname));
2264 return FALSE;
2266 while((dent = readdir(dir)) != NULL) {
2267 struct stat statbuf;
2269 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2270 continue;
2272 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2274 sprintf(path, "%s/%s", dirname, dent->d_name);
2276 if(stat(path, &statbuf) == -1)
2278 WARN("Can't stat %s\n", debugstr_a(path));
2279 continue;
2281 if(S_ISDIR(statbuf.st_mode))
2282 ReadFontDir(path, external_fonts);
2283 else
2285 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2286 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2287 AddFontToList(path, NULL, 0, addfont_flags);
2290 closedir(dir);
2291 return TRUE;
2294 static void load_fontconfig_fonts(void)
2296 #ifdef SONAME_LIBFONTCONFIG
2297 void *fc_handle = NULL;
2298 FcConfig *config;
2299 FcPattern *pat;
2300 FcObjectSet *os;
2301 FcFontSet *fontset;
2302 int i, len;
2303 char *file;
2304 const char *ext;
2306 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2307 if(!fc_handle) {
2308 TRACE("Wine cannot find the fontconfig library (%s).\n",
2309 SONAME_LIBFONTCONFIG);
2310 return;
2312 #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;}
2313 LOAD_FUNCPTR(FcConfigGetCurrent);
2314 LOAD_FUNCPTR(FcFontList);
2315 LOAD_FUNCPTR(FcFontSetDestroy);
2316 LOAD_FUNCPTR(FcInit);
2317 LOAD_FUNCPTR(FcObjectSetAdd);
2318 LOAD_FUNCPTR(FcObjectSetCreate);
2319 LOAD_FUNCPTR(FcObjectSetDestroy);
2320 LOAD_FUNCPTR(FcPatternCreate);
2321 LOAD_FUNCPTR(FcPatternDestroy);
2322 LOAD_FUNCPTR(FcPatternGetBool);
2323 LOAD_FUNCPTR(FcPatternGetString);
2324 #undef LOAD_FUNCPTR
2326 if(!pFcInit()) return;
2328 config = pFcConfigGetCurrent();
2329 pat = pFcPatternCreate();
2330 os = pFcObjectSetCreate();
2331 pFcObjectSetAdd(os, FC_FILE);
2332 pFcObjectSetAdd(os, FC_SCALABLE);
2333 fontset = pFcFontList(config, pat, os);
2334 if(!fontset) return;
2335 for(i = 0; i < fontset->nfont; i++) {
2336 FcBool scalable;
2338 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2339 continue;
2340 TRACE("fontconfig: %s\n", file);
2342 /* We're just interested in OT/TT fonts for now, so this hack just
2343 picks up the scalable fonts without extensions .pf[ab] to save time
2344 loading every other font */
2346 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2348 TRACE("not scalable\n");
2349 continue;
2352 len = strlen( file );
2353 if(len < 4) continue;
2354 ext = &file[ len - 3 ];
2355 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2356 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2358 pFcFontSetDestroy(fontset);
2359 pFcObjectSetDestroy(os);
2360 pFcPatternDestroy(pat);
2361 sym_not_found:
2362 #endif
2363 return;
2366 static BOOL load_font_from_data_dir(LPCWSTR file)
2368 BOOL ret = FALSE;
2369 const char *data_dir = wine_get_data_dir();
2371 if (!data_dir) data_dir = wine_get_build_dir();
2373 if (data_dir)
2375 INT len;
2376 char *unix_name;
2378 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2380 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2382 strcpy(unix_name, data_dir);
2383 strcat(unix_name, "/fonts/");
2385 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2387 EnterCriticalSection( &freetype_cs );
2388 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2389 LeaveCriticalSection( &freetype_cs );
2390 HeapFree(GetProcessHeap(), 0, unix_name);
2392 return ret;
2395 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2397 static const WCHAR slashW[] = {'\\','\0'};
2398 BOOL ret = FALSE;
2399 WCHAR windowsdir[MAX_PATH];
2400 char *unixname;
2402 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2403 strcatW(windowsdir, fontsW);
2404 strcatW(windowsdir, slashW);
2405 strcatW(windowsdir, file);
2406 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2407 EnterCriticalSection( &freetype_cs );
2408 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2409 LeaveCriticalSection( &freetype_cs );
2410 HeapFree(GetProcessHeap(), 0, unixname);
2412 return ret;
2415 static void load_system_fonts(void)
2417 HKEY hkey;
2418 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2419 const WCHAR * const *value;
2420 DWORD dlen, type;
2421 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2422 char *unixname;
2424 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2425 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2426 strcatW(windowsdir, fontsW);
2427 for(value = SystemFontValues; *value; value++) {
2428 dlen = sizeof(data);
2429 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2430 type == REG_SZ) {
2431 BOOL added = FALSE;
2433 sprintfW(pathW, fmtW, windowsdir, data);
2434 if((unixname = wine_get_unix_file_name(pathW))) {
2435 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2436 HeapFree(GetProcessHeap(), 0, unixname);
2438 if (!added)
2439 load_font_from_data_dir(data);
2442 RegCloseKey(hkey);
2446 /*************************************************************
2448 * This adds registry entries for any externally loaded fonts
2449 * (fonts from fontconfig or FontDirs). It also deletes entries
2450 * of no longer existing fonts.
2453 static void update_reg_entries(void)
2455 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2456 LPWSTR valueW;
2457 DWORD len, len_fam;
2458 Family *family;
2459 Face *face;
2460 struct list *family_elem_ptr, *face_elem_ptr;
2461 WCHAR *file;
2462 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2463 static const WCHAR spaceW[] = {' ', '\0'};
2464 char *path;
2466 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2467 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2468 ERR("Can't create Windows font reg key\n");
2469 goto end;
2472 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2473 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2474 ERR("Can't create Windows font reg key\n");
2475 goto end;
2478 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2479 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2480 ERR("Can't create external font reg key\n");
2481 goto end;
2484 /* enumerate the fonts and add external ones to the two keys */
2486 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2487 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2488 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2489 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2490 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2491 if(!face->external) continue;
2492 len = len_fam;
2493 if (!(face->ntmFlags & NTM_REGULAR))
2494 len = len_fam + strlenW(face->StyleName) + 1;
2495 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2496 strcpyW(valueW, family->FamilyName);
2497 if(len != len_fam) {
2498 strcatW(valueW, spaceW);
2499 strcatW(valueW, face->StyleName);
2501 strcatW(valueW, TrueType);
2503 file = wine_get_dos_file_name(face->file);
2504 if(file)
2505 len = strlenW(file) + 1;
2506 else
2508 if((path = strrchr(face->file, '/')) == NULL)
2509 path = face->file;
2510 else
2511 path++;
2512 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2514 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2515 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2517 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2518 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2519 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2521 HeapFree(GetProcessHeap(), 0, file);
2522 HeapFree(GetProcessHeap(), 0, valueW);
2525 end:
2526 if(external_key) RegCloseKey(external_key);
2527 if(win9x_key) RegCloseKey(win9x_key);
2528 if(winnt_key) RegCloseKey(winnt_key);
2529 return;
2532 static void delete_external_font_keys(void)
2534 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2535 DWORD dlen, vlen, datalen, valuelen, i, type;
2536 LPWSTR valueW;
2537 LPVOID data;
2539 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2540 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2541 ERR("Can't create Windows font reg key\n");
2542 goto end;
2545 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2546 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2547 ERR("Can't create Windows font reg key\n");
2548 goto end;
2551 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2552 ERR("Can't create external font reg key\n");
2553 goto end;
2556 /* Delete all external fonts added last time */
2558 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2559 &valuelen, &datalen, NULL, NULL);
2560 valuelen++; /* returned value doesn't include room for '\0' */
2561 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2562 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2564 dlen = datalen * sizeof(WCHAR);
2565 vlen = valuelen;
2566 i = 0;
2567 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2568 &dlen) == ERROR_SUCCESS) {
2570 RegDeleteValueW(winnt_key, valueW);
2571 RegDeleteValueW(win9x_key, valueW);
2572 /* reset dlen and vlen */
2573 dlen = datalen;
2574 vlen = valuelen;
2576 HeapFree(GetProcessHeap(), 0, data);
2577 HeapFree(GetProcessHeap(), 0, valueW);
2579 /* Delete the old external fonts key */
2580 RegCloseKey(external_key);
2581 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2583 end:
2584 if(win9x_key) RegCloseKey(win9x_key);
2585 if(winnt_key) RegCloseKey(winnt_key);
2588 /*************************************************************
2589 * WineEngAddFontResourceEx
2592 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2594 INT ret = 0;
2596 GDI_CheckNotLock();
2598 if (ft_handle) /* do it only if we have freetype up and running */
2600 char *unixname;
2602 if(flags)
2603 FIXME("Ignoring flags %x\n", flags);
2605 if((unixname = wine_get_unix_file_name(file)))
2607 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2609 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2610 EnterCriticalSection( &freetype_cs );
2611 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2612 LeaveCriticalSection( &freetype_cs );
2613 HeapFree(GetProcessHeap(), 0, unixname);
2615 if (!ret && !strchrW(file, '\\')) {
2616 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2617 ret = load_font_from_winfonts_dir(file);
2618 if (!ret) {
2619 /* Try in datadir/fonts (or builddir/fonts),
2620 * needed for Magic the Gathering Online
2622 ret = load_font_from_data_dir(file);
2626 return ret;
2629 /*************************************************************
2630 * WineEngAddFontMemResourceEx
2633 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2635 GDI_CheckNotLock();
2637 if (ft_handle) /* do it only if we have freetype up and running */
2639 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2641 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2642 memcpy(pFontCopy, pbFont, cbFont);
2644 EnterCriticalSection( &freetype_cs );
2645 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2646 LeaveCriticalSection( &freetype_cs );
2648 if (*pcFonts == 0)
2650 TRACE("AddFontToList failed\n");
2651 HeapFree(GetProcessHeap(), 0, pFontCopy);
2652 return 0;
2654 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2655 * For now return something unique but quite random
2657 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2658 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2661 *pcFonts = 0;
2662 return 0;
2665 /*************************************************************
2666 * WineEngRemoveFontResourceEx
2669 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2671 GDI_CheckNotLock();
2672 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2673 return TRUE;
2676 static const struct nls_update_font_list
2678 UINT ansi_cp, oem_cp;
2679 const char *oem, *fixed, *system;
2680 const char *courier, *serif, *small, *sserif;
2681 /* these are for font substitutes */
2682 const char *shelldlg, *tmsrmn;
2683 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2684 *helv_0, *tmsrmn_0;
2685 const struct subst
2687 const char *from, *to;
2688 } arial_0, courier_new_0, times_new_roman_0;
2689 } nls_update_font_list[] =
2691 /* Latin 1 (United States) */
2692 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2693 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2694 "Tahoma","Times New Roman",
2695 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2696 { 0 }, { 0 }, { 0 }
2698 /* Latin 1 (Multilingual) */
2699 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2700 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2701 "Tahoma","Times New Roman", /* FIXME unverified */
2702 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2703 { 0 }, { 0 }, { 0 }
2705 /* Eastern Europe */
2706 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2707 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2708 "Tahoma","Times New Roman", /* FIXME unverified */
2709 "Fixedsys,238", "System,238",
2710 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2711 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2712 { "Arial CE,0", "Arial,238" },
2713 { "Courier New CE,0", "Courier New,238" },
2714 { "Times New Roman CE,0", "Times New Roman,238" }
2716 /* Cyrillic */
2717 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2718 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2719 "Tahoma","Times New Roman", /* FIXME unverified */
2720 "Fixedsys,204", "System,204",
2721 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2722 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2723 { "Arial Cyr,0", "Arial,204" },
2724 { "Courier New Cyr,0", "Courier New,204" },
2725 { "Times New Roman Cyr,0", "Times New Roman,204" }
2727 /* Greek */
2728 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2729 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2730 "Tahoma","Times New Roman", /* FIXME unverified */
2731 "Fixedsys,161", "System,161",
2732 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2733 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2734 { "Arial Greek,0", "Arial,161" },
2735 { "Courier New Greek,0", "Courier New,161" },
2736 { "Times New Roman Greek,0", "Times New Roman,161" }
2738 /* Turkish */
2739 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2740 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2741 "Tahoma","Times New Roman", /* FIXME unverified */
2742 "Fixedsys,162", "System,162",
2743 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2744 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2745 { "Arial Tur,0", "Arial,162" },
2746 { "Courier New Tur,0", "Courier New,162" },
2747 { "Times New Roman Tur,0", "Times New Roman,162" }
2749 /* Hebrew */
2750 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2751 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2752 "Tahoma","Times New Roman", /* FIXME unverified */
2753 "Fixedsys,177", "System,177",
2754 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2755 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2756 { 0 }, { 0 }, { 0 }
2758 /* Arabic */
2759 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2760 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2761 "Tahoma","Times New Roman", /* FIXME unverified */
2762 "Fixedsys,178", "System,178",
2763 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2764 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2765 { 0 }, { 0 }, { 0 }
2767 /* Baltic */
2768 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2769 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2770 "Tahoma","Times New Roman", /* FIXME unverified */
2771 "Fixedsys,186", "System,186",
2772 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2773 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2774 { "Arial Baltic,0", "Arial,186" },
2775 { "Courier New Baltic,0", "Courier New,186" },
2776 { "Times New Roman Baltic,0", "Times New Roman,186" }
2778 /* Vietnamese */
2779 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2780 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2781 "Tahoma","Times New Roman", /* FIXME unverified */
2782 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2783 { 0 }, { 0 }, { 0 }
2785 /* Thai */
2786 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2787 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2788 "Tahoma","Times New Roman", /* FIXME unverified */
2789 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2790 { 0 }, { 0 }, { 0 }
2792 /* Japanese */
2793 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2794 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2795 "MS UI Gothic","MS Serif",
2796 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2797 { 0 }, { 0 }, { 0 }
2799 /* Chinese Simplified */
2800 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2801 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2802 "SimSun", "NSimSun",
2803 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2804 { 0 }, { 0 }, { 0 }
2806 /* Korean */
2807 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2808 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2809 "Gulim", "Batang",
2810 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2811 { 0 }, { 0 }, { 0 }
2813 /* Chinese Traditional */
2814 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2815 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2816 "PMingLiU", "MingLiU",
2817 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2818 { 0 }, { 0 }, { 0 }
2822 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2824 return ( ansi_cp == 932 /* CP932 for Japanese */
2825 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2826 || ansi_cp == 949 /* CP949 for Korean */
2827 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2830 static inline HKEY create_fonts_NT_registry_key(void)
2832 HKEY hkey = 0;
2834 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2835 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2836 return hkey;
2839 static inline HKEY create_fonts_9x_registry_key(void)
2841 HKEY hkey = 0;
2843 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2844 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2845 return hkey;
2848 static inline HKEY create_config_fonts_registry_key(void)
2850 HKEY hkey = 0;
2852 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2853 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2854 return hkey;
2857 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2859 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2860 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2861 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2862 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2865 static void set_value_key(HKEY hkey, const char *name, const char *value)
2867 if (value)
2868 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2869 else if (name)
2870 RegDeleteValueA(hkey, name);
2873 static void update_font_info(void)
2875 char buf[40], cpbuf[40];
2876 DWORD len, type;
2877 HKEY hkey = 0;
2878 UINT i, ansi_cp = 0, oem_cp = 0;
2879 BOOL done = FALSE;
2881 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2882 return;
2884 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2885 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2886 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2887 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2888 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2890 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2891 if (is_dbcs_ansi_cp(ansi_cp))
2892 use_default_fallback = TRUE;
2894 len = sizeof(buf);
2895 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2897 if (!strcmp( buf, cpbuf )) /* already set correctly */
2899 RegCloseKey(hkey);
2900 return;
2902 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2904 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2906 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2907 RegCloseKey(hkey);
2909 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2911 HKEY hkey;
2913 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2914 nls_update_font_list[i].oem_cp == oem_cp)
2916 hkey = create_config_fonts_registry_key();
2917 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2918 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2919 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2920 RegCloseKey(hkey);
2922 hkey = create_fonts_NT_registry_key();
2923 add_font_list(hkey, &nls_update_font_list[i]);
2924 RegCloseKey(hkey);
2926 hkey = create_fonts_9x_registry_key();
2927 add_font_list(hkey, &nls_update_font_list[i]);
2928 RegCloseKey(hkey);
2930 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2932 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2933 strlen(nls_update_font_list[i].shelldlg)+1);
2934 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2935 strlen(nls_update_font_list[i].tmsrmn)+1);
2937 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2938 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2939 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2940 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2941 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2942 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2943 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2944 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2946 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2947 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2948 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2950 RegCloseKey(hkey);
2952 done = TRUE;
2954 else
2956 /* Delete the FontSubstitutes from other locales */
2957 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2959 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2960 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2961 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2962 RegCloseKey(hkey);
2966 if (!done)
2967 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2970 static BOOL init_freetype(void)
2972 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2973 if(!ft_handle) {
2974 WINE_MESSAGE(
2975 "Wine cannot find the FreeType font library. To enable Wine to\n"
2976 "use TrueType fonts please install a version of FreeType greater than\n"
2977 "or equal to 2.0.5.\n"
2978 "http://www.freetype.org\n");
2979 return FALSE;
2982 #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;}
2984 LOAD_FUNCPTR(FT_Done_Face)
2985 LOAD_FUNCPTR(FT_Get_Char_Index)
2986 LOAD_FUNCPTR(FT_Get_First_Char)
2987 LOAD_FUNCPTR(FT_Get_Module)
2988 LOAD_FUNCPTR(FT_Get_Next_Char)
2989 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2990 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2991 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2992 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2993 LOAD_FUNCPTR(FT_Init_FreeType)
2994 LOAD_FUNCPTR(FT_Library_Version)
2995 LOAD_FUNCPTR(FT_Load_Glyph)
2996 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2997 LOAD_FUNCPTR(FT_Matrix_Multiply)
2998 #ifndef FT_MULFIX_INLINED
2999 LOAD_FUNCPTR(FT_MulFix)
3000 #endif
3001 LOAD_FUNCPTR(FT_New_Face)
3002 LOAD_FUNCPTR(FT_New_Memory_Face)
3003 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3004 LOAD_FUNCPTR(FT_Outline_Transform)
3005 LOAD_FUNCPTR(FT_Outline_Translate)
3006 LOAD_FUNCPTR(FT_Render_Glyph)
3007 LOAD_FUNCPTR(FT_Select_Charmap)
3008 LOAD_FUNCPTR(FT_Set_Charmap)
3009 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3010 LOAD_FUNCPTR(FT_Vector_Transform)
3011 LOAD_FUNCPTR(FT_Vector_Unit)
3012 #undef LOAD_FUNCPTR
3013 /* Don't warn if these ones are missing */
3014 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3015 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3016 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3017 #endif
3019 if(pFT_Init_FreeType(&library) != 0) {
3020 ERR("Can't init FreeType library\n");
3021 wine_dlclose(ft_handle, NULL, 0);
3022 ft_handle = NULL;
3023 return FALSE;
3025 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3027 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3028 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3029 ((FT_Version.minor << 8) & 0x00ff00) |
3030 ((FT_Version.patch ) & 0x0000ff);
3032 font_driver = &freetype_funcs;
3033 return TRUE;
3035 sym_not_found:
3036 WINE_MESSAGE(
3037 "Wine cannot find certain functions that it needs inside the FreeType\n"
3038 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3039 "FreeType to at least version 2.1.4.\n"
3040 "http://www.freetype.org\n");
3041 wine_dlclose(ft_handle, NULL, 0);
3042 ft_handle = NULL;
3043 return FALSE;
3046 static void init_font_list(void)
3048 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3049 static const WCHAR pathW[] = {'P','a','t','h',0};
3050 HKEY hkey;
3051 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3052 WCHAR windowsdir[MAX_PATH];
3053 char *unixname;
3054 const char *home;
3055 const char *data_dir;
3057 delete_external_font_keys();
3059 /* load the system bitmap fonts */
3060 load_system_fonts();
3062 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3063 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3064 strcatW(windowsdir, fontsW);
3065 if((unixname = wine_get_unix_file_name(windowsdir)))
3067 ReadFontDir(unixname, FALSE);
3068 HeapFree(GetProcessHeap(), 0, unixname);
3071 /* load the system truetype fonts */
3072 data_dir = wine_get_data_dir();
3073 if (!data_dir) data_dir = wine_get_build_dir();
3074 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3076 strcpy(unixname, data_dir);
3077 strcat(unixname, "/fonts/");
3078 ReadFontDir(unixname, TRUE);
3079 HeapFree(GetProcessHeap(), 0, unixname);
3082 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3083 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3084 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3085 will skip these. */
3086 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3087 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3088 &hkey) == ERROR_SUCCESS)
3090 LPWSTR data, valueW;
3091 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3092 &valuelen, &datalen, NULL, NULL);
3094 valuelen++; /* returned value doesn't include room for '\0' */
3095 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3096 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3097 if (valueW && data)
3099 dlen = datalen * sizeof(WCHAR);
3100 vlen = valuelen;
3101 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3102 &dlen) == ERROR_SUCCESS)
3104 if(data[0] && (data[1] == ':'))
3106 if((unixname = wine_get_unix_file_name(data)))
3108 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3109 HeapFree(GetProcessHeap(), 0, unixname);
3112 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3114 WCHAR pathW[MAX_PATH];
3115 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3116 BOOL added = FALSE;
3118 sprintfW(pathW, fmtW, windowsdir, data);
3119 if((unixname = wine_get_unix_file_name(pathW)))
3121 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3122 HeapFree(GetProcessHeap(), 0, unixname);
3124 if (!added)
3125 load_font_from_data_dir(data);
3127 /* reset dlen and vlen */
3128 dlen = datalen;
3129 vlen = valuelen;
3132 HeapFree(GetProcessHeap(), 0, data);
3133 HeapFree(GetProcessHeap(), 0, valueW);
3134 RegCloseKey(hkey);
3137 load_fontconfig_fonts();
3139 /* then look in any directories that we've specified in the config file */
3140 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3141 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3143 DWORD len;
3144 LPWSTR valueW;
3145 LPSTR valueA, ptr;
3147 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3149 len += sizeof(WCHAR);
3150 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3151 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3153 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3154 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3155 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3156 TRACE( "got font path %s\n", debugstr_a(valueA) );
3157 ptr = valueA;
3158 while (ptr)
3160 LPSTR next = strchr( ptr, ':' );
3161 if (next) *next++ = 0;
3162 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3163 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3165 strcpy( unixname, home );
3166 strcat( unixname, ptr + 1 );
3167 ReadFontDir( unixname, TRUE );
3168 HeapFree( GetProcessHeap(), 0, unixname );
3170 else
3171 ReadFontDir( ptr, TRUE );
3172 ptr = next;
3174 HeapFree( GetProcessHeap(), 0, valueA );
3176 HeapFree( GetProcessHeap(), 0, valueW );
3178 RegCloseKey(hkey);
3181 #ifdef __APPLE__
3182 /* Mac default font locations. */
3183 ReadFontDir( "/Library/Fonts", TRUE );
3184 ReadFontDir( "/Network/Library/Fonts", TRUE );
3185 ReadFontDir( "/System/Library/Fonts", TRUE );
3186 if ((home = getenv( "HOME" )))
3188 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3189 strcpy( unixname, home );
3190 strcat( unixname, "/Library/Fonts" );
3191 ReadFontDir( unixname, TRUE);
3192 HeapFree( GetProcessHeap(), 0, unixname );
3194 #endif
3197 static BOOL move_to_front(const WCHAR *name)
3199 Family *family, *cursor2;
3200 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3202 if(!strcmpiW(family->FamilyName, name))
3204 list_remove(&family->entry);
3205 list_add_head(&font_list, &family->entry);
3206 return TRUE;
3209 return FALSE;
3212 static BOOL set_default(const WCHAR **name_list)
3214 while (*name_list)
3216 if (move_to_front(*name_list)) return TRUE;
3217 name_list++;
3220 return FALSE;
3223 static void reorder_font_list(void)
3225 set_default( default_serif_list );
3226 set_default( default_fixed_list );
3227 set_default( default_sans_list );
3230 /*************************************************************
3231 * WineEngInit
3233 * Initialize FreeType library and create a list of available faces
3235 BOOL WineEngInit(void)
3237 HKEY hkey_font_cache;
3238 DWORD disposition;
3239 HANDLE font_mutex;
3241 /* update locale dependent font info in registry */
3242 update_font_info();
3244 if(!init_freetype()) return FALSE;
3246 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3248 ERR("Failed to create font mutex\n");
3249 return FALSE;
3251 WaitForSingleObject(font_mutex, INFINITE);
3253 create_font_cache_key(&hkey_font_cache, &disposition);
3255 if(disposition == REG_CREATED_NEW_KEY)
3256 init_font_list();
3257 else
3258 load_font_list_from_cache(hkey_font_cache);
3260 RegCloseKey(hkey_font_cache);
3262 reorder_font_list();
3264 DumpFontList();
3265 LoadSubstList();
3266 DumpSubstList();
3267 LoadReplaceList();
3269 if(disposition == REG_CREATED_NEW_KEY)
3270 update_reg_entries();
3272 init_system_links();
3274 ReleaseMutex(font_mutex);
3275 return TRUE;
3279 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3281 TT_OS2 *pOS2;
3282 TT_HoriHeader *pHori;
3284 LONG ppem;
3286 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3287 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3289 if(height == 0) height = 16;
3291 /* Calc. height of EM square:
3293 * For +ve lfHeight we have
3294 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3295 * Re-arranging gives:
3296 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3298 * For -ve lfHeight we have
3299 * |lfHeight| = ppem
3300 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3301 * with il = winAscent + winDescent - units_per_em]
3305 if(height > 0) {
3306 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3307 ppem = MulDiv(ft_face->units_per_EM, height,
3308 pHori->Ascender - pHori->Descender);
3309 else
3310 ppem = MulDiv(ft_face->units_per_EM, height,
3311 pOS2->usWinAscent + pOS2->usWinDescent);
3313 else
3314 ppem = -height;
3316 return ppem;
3319 static struct font_mapping *map_font_file( const char *name )
3321 struct font_mapping *mapping;
3322 struct stat st;
3323 int fd;
3325 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3326 if (fstat( fd, &st ) == -1) goto error;
3328 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3330 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3332 mapping->refcount++;
3333 close( fd );
3334 return mapping;
3337 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3338 goto error;
3340 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3341 close( fd );
3343 if (mapping->data == MAP_FAILED)
3345 HeapFree( GetProcessHeap(), 0, mapping );
3346 return NULL;
3348 mapping->refcount = 1;
3349 mapping->dev = st.st_dev;
3350 mapping->ino = st.st_ino;
3351 mapping->size = st.st_size;
3352 list_add_tail( &mappings_list, &mapping->entry );
3353 return mapping;
3355 error:
3356 close( fd );
3357 return NULL;
3360 static void unmap_font_file( struct font_mapping *mapping )
3362 if (!--mapping->refcount)
3364 list_remove( &mapping->entry );
3365 munmap( mapping->data, mapping->size );
3366 HeapFree( GetProcessHeap(), 0, mapping );
3370 static LONG load_VDMX(GdiFont*, LONG);
3372 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3374 FT_Error err;
3375 FT_Face ft_face;
3376 void *data_ptr;
3377 DWORD data_size;
3379 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3381 if (face->file)
3383 if (!(font->mapping = map_font_file( face->file )))
3385 WARN("failed to map %s\n", debugstr_a(face->file));
3386 return 0;
3388 data_ptr = font->mapping->data;
3389 data_size = font->mapping->size;
3391 else
3393 data_ptr = face->font_data_ptr;
3394 data_size = face->font_data_size;
3397 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3398 if(err) {
3399 ERR("FT_New_Face rets %d\n", err);
3400 return 0;
3403 /* set it here, as load_VDMX needs it */
3404 font->ft_face = ft_face;
3406 if(FT_IS_SCALABLE(ft_face)) {
3407 /* load the VDMX table if we have one */
3408 font->ppem = load_VDMX(font, height);
3409 if(font->ppem == 0)
3410 font->ppem = calc_ppem_for_height(ft_face, height);
3411 TRACE("height %d => ppem %d\n", height, font->ppem);
3413 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3414 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3415 } else {
3416 font->ppem = height;
3417 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3418 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3420 return ft_face;
3424 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3426 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3427 a single face with the requested charset. The idea is to check if
3428 the selected font supports the current ANSI codepage, if it does
3429 return the corresponding charset, else return the first charset */
3431 CHARSETINFO csi;
3432 int acp = GetACP(), i;
3433 DWORD fs0;
3435 *cp = acp;
3436 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3438 const SYSTEM_LINKS *font_link;
3440 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3441 return csi.ciCharset;
3443 font_link = find_font_link(family_name);
3444 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3445 return csi.ciCharset;
3448 for(i = 0; i < 32; i++) {
3449 fs0 = 1L << i;
3450 if(face->fs.fsCsb[0] & fs0) {
3451 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3452 *cp = csi.ciACP;
3453 return csi.ciCharset;
3455 else
3456 FIXME("TCI failing on %x\n", fs0);
3460 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3461 face->fs.fsCsb[0], face->file);
3462 *cp = acp;
3463 return DEFAULT_CHARSET;
3466 static GdiFont *alloc_font(void)
3468 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3469 ret->gmsize = 1;
3470 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3471 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3472 ret->potm = NULL;
3473 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3474 ret->total_kern_pairs = (DWORD)-1;
3475 ret->kern_pairs = NULL;
3476 list_init(&ret->hfontlist);
3477 list_init(&ret->child_fonts);
3478 return ret;
3481 static void free_font(GdiFont *font)
3483 struct list *cursor, *cursor2;
3484 DWORD i;
3486 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3488 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3489 list_remove(cursor);
3490 if(child->font)
3491 free_font(child->font);
3492 HeapFree(GetProcessHeap(), 0, child);
3495 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3497 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3498 DeleteObject(hfontlist->hfont);
3499 list_remove(&hfontlist->entry);
3500 HeapFree(GetProcessHeap(), 0, hfontlist);
3503 if (font->ft_face) pFT_Done_Face(font->ft_face);
3504 if (font->mapping) unmap_font_file( font->mapping );
3505 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3506 HeapFree(GetProcessHeap(), 0, font->potm);
3507 HeapFree(GetProcessHeap(), 0, font->name);
3508 for (i = 0; i < font->gmsize; i++)
3509 HeapFree(GetProcessHeap(),0,font->gm[i]);
3510 HeapFree(GetProcessHeap(), 0, font->gm);
3511 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3512 HeapFree(GetProcessHeap(), 0, font);
3516 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3518 FT_Face ft_face = font->ft_face;
3519 FT_ULong len;
3520 FT_Error err;
3522 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3524 if(!buf)
3525 len = 0;
3526 else
3527 len = cbData;
3529 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3531 /* make sure value of len is the value freetype says it needs */
3532 if (buf && len)
3534 FT_ULong needed = 0;
3535 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3536 if( !err && needed < len) len = needed;
3538 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3539 if (err)
3541 TRACE("Can't find table %c%c%c%c\n",
3542 /* bytes were reversed */
3543 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3544 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3545 return GDI_ERROR;
3547 return len;
3550 /*************************************************************
3551 * load_VDMX
3553 * load the vdmx entry for the specified height
3556 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3557 ( ( (FT_ULong)_x4 << 24 ) | \
3558 ( (FT_ULong)_x3 << 16 ) | \
3559 ( (FT_ULong)_x2 << 8 ) | \
3560 (FT_ULong)_x1 )
3562 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3564 typedef struct {
3565 BYTE bCharSet;
3566 BYTE xRatio;
3567 BYTE yStartRatio;
3568 BYTE yEndRatio;
3569 } Ratios;
3571 typedef struct {
3572 WORD recs;
3573 BYTE startsz;
3574 BYTE endsz;
3575 } VDMX_group;
3577 static LONG load_VDMX(GdiFont *font, LONG height)
3579 WORD hdr[3], tmp;
3580 VDMX_group group;
3581 BYTE devXRatio, devYRatio;
3582 USHORT numRecs, numRatios;
3583 DWORD result, offset = -1;
3584 LONG ppem = 0;
3585 int i;
3587 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3589 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3590 return ppem;
3592 /* FIXME: need the real device aspect ratio */
3593 devXRatio = 1;
3594 devYRatio = 1;
3596 numRecs = GET_BE_WORD(hdr[1]);
3597 numRatios = GET_BE_WORD(hdr[2]);
3599 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3600 for(i = 0; i < numRatios; i++) {
3601 Ratios ratio;
3603 offset = (3 * 2) + (i * sizeof(Ratios));
3604 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3605 offset = -1;
3607 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3609 if((ratio.xRatio == 0 &&
3610 ratio.yStartRatio == 0 &&
3611 ratio.yEndRatio == 0) ||
3612 (devXRatio == ratio.xRatio &&
3613 devYRatio >= ratio.yStartRatio &&
3614 devYRatio <= ratio.yEndRatio))
3616 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3617 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3618 offset = GET_BE_WORD(tmp);
3619 break;
3623 if(offset == -1) {
3624 FIXME("No suitable ratio found\n");
3625 return ppem;
3628 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3629 USHORT recs;
3630 BYTE startsz, endsz;
3631 WORD *vTable;
3633 recs = GET_BE_WORD(group.recs);
3634 startsz = group.startsz;
3635 endsz = group.endsz;
3637 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3639 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3640 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3641 if(result == GDI_ERROR) {
3642 FIXME("Failed to retrieve vTable\n");
3643 goto end;
3646 if(height > 0) {
3647 for(i = 0; i < recs; i++) {
3648 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3649 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3650 ppem = GET_BE_WORD(vTable[i * 3]);
3652 if(yMax + -yMin == height) {
3653 font->yMax = yMax;
3654 font->yMin = yMin;
3655 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3656 break;
3658 if(yMax + -yMin > height) {
3659 if(--i < 0) {
3660 ppem = 0;
3661 goto end; /* failed */
3663 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3664 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3665 ppem = GET_BE_WORD(vTable[i * 3]);
3666 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3667 break;
3670 if(!font->yMax) {
3671 ppem = 0;
3672 TRACE("ppem not found for height %d\n", height);
3675 end:
3676 HeapFree(GetProcessHeap(), 0, vTable);
3679 return ppem;
3682 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3684 if(font->font_desc.hash != fd->hash) return TRUE;
3685 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3686 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3687 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3688 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3691 static void calc_hash(FONT_DESC *pfd)
3693 DWORD hash = 0, *ptr, two_chars;
3694 WORD *pwc;
3695 unsigned int i;
3697 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3698 hash ^= *ptr;
3699 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3700 hash ^= *ptr;
3701 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3702 two_chars = *ptr;
3703 pwc = (WCHAR *)&two_chars;
3704 if(!*pwc) break;
3705 *pwc = toupperW(*pwc);
3706 pwc++;
3707 *pwc = toupperW(*pwc);
3708 hash ^= two_chars;
3709 if(!*pwc) break;
3711 hash ^= !pfd->can_use_bitmap;
3712 pfd->hash = hash;
3713 return;
3716 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3718 GdiFont *ret;
3719 FONT_DESC fd;
3720 HFONTLIST *hflist;
3721 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3723 fd.lf = *plf;
3724 fd.matrix = *pmat;
3725 fd.can_use_bitmap = can_use_bitmap;
3726 calc_hash(&fd);
3728 /* try the child list */
3729 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3730 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3731 if(!fontcmp(ret, &fd)) {
3732 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3733 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3734 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3735 if(hflist->hfont == hfont)
3736 return ret;
3741 /* try the in-use list */
3742 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3743 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3744 if(!fontcmp(ret, &fd)) {
3745 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3746 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3747 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3748 if(hflist->hfont == hfont)
3749 return ret;
3751 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3752 hflist->hfont = hfont;
3753 list_add_head(&ret->hfontlist, &hflist->entry);
3754 return ret;
3758 /* then the unused list */
3759 font_elem_ptr = list_head(&unused_gdi_font_list);
3760 while(font_elem_ptr) {
3761 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3762 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3763 if(!fontcmp(ret, &fd)) {
3764 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3765 assert(list_empty(&ret->hfontlist));
3766 TRACE("Found %p in unused list\n", ret);
3767 list_remove(&ret->entry);
3768 list_add_head(&gdi_font_list, &ret->entry);
3769 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3770 hflist->hfont = hfont;
3771 list_add_head(&ret->hfontlist, &hflist->entry);
3772 return ret;
3775 return NULL;
3778 static void add_to_cache(GdiFont *font)
3780 static DWORD cache_num = 1;
3782 font->cache_num = cache_num++;
3783 list_add_head(&gdi_font_list, &font->entry);
3786 /*************************************************************
3787 * create_child_font_list
3789 static BOOL create_child_font_list(GdiFont *font)
3791 BOOL ret = FALSE;
3792 SYSTEM_LINKS *font_link;
3793 CHILD_FONT *font_link_entry, *new_child;
3794 FontSubst *psub;
3795 WCHAR* font_name;
3797 psub = get_font_subst(&font_subst_list, font->name, -1);
3798 font_name = psub ? psub->to.name : font->name;
3799 font_link = find_font_link(font_name);
3800 if (font_link != NULL)
3802 TRACE("found entry in system list\n");
3803 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3805 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3806 new_child->face = font_link_entry->face;
3807 new_child->font = NULL;
3808 list_add_tail(&font->child_fonts, &new_child->entry);
3809 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3811 ret = TRUE;
3814 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3815 * Sans Serif. This is how asian windows get default fallbacks for fonts
3817 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3818 font->charset != OEM_CHARSET &&
3819 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3821 font_link = find_font_link(szDefaultFallbackLink);
3822 if (font_link != NULL)
3824 TRACE("found entry in default fallback list\n");
3825 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3827 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3828 new_child->face = font_link_entry->face;
3829 new_child->font = NULL;
3830 list_add_tail(&font->child_fonts, &new_child->entry);
3831 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3833 ret = TRUE;
3837 return ret;
3840 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3842 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3844 if (pFT_Set_Charmap)
3846 FT_Int i;
3847 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3849 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3851 for (i = 0; i < ft_face->num_charmaps; i++)
3853 if (ft_face->charmaps[i]->encoding == encoding)
3855 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3856 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3858 switch (ft_face->charmaps[i]->platform_id)
3860 default:
3861 cmap_def = ft_face->charmaps[i];
3862 break;
3863 case 0: /* Apple Unicode */
3864 cmap0 = ft_face->charmaps[i];
3865 break;
3866 case 1: /* Macintosh */
3867 cmap1 = ft_face->charmaps[i];
3868 break;
3869 case 2: /* ISO */
3870 cmap2 = ft_face->charmaps[i];
3871 break;
3872 case 3: /* Microsoft */
3873 cmap3 = ft_face->charmaps[i];
3874 break;
3878 if (cmap3) /* prefer Microsoft cmap table */
3879 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3880 else if (cmap1)
3881 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3882 else if (cmap2)
3883 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3884 else if (cmap0)
3885 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3886 else if (cmap_def)
3887 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3889 return ft_err == FT_Err_Ok;
3892 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3896 /*************************************************************
3897 * freetype_CreateDC
3899 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3900 LPCWSTR output, const DEVMODEW *devmode )
3902 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3904 if (!physdev) return FALSE;
3905 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3906 return TRUE;
3910 /*************************************************************
3911 * freetype_DeleteDC
3913 static BOOL freetype_DeleteDC( PHYSDEV dev )
3915 struct freetype_physdev *physdev = get_freetype_dev( dev );
3916 HeapFree( GetProcessHeap(), 0, physdev );
3917 return TRUE;
3921 /*************************************************************
3922 * freetype_SelectFont
3924 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3926 struct freetype_physdev *physdev = get_freetype_dev( dev );
3927 GdiFont *ret;
3928 Face *face, *best, *best_bitmap;
3929 Family *family, *last_resort_family;
3930 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
3931 INT height, width = 0;
3932 unsigned int score = 0, new_score;
3933 signed int diff = 0, newdiff;
3934 BOOL bd, it, can_use_bitmap, want_vertical;
3935 LOGFONTW lf;
3936 CHARSETINFO csi;
3937 HFONTLIST *hflist;
3938 FMAT2 dcmat;
3939 FontSubst *psub = NULL;
3940 DC *dc = get_dc_ptr( dev->hdc );
3941 const SYSTEM_LINKS *font_link;
3943 if (!hfont) /* notification that the font has been changed by another driver */
3945 dc->gdiFont = NULL;
3946 physdev->font = NULL;
3947 release_dc_ptr( dc );
3948 return 0;
3951 GetObjectW( hfont, sizeof(lf), &lf );
3952 lf.lfWidth = abs(lf.lfWidth);
3954 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3956 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3957 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3958 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3959 lf.lfEscapement);
3961 if(dc->GraphicsMode == GM_ADVANCED)
3963 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3964 /* Try to avoid not necessary glyph transformations */
3965 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3967 lf.lfHeight *= fabs(dcmat.eM11);
3968 lf.lfWidth *= fabs(dcmat.eM11);
3969 dcmat.eM11 = dcmat.eM22 = 1.0;
3972 else
3974 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3975 font scaling abilities. */
3976 dcmat.eM11 = dcmat.eM22 = 1.0;
3977 dcmat.eM21 = dcmat.eM12 = 0;
3978 if (dc->vport2WorldValid)
3980 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
3981 lf.lfOrientation = -lf.lfOrientation;
3982 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
3983 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
3987 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3988 dcmat.eM21, dcmat.eM22);
3990 GDI_CheckNotLock();
3991 EnterCriticalSection( &freetype_cs );
3993 /* check the cache first */
3994 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3995 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3996 goto done;
3999 if(list_empty(&font_list)) /* No fonts installed */
4001 TRACE("No fonts installed\n");
4002 goto done;
4005 TRACE("not in cache\n");
4006 ret = alloc_font();
4008 ret->font_desc.matrix = dcmat;
4009 ret->font_desc.lf = lf;
4010 ret->font_desc.can_use_bitmap = can_use_bitmap;
4011 calc_hash(&ret->font_desc);
4012 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4013 hflist->hfont = hfont;
4014 list_add_head(&ret->hfontlist, &hflist->entry);
4016 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4017 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4018 original value lfCharSet. Note this is a special case for
4019 Symbol and doesn't happen at least for "Wingdings*" */
4021 if(!strcmpiW(lf.lfFaceName, SymbolW))
4022 lf.lfCharSet = SYMBOL_CHARSET;
4024 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4025 switch(lf.lfCharSet) {
4026 case DEFAULT_CHARSET:
4027 csi.fs.fsCsb[0] = 0;
4028 break;
4029 default:
4030 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4031 csi.fs.fsCsb[0] = 0;
4032 break;
4036 family = NULL;
4037 if(lf.lfFaceName[0] != '\0') {
4038 CHILD_FONT *font_link_entry;
4039 LPWSTR FaceName = lf.lfFaceName;
4041 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4043 if(psub) {
4044 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4045 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4046 if (psub->to.charset != -1)
4047 lf.lfCharSet = psub->to.charset;
4050 /* We want a match on name and charset or just name if
4051 charset was DEFAULT_CHARSET. If the latter then
4052 we fixup the returned charset later in get_nearest_charset
4053 where we'll either use the charset of the current ansi codepage
4054 or if that's unavailable the first charset that the font supports.
4056 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4057 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4058 if (!strcmpiW(family->FamilyName, FaceName) ||
4059 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4061 font_link = find_font_link(family->FamilyName);
4062 face_list = get_face_list_from_family(family);
4063 LIST_FOR_EACH(face_elem_ptr, face_list) {
4064 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4065 if (!(face->scalable || can_use_bitmap))
4066 continue;
4067 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4068 goto found;
4069 if (font_link != NULL &&
4070 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4071 goto found;
4072 if (!csi.fs.fsCsb[0])
4073 goto found;
4078 /* Search by full face name. */
4079 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4080 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4081 face_list = get_face_list_from_family(family);
4082 LIST_FOR_EACH(face_elem_ptr, face_list) {
4083 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4084 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4085 (face->scalable || can_use_bitmap))
4087 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4088 goto found_face;
4089 font_link = find_font_link(family->FamilyName);
4090 if (font_link != NULL &&
4091 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4092 goto found_face;
4098 * Try check the SystemLink list first for a replacement font.
4099 * We may find good replacements there.
4101 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4103 if(!strcmpiW(font_link->font_name, FaceName) ||
4104 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4106 TRACE("found entry in system list\n");
4107 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4109 const SYSTEM_LINKS *links;
4111 face = font_link_entry->face;
4112 if (!(face->scalable || can_use_bitmap))
4113 continue;
4114 family = face->family;
4115 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4116 goto found;
4117 links = find_font_link(family->FamilyName);
4118 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4119 goto found;
4125 psub = NULL; /* substitution is no more relevant */
4127 /* If requested charset was DEFAULT_CHARSET then try using charset
4128 corresponding to the current ansi codepage */
4129 if (!csi.fs.fsCsb[0])
4131 INT acp = GetACP();
4132 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4133 FIXME("TCI failed on codepage %d\n", acp);
4134 csi.fs.fsCsb[0] = 0;
4135 } else
4136 lf.lfCharSet = csi.ciCharset;
4139 want_vertical = (lf.lfFaceName[0] == '@');
4141 /* Face families are in the top 4 bits of lfPitchAndFamily,
4142 so mask with 0xF0 before testing */
4144 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4145 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4146 strcpyW(lf.lfFaceName, defFixed);
4147 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4148 strcpyW(lf.lfFaceName, defSerif);
4149 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4150 strcpyW(lf.lfFaceName, defSans);
4151 else
4152 strcpyW(lf.lfFaceName, defSans);
4153 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4154 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4155 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4156 font_link = find_font_link(family->FamilyName);
4157 face_list = get_face_list_from_family(family);
4158 LIST_FOR_EACH(face_elem_ptr, face_list) {
4159 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4160 if (!(face->scalable || can_use_bitmap))
4161 continue;
4162 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4163 goto found;
4164 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4165 goto found;
4170 last_resort_family = NULL;
4171 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4172 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4173 font_link = find_font_link(family->FamilyName);
4174 face_list = get_face_list_from_family(family);
4175 LIST_FOR_EACH(face_elem_ptr, face_list) {
4176 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4177 if(face->vertical == want_vertical &&
4178 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4179 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4180 if(face->scalable)
4181 goto found;
4182 if(can_use_bitmap && !last_resort_family)
4183 last_resort_family = family;
4188 if(last_resort_family) {
4189 family = last_resort_family;
4190 csi.fs.fsCsb[0] = 0;
4191 goto found;
4194 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4195 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4196 face_list = get_face_list_from_family(family);
4197 LIST_FOR_EACH(face_elem_ptr, face_list) {
4198 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4199 if(face->scalable && face->vertical == want_vertical) {
4200 csi.fs.fsCsb[0] = 0;
4201 WARN("just using first face for now\n");
4202 goto found;
4204 if(can_use_bitmap && !last_resort_family)
4205 last_resort_family = family;
4208 if(!last_resort_family) {
4209 FIXME("can't find a single appropriate font - bailing\n");
4210 free_font(ret);
4211 ret = NULL;
4212 goto done;
4215 WARN("could only find a bitmap font - this will probably look awful!\n");
4216 family = last_resort_family;
4217 csi.fs.fsCsb[0] = 0;
4219 found:
4220 it = lf.lfItalic ? 1 : 0;
4221 bd = lf.lfWeight > 550 ? 1 : 0;
4223 height = lf.lfHeight;
4225 face = best = best_bitmap = NULL;
4226 font_link = find_font_link(family->FamilyName);
4227 face_list = get_face_list_from_family(family);
4228 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4230 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4231 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4232 !csi.fs.fsCsb[0])
4234 BOOL italic, bold;
4236 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4237 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4238 new_score = (italic ^ it) + (bold ^ bd);
4239 if(!best || new_score <= score)
4241 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4242 italic, bold, it, bd);
4243 score = new_score;
4244 best = face;
4245 if(best->scalable && score == 0) break;
4246 if(!best->scalable)
4248 if(height > 0)
4249 newdiff = height - (signed int)(best->size.height);
4250 else
4251 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4252 if(!best_bitmap || new_score < score ||
4253 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4255 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4256 diff = newdiff;
4257 best_bitmap = best;
4258 if(score == 0 && diff == 0) break;
4264 if(best)
4265 face = best->scalable ? best : best_bitmap;
4266 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4267 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4269 found_face:
4270 height = lf.lfHeight;
4272 ret->fs = face->fs;
4274 if(csi.fs.fsCsb[0]) {
4275 ret->charset = lf.lfCharSet;
4276 ret->codepage = csi.ciACP;
4278 else
4279 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4281 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4282 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4284 ret->aveWidth = height ? lf.lfWidth : 0;
4286 if(!face->scalable) {
4287 /* Windows uses integer scaling factors for bitmap fonts */
4288 INT scale, scaled_height;
4289 GdiFont *cachedfont;
4291 /* FIXME: rotation of bitmap fonts is ignored */
4292 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4293 if (ret->aveWidth)
4294 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4295 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4296 dcmat.eM11 = dcmat.eM22 = 1.0;
4297 /* As we changed the matrix, we need to search the cache for the font again,
4298 * otherwise we might explode the cache. */
4299 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4300 TRACE("Found cached font after non-scalable matrix rescale!\n");
4301 free_font( ret );
4302 ret = cachedfont;
4303 goto done;
4305 calc_hash(&ret->font_desc);
4307 if (height != 0) height = diff;
4308 height += face->size.height;
4310 scale = (height + face->size.height - 1) / face->size.height;
4311 scaled_height = scale * face->size.height;
4312 /* Only jump to the next height if the difference <= 25% original height */
4313 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4314 /* The jump between unscaled and doubled is delayed by 1 */
4315 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4316 ret->scale_y = scale;
4318 width = face->size.x_ppem >> 6;
4319 height = face->size.y_ppem >> 6;
4321 else
4322 ret->scale_y = 1.0;
4323 TRACE("font scale y: %f\n", ret->scale_y);
4325 ret->ft_face = OpenFontFace(ret, face, width, height);
4327 if (!ret->ft_face)
4329 free_font( ret );
4330 ret = NULL;
4331 goto done;
4334 ret->ntmFlags = face->ntmFlags;
4336 if (ret->charset == SYMBOL_CHARSET &&
4337 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4338 /* No ops */
4340 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4341 /* No ops */
4343 else {
4344 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4347 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4348 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4349 ret->underline = lf.lfUnderline ? 0xff : 0;
4350 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4351 create_child_font_list(ret);
4353 if (face->vertical) /* We need to try to load the GSUB table */
4355 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4356 if (length != GDI_ERROR)
4358 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4359 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4360 TRACE("Loaded GSUB table of %i bytes\n",length);
4364 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4366 add_to_cache(ret);
4367 done:
4368 if (ret)
4370 dc->gdiFont = ret;
4371 physdev->font = ret;
4373 LeaveCriticalSection( &freetype_cs );
4374 release_dc_ptr( dc );
4375 return ret ? hfont : 0;
4378 static void dump_gdi_font_list(void)
4380 GdiFont *gdiFont;
4381 struct list *elem_ptr;
4383 TRACE("---------- gdiFont Cache ----------\n");
4384 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4385 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4386 TRACE("gdiFont=%p %s %d\n",
4387 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4390 TRACE("---------- Unused gdiFont Cache ----------\n");
4391 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4392 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4393 TRACE("gdiFont=%p %s %d\n",
4394 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4397 TRACE("---------- Child gdiFont Cache ----------\n");
4398 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4399 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4400 TRACE("gdiFont=%p %s %d\n",
4401 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4405 /*************************************************************
4406 * WineEngDestroyFontInstance
4408 * free the gdiFont associated with this handle
4411 BOOL WineEngDestroyFontInstance(HFONT handle)
4413 GdiFont *gdiFont;
4414 HFONTLIST *hflist;
4415 BOOL ret = FALSE;
4416 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4417 int i = 0;
4419 GDI_CheckNotLock();
4420 EnterCriticalSection( &freetype_cs );
4422 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4424 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4425 while(hfontlist_elem_ptr) {
4426 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4427 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4428 if(hflist->hfont == handle) {
4429 TRACE("removing child font %p from child list\n", gdiFont);
4430 list_remove(&gdiFont->entry);
4431 LeaveCriticalSection( &freetype_cs );
4432 return TRUE;
4437 TRACE("destroying hfont=%p\n", handle);
4438 if(TRACE_ON(font))
4439 dump_gdi_font_list();
4441 font_elem_ptr = list_head(&gdi_font_list);
4442 while(font_elem_ptr) {
4443 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4444 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4446 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4447 while(hfontlist_elem_ptr) {
4448 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4449 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4450 if(hflist->hfont == handle) {
4451 list_remove(&hflist->entry);
4452 HeapFree(GetProcessHeap(), 0, hflist);
4453 ret = TRUE;
4456 if(list_empty(&gdiFont->hfontlist)) {
4457 TRACE("Moving to Unused list\n");
4458 list_remove(&gdiFont->entry);
4459 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4464 font_elem_ptr = list_head(&unused_gdi_font_list);
4465 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4466 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4467 while(font_elem_ptr) {
4468 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4469 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4470 TRACE("freeing %p\n", gdiFont);
4471 list_remove(&gdiFont->entry);
4472 free_font(gdiFont);
4474 LeaveCriticalSection( &freetype_cs );
4475 return ret;
4478 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4480 HRSRC rsrc;
4481 HGLOBAL hMem;
4482 WCHAR *p;
4483 int i;
4485 id += IDS_FIRST_SCRIPT;
4486 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4487 if (!rsrc) return 0;
4488 hMem = LoadResource( gdi32_module, rsrc );
4489 if (!hMem) return 0;
4491 p = LockResource( hMem );
4492 id &= 0x000f;
4493 while (id--) p += *p + 1;
4495 i = min(LF_FACESIZE - 1, *p);
4496 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4497 buffer[i] = 0;
4498 return i;
4502 /***************************************************
4503 * create_enum_charset_list
4505 * This function creates charset enumeration list because in DEFAULT_CHARSET
4506 * case, the ANSI codepage's charset takes precedence over other charsets.
4507 * This function works as a filter other than DEFAULT_CHARSET case.
4509 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4511 CHARSETINFO csi;
4512 DWORD n = 0;
4514 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4515 csi.fs.fsCsb[0] != 0) {
4516 list->element[n].mask = csi.fs.fsCsb[0];
4517 list->element[n].charset = csi.ciCharset;
4518 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4519 n++;
4521 else { /* charset is DEFAULT_CHARSET or invalid. */
4522 INT acp, i;
4524 /* Set the current codepage's charset as the first element. */
4525 acp = GetACP();
4526 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4527 csi.fs.fsCsb[0] != 0) {
4528 list->element[n].mask = csi.fs.fsCsb[0];
4529 list->element[n].charset = csi.ciCharset;
4530 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4531 n++;
4534 /* Fill out left elements. */
4535 for (i = 0; i < 32; i++) {
4536 FONTSIGNATURE fs;
4537 fs.fsCsb[0] = 1L << i;
4538 fs.fsCsb[1] = 0;
4539 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4540 continue; /* skip, already added. */
4541 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4542 continue; /* skip, this is an invalid fsCsb bit. */
4544 list->element[n].mask = fs.fsCsb[0];
4545 list->element[n].charset = csi.ciCharset;
4546 load_script_name( i, list->element[n].name );
4547 n++;
4550 list->total = n;
4552 return n;
4555 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4556 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4558 GdiFont *font;
4559 LONG width, height;
4561 if (face->cached_enum_data)
4563 TRACE("Cached\n");
4564 *pelf = face->cached_enum_data->elf;
4565 *pntm = face->cached_enum_data->ntm;
4566 *ptype = face->cached_enum_data->type;
4567 return;
4570 font = alloc_font();
4572 if(face->scalable) {
4573 height = -2048; /* 2048 is the most common em size */
4574 width = 0;
4575 } else {
4576 height = face->size.y_ppem >> 6;
4577 width = face->size.x_ppem >> 6;
4579 font->scale_y = 1.0;
4581 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4583 free_font(font);
4584 return;
4587 font->name = strdupW(face->family->FamilyName);
4588 font->ntmFlags = face->ntmFlags;
4590 if (get_outline_text_metrics(font))
4592 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4594 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4596 lstrcpynW(pelf->elfLogFont.lfFaceName,
4597 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4598 LF_FACESIZE);
4599 lstrcpynW(pelf->elfFullName,
4600 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4601 LF_FULLFACESIZE);
4602 lstrcpynW(pelf->elfStyle,
4603 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4604 LF_FACESIZE);
4606 else
4608 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4610 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4612 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4613 if (face->FullName)
4614 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4615 else
4616 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4617 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4620 pntm->ntmTm.ntmFlags = face->ntmFlags;
4621 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4622 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4623 pntm->ntmFontSig = face->fs;
4625 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4627 pelf->elfLogFont.lfEscapement = 0;
4628 pelf->elfLogFont.lfOrientation = 0;
4629 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4630 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4631 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4632 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4633 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4634 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4635 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4636 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4637 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4638 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4639 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4641 *ptype = 0;
4642 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4643 *ptype |= TRUETYPE_FONTTYPE;
4644 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4645 *ptype |= DEVICE_FONTTYPE;
4646 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4647 *ptype |= RASTER_FONTTYPE;
4649 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4650 if (face->cached_enum_data)
4652 face->cached_enum_data->elf = *pelf;
4653 face->cached_enum_data->ntm = *pntm;
4654 face->cached_enum_data->type = *ptype;
4657 free_font(font);
4660 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
4662 static const WCHAR spaceW[] = { ' ', 0 };
4664 strcpyW(full_name, family_name);
4665 strcatW(full_name, spaceW);
4666 strcatW(full_name, style_name);
4669 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4671 const struct list *face_list, *face_elem_ptr;
4673 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4675 face_list = get_face_list_from_family(family);
4676 LIST_FOR_EACH(face_elem_ptr, face_list)
4678 WCHAR full_family_name[LF_FULLFACESIZE];
4679 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4681 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4683 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4684 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4685 continue;
4688 create_full_name(full_family_name, family->FamilyName, face->StyleName);
4689 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4692 return FALSE;
4695 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
4697 WCHAR full_family_name[LF_FULLFACESIZE];
4699 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
4701 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4703 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4704 debugstr_w(family_name), debugstr_w(face->StyleName));
4705 return FALSE;
4708 create_full_name(full_family_name, family_name, face->StyleName);
4709 return !strcmpiW(lf->lfFaceName, full_family_name);
4712 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
4713 FONTENUMPROCW proc, LPARAM lparam)
4715 ENUMLOGFONTEXW elf;
4716 NEWTEXTMETRICEXW ntm;
4717 DWORD type = 0;
4718 int i;
4720 GetEnumStructs(face, &elf, &ntm, &type);
4721 for(i = 0; i < list->total; i++) {
4722 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4723 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4724 load_script_name( IDS_OEM_DOS, elf.elfScript );
4725 i = list->total; /* break out of loop after enumeration */
4726 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4727 continue;
4728 else {
4729 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4730 strcpyW(elf.elfScript, list->element[i].name);
4731 if (!elf.elfScript[0])
4732 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4734 /* Font Replacement */
4735 if (family != face->family)
4737 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
4738 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
4740 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4741 debugstr_w(elf.elfLogFont.lfFaceName),
4742 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4743 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4744 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4745 ntm.ntmTm.ntmFlags);
4746 /* release section before callback (FIXME) */
4747 LeaveCriticalSection( &freetype_cs );
4748 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4749 EnterCriticalSection( &freetype_cs );
4751 return TRUE;
4754 /*************************************************************
4755 * freetype_EnumFonts
4757 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4759 Family *family;
4760 Face *face;
4761 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4762 LOGFONTW lf;
4763 struct enum_charset_list enum_charsets;
4765 if (!plf)
4767 lf.lfCharSet = DEFAULT_CHARSET;
4768 lf.lfPitchAndFamily = 0;
4769 lf.lfFaceName[0] = 0;
4770 plf = &lf;
4773 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4775 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4777 GDI_CheckNotLock();
4778 EnterCriticalSection( &freetype_cs );
4779 if(plf->lfFaceName[0]) {
4780 FontSubst *psub;
4781 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4783 if(psub) {
4784 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4785 debugstr_w(psub->to.name));
4786 lf = *plf;
4787 strcpyW(lf.lfFaceName, psub->to.name);
4788 plf = &lf;
4791 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4792 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4793 if(family_matches(family, plf)) {
4794 face_list = get_face_list_from_family(family);
4795 LIST_FOR_EACH(face_elem_ptr, face_list) {
4796 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4797 if (!face_matches(family->FamilyName, face, plf)) continue;
4798 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4802 } else {
4803 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4804 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4805 face_list = get_face_list_from_family(family);
4806 face_elem_ptr = list_head(face_list);
4807 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4808 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4811 LeaveCriticalSection( &freetype_cs );
4812 return TRUE;
4815 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4817 pt->x.value = vec->x >> 6;
4818 pt->x.fract = (vec->x & 0x3f) << 10;
4819 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4820 pt->y.value = vec->y >> 6;
4821 pt->y.fract = (vec->y & 0x3f) << 10;
4822 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4823 return;
4826 /***************************************************
4827 * According to the MSDN documentation on WideCharToMultiByte,
4828 * certain codepages cannot set the default_used parameter.
4829 * This returns TRUE if the codepage can set that parameter, false else
4830 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4832 static BOOL codepage_sets_default_used(UINT codepage)
4834 switch (codepage)
4836 case CP_UTF7:
4837 case CP_UTF8:
4838 case CP_SYMBOL:
4839 return FALSE;
4840 default:
4841 return TRUE;
4846 * GSUB Table handling functions
4849 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4851 const GSUB_CoverageFormat1* cf1;
4853 cf1 = table;
4855 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4857 int count = GET_BE_WORD(cf1->GlyphCount);
4858 int i;
4859 TRACE("Coverage Format 1, %i glyphs\n",count);
4860 for (i = 0; i < count; i++)
4861 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4862 return i;
4863 return -1;
4865 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4867 const GSUB_CoverageFormat2* cf2;
4868 int i;
4869 int count;
4870 cf2 = (const GSUB_CoverageFormat2*)cf1;
4872 count = GET_BE_WORD(cf2->RangeCount);
4873 TRACE("Coverage Format 2, %i ranges\n",count);
4874 for (i = 0; i < count; i++)
4876 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4877 return -1;
4878 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4879 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4881 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4882 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4885 return -1;
4887 else
4888 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4890 return -1;
4893 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4895 const GSUB_ScriptList *script;
4896 const GSUB_Script *deflt = NULL;
4897 int i;
4898 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4900 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4901 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4903 const GSUB_Script *scr;
4904 int offset;
4906 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4907 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4909 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4910 return scr;
4911 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4912 deflt = scr;
4914 return deflt;
4917 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4919 int i;
4920 int offset;
4921 const GSUB_LangSys *Lang;
4923 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4925 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4927 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4928 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4930 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4931 return Lang;
4933 offset = GET_BE_WORD(script->DefaultLangSys);
4934 if (offset)
4936 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4937 return Lang;
4939 return NULL;
4942 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4944 int i;
4945 const GSUB_FeatureList *feature;
4946 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4948 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4949 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4951 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4952 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4954 const GSUB_Feature *feat;
4955 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4956 return feat;
4959 return NULL;
4962 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4964 int i;
4965 int offset;
4966 const GSUB_LookupList *lookup;
4967 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4969 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4970 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4972 const GSUB_LookupTable *look;
4973 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4974 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4975 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4976 if (GET_BE_WORD(look->LookupType) != 1)
4977 FIXME("We only handle SubType 1\n");
4978 else
4980 int j;
4982 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4984 const GSUB_SingleSubstFormat1 *ssf1;
4985 offset = GET_BE_WORD(look->SubTable[j]);
4986 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4987 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4989 int offset = GET_BE_WORD(ssf1->Coverage);
4990 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4991 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4993 TRACE(" Glyph 0x%x ->",glyph);
4994 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4995 TRACE(" 0x%x\n",glyph);
4998 else
5000 const GSUB_SingleSubstFormat2 *ssf2;
5001 INT index;
5002 INT offset;
5004 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5005 offset = GET_BE_WORD(ssf1->Coverage);
5006 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5007 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5008 TRACE(" Coverage index %i\n",index);
5009 if (index != -1)
5011 TRACE(" Glyph is 0x%x ->",glyph);
5012 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5013 TRACE("0x%x\n",glyph);
5019 return glyph;
5022 static const char* get_opentype_script(const GdiFont *font)
5025 * I am not sure if this is the correct way to generate our script tag
5028 switch (font->charset)
5030 case ANSI_CHARSET: return "latn";
5031 case BALTIC_CHARSET: return "latn"; /* ?? */
5032 case CHINESEBIG5_CHARSET: return "hani";
5033 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5034 case GB2312_CHARSET: return "hani";
5035 case GREEK_CHARSET: return "grek";
5036 case HANGUL_CHARSET: return "hang";
5037 case RUSSIAN_CHARSET: return "cyrl";
5038 case SHIFTJIS_CHARSET: return "kana";
5039 case TURKISH_CHARSET: return "latn"; /* ?? */
5040 case VIETNAMESE_CHARSET: return "latn";
5041 case JOHAB_CHARSET: return "latn"; /* ?? */
5042 case ARABIC_CHARSET: return "arab";
5043 case HEBREW_CHARSET: return "hebr";
5044 case THAI_CHARSET: return "thai";
5045 default: return "latn";
5049 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5051 const GSUB_Header *header;
5052 const GSUB_Script *script;
5053 const GSUB_LangSys *language;
5054 const GSUB_Feature *feature;
5056 if (!font->GSUB_Table)
5057 return glyph;
5059 header = font->GSUB_Table;
5061 script = GSUB_get_script_table(header, get_opentype_script(font));
5062 if (!script)
5064 TRACE("Script not found\n");
5065 return glyph;
5067 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5068 if (!language)
5070 TRACE("Language not found\n");
5071 return glyph;
5073 feature = GSUB_get_feature(header, language, "vrt2");
5074 if (!feature)
5075 feature = GSUB_get_feature(header, language, "vert");
5076 if (!feature)
5078 TRACE("vrt2/vert feature not found\n");
5079 return glyph;
5081 return GSUB_apply_feature(header, feature, glyph);
5084 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5086 FT_UInt glyphId;
5088 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5089 WCHAR wc = (WCHAR)glyph;
5090 BOOL default_used;
5091 BOOL *default_used_pointer;
5092 FT_UInt ret;
5093 char buf;
5094 default_used_pointer = NULL;
5095 default_used = FALSE;
5096 if (codepage_sets_default_used(font->codepage))
5097 default_used_pointer = &default_used;
5098 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5099 ret = 0;
5100 else
5101 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5102 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5103 return ret;
5106 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5108 if (glyph < 0x100) glyph += 0xf000;
5109 /* there is a number of old pre-Unicode "broken" TTFs, which
5110 do have symbols at U+00XX instead of U+f0XX */
5111 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5112 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5114 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5116 return glyphId;
5119 /*************************************************************
5120 * freetype_GetGlyphIndices
5122 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5124 struct freetype_physdev *physdev = get_freetype_dev( dev );
5125 int i;
5126 WORD default_char;
5127 BOOL got_default = FALSE;
5129 if (!physdev->font)
5131 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5132 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5135 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5137 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5138 got_default = TRUE;
5141 GDI_CheckNotLock();
5142 EnterCriticalSection( &freetype_cs );
5144 for(i = 0; i < count; i++)
5146 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5147 if (pgi[i] == 0)
5149 if (!got_default)
5151 if (FT_IS_SFNT(physdev->font->ft_face))
5153 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5154 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5156 else
5158 TEXTMETRICW textm;
5159 get_text_metrics(physdev->font, &textm);
5160 default_char = textm.tmDefaultChar;
5162 got_default = TRUE;
5164 pgi[i] = default_char;
5167 LeaveCriticalSection( &freetype_cs );
5168 return count;
5171 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5173 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5174 return !memcmp(matrix, &identity, sizeof(FMAT2));
5177 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5179 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5180 return !memcmp(matrix, &identity, sizeof(MAT2));
5183 static inline BYTE get_max_level( UINT format )
5185 switch( format )
5187 case GGO_GRAY2_BITMAP: return 4;
5188 case GGO_GRAY4_BITMAP: return 16;
5189 case GGO_GRAY8_BITMAP: return 64;
5191 return 255;
5194 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5196 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5197 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5198 const MAT2* lpmat)
5200 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5201 FT_Face ft_face = incoming_font->ft_face;
5202 GdiFont *font = incoming_font;
5203 FT_UInt glyph_index;
5204 DWORD width, height, pitch, needed = 0;
5205 FT_Bitmap ft_bitmap;
5206 FT_Error err;
5207 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5208 FT_Angle angle = 0;
5209 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5210 double widthRatio = 1.0;
5211 FT_Matrix transMat = identityMat;
5212 FT_Matrix transMatUnrotated;
5213 BOOL needsTransform = FALSE;
5214 BOOL tategaki = (font->GSUB_Table != NULL);
5215 UINT original_index;
5217 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5218 buflen, buf, lpmat);
5220 TRACE("font transform %f %f %f %f\n",
5221 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5222 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5224 if(format & GGO_GLYPH_INDEX) {
5225 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5226 original_index = glyph;
5227 format &= ~GGO_GLYPH_INDEX;
5228 } else {
5229 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5230 ft_face = font->ft_face;
5231 original_index = glyph_index;
5234 if(format & GGO_UNHINTED) {
5235 load_flags |= FT_LOAD_NO_HINTING;
5236 format &= ~GGO_UNHINTED;
5239 /* tategaki never appears to happen to lower glyph index */
5240 if (glyph_index < TATEGAKI_LOWER_BOUND )
5241 tategaki = FALSE;
5243 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5244 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5245 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5246 font->gmsize * sizeof(GM*));
5247 } else {
5248 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5249 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5251 *lpgm = FONT_GM(font,original_index)->gm;
5252 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5253 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5254 lpgm->gmCellIncX, lpgm->gmCellIncY);
5255 return 1; /* FIXME */
5259 if (!font->gm[original_index / GM_BLOCK_SIZE])
5260 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5262 /* Scaling factor */
5263 if (font->aveWidth)
5265 TEXTMETRICW tm;
5267 get_text_metrics(font, &tm);
5269 widthRatio = (double)font->aveWidth;
5270 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5272 else
5273 widthRatio = font->scale_y;
5275 /* Scaling transform */
5276 if (widthRatio != 1.0 || font->scale_y != 1.0)
5278 FT_Matrix scaleMat;
5279 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5280 scaleMat.xy = 0;
5281 scaleMat.yx = 0;
5282 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5284 pFT_Matrix_Multiply(&scaleMat, &transMat);
5285 needsTransform = TRUE;
5288 /* Slant transform */
5289 if (font->fake_italic) {
5290 FT_Matrix slantMat;
5292 slantMat.xx = (1 << 16);
5293 slantMat.xy = ((1 << 16) >> 2);
5294 slantMat.yx = 0;
5295 slantMat.yy = (1 << 16);
5296 pFT_Matrix_Multiply(&slantMat, &transMat);
5297 needsTransform = TRUE;
5300 /* Rotation transform */
5301 transMatUnrotated = transMat;
5302 if(font->orientation && !tategaki) {
5303 FT_Matrix rotationMat;
5304 FT_Vector vecAngle;
5305 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5306 pFT_Vector_Unit(&vecAngle, angle);
5307 rotationMat.xx = vecAngle.x;
5308 rotationMat.xy = -vecAngle.y;
5309 rotationMat.yx = -rotationMat.xy;
5310 rotationMat.yy = rotationMat.xx;
5312 pFT_Matrix_Multiply(&rotationMat, &transMat);
5313 needsTransform = TRUE;
5316 /* World transform */
5317 if (!is_identity_FMAT2(&font->font_desc.matrix))
5319 FT_Matrix worldMat;
5320 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5321 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5322 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5323 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5324 pFT_Matrix_Multiply(&worldMat, &transMat);
5325 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5326 needsTransform = TRUE;
5329 /* Extra transformation specified by caller */
5330 if (!is_identity_MAT2(lpmat))
5332 FT_Matrix extraMat;
5333 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5334 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5335 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5336 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5337 pFT_Matrix_Multiply(&extraMat, &transMat);
5338 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5339 needsTransform = TRUE;
5342 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5343 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5344 format == GGO_GRAY8_BITMAP))
5346 load_flags |= FT_LOAD_NO_BITMAP;
5349 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5351 if(err) {
5352 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5353 return GDI_ERROR;
5356 if(!needsTransform) {
5357 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5358 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5359 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5361 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5362 bottom = (ft_face->glyph->metrics.horiBearingY -
5363 ft_face->glyph->metrics.height) & -64;
5364 lpgm->gmCellIncX = adv;
5365 lpgm->gmCellIncY = 0;
5366 } else {
5367 INT xc, yc;
5368 FT_Vector vec;
5370 left = right = 0;
5372 for(xc = 0; xc < 2; xc++) {
5373 for(yc = 0; yc < 2; yc++) {
5374 vec.x = (ft_face->glyph->metrics.horiBearingX +
5375 xc * ft_face->glyph->metrics.width);
5376 vec.y = ft_face->glyph->metrics.horiBearingY -
5377 yc * ft_face->glyph->metrics.height;
5378 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5379 pFT_Vector_Transform(&vec, &transMat);
5380 if(xc == 0 && yc == 0) {
5381 left = right = vec.x;
5382 top = bottom = vec.y;
5383 } else {
5384 if(vec.x < left) left = vec.x;
5385 else if(vec.x > right) right = vec.x;
5386 if(vec.y < bottom) bottom = vec.y;
5387 else if(vec.y > top) top = vec.y;
5391 left = left & -64;
5392 right = (right + 63) & -64;
5393 bottom = bottom & -64;
5394 top = (top + 63) & -64;
5396 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5397 vec.x = ft_face->glyph->metrics.horiAdvance;
5398 vec.y = 0;
5399 pFT_Vector_Transform(&vec, &transMat);
5400 lpgm->gmCellIncX = (vec.x+63) >> 6;
5401 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5403 vec.x = ft_face->glyph->metrics.horiAdvance;
5404 vec.y = 0;
5405 pFT_Vector_Transform(&vec, &transMatUnrotated);
5406 adv = (vec.x+63) >> 6;
5409 lsb = left >> 6;
5410 bbx = (right - left) >> 6;
5411 lpgm->gmBlackBoxX = (right - left) >> 6;
5412 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5413 lpgm->gmptGlyphOrigin.x = left >> 6;
5414 lpgm->gmptGlyphOrigin.y = top >> 6;
5416 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5417 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5418 lpgm->gmCellIncX, lpgm->gmCellIncY);
5420 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5421 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5423 FONT_GM(font,original_index)->gm = *lpgm;
5424 FONT_GM(font,original_index)->adv = adv;
5425 FONT_GM(font,original_index)->lsb = lsb;
5426 FONT_GM(font,original_index)->bbx = bbx;
5427 FONT_GM(font,original_index)->init = TRUE;
5430 if(format == GGO_METRICS)
5432 return 1; /* FIXME */
5435 if(ft_face->glyph->format != ft_glyph_format_outline &&
5436 (format == GGO_NATIVE || format == GGO_BEZIER))
5438 TRACE("loaded a bitmap\n");
5439 return GDI_ERROR;
5442 switch(format) {
5443 case GGO_BITMAP:
5444 width = lpgm->gmBlackBoxX;
5445 height = lpgm->gmBlackBoxY;
5446 pitch = ((width + 31) >> 5) << 2;
5447 needed = pitch * height;
5449 if(!buf || !buflen) break;
5451 switch(ft_face->glyph->format) {
5452 case ft_glyph_format_bitmap:
5454 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5455 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5456 INT h = ft_face->glyph->bitmap.rows;
5457 while(h--) {
5458 memcpy(dst, src, w);
5459 src += ft_face->glyph->bitmap.pitch;
5460 dst += pitch;
5462 break;
5465 case ft_glyph_format_outline:
5466 ft_bitmap.width = width;
5467 ft_bitmap.rows = height;
5468 ft_bitmap.pitch = pitch;
5469 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5470 ft_bitmap.buffer = buf;
5472 if(needsTransform)
5473 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5475 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5477 /* Note: FreeType will only set 'black' bits for us. */
5478 memset(buf, 0, needed);
5479 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5480 break;
5482 default:
5483 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5484 return GDI_ERROR;
5486 break;
5488 case GGO_GRAY2_BITMAP:
5489 case GGO_GRAY4_BITMAP:
5490 case GGO_GRAY8_BITMAP:
5491 case WINE_GGO_GRAY16_BITMAP:
5493 unsigned int max_level, row, col;
5494 BYTE *start, *ptr;
5496 width = lpgm->gmBlackBoxX;
5497 height = lpgm->gmBlackBoxY;
5498 pitch = (width + 3) / 4 * 4;
5499 needed = pitch * height;
5501 if(!buf || !buflen) break;
5503 max_level = get_max_level( format );
5505 switch(ft_face->glyph->format) {
5506 case ft_glyph_format_bitmap:
5508 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5509 INT h = ft_face->glyph->bitmap.rows;
5510 INT x;
5511 memset( buf, 0, needed );
5512 while(h--) {
5513 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5514 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5515 src += ft_face->glyph->bitmap.pitch;
5516 dst += pitch;
5518 return needed;
5520 case ft_glyph_format_outline:
5522 ft_bitmap.width = width;
5523 ft_bitmap.rows = height;
5524 ft_bitmap.pitch = pitch;
5525 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5526 ft_bitmap.buffer = buf;
5528 if(needsTransform)
5529 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5531 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5533 memset(ft_bitmap.buffer, 0, buflen);
5535 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5537 if (max_level != 255)
5539 for (row = 0, start = buf; row < height; row++)
5541 for (col = 0, ptr = start; col < width; col++, ptr++)
5542 *ptr = (((int)*ptr) * max_level + 128) / 256;
5543 start += pitch;
5546 return needed;
5549 default:
5550 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5551 return GDI_ERROR;
5553 break;
5556 case WINE_GGO_HRGB_BITMAP:
5557 case WINE_GGO_HBGR_BITMAP:
5558 case WINE_GGO_VRGB_BITMAP:
5559 case WINE_GGO_VBGR_BITMAP:
5560 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5562 switch (ft_face->glyph->format)
5564 case FT_GLYPH_FORMAT_BITMAP:
5566 BYTE *src, *dst;
5567 INT src_pitch, x;
5569 width = lpgm->gmBlackBoxX;
5570 height = lpgm->gmBlackBoxY;
5571 pitch = width * 4;
5572 needed = pitch * height;
5574 if (!buf || !buflen) break;
5576 memset(buf, 0, buflen);
5577 dst = buf;
5578 src = ft_face->glyph->bitmap.buffer;
5579 src_pitch = ft_face->glyph->bitmap.pitch;
5581 height = min( height, ft_face->glyph->bitmap.rows );
5582 while ( height-- )
5584 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5586 if ( src[x / 8] & masks[x % 8] )
5587 ((unsigned int *)dst)[x] = ~0u;
5589 src += src_pitch;
5590 dst += pitch;
5593 break;
5596 case FT_GLYPH_FORMAT_OUTLINE:
5598 unsigned int *dst;
5599 BYTE *src;
5600 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5601 INT x_shift, y_shift;
5602 BOOL rgb;
5603 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5604 FT_Render_Mode render_mode =
5605 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5606 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5608 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5610 if ( render_mode == FT_RENDER_MODE_LCD)
5612 lpgm->gmBlackBoxX += 2;
5613 lpgm->gmptGlyphOrigin.x -= 1;
5615 else
5617 lpgm->gmBlackBoxY += 2;
5618 lpgm->gmptGlyphOrigin.y += 1;
5622 width = lpgm->gmBlackBoxX;
5623 height = lpgm->gmBlackBoxY;
5624 pitch = width * 4;
5625 needed = pitch * height;
5627 if (!buf || !buflen) break;
5629 memset(buf, 0, buflen);
5630 dst = buf;
5631 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5633 if ( needsTransform )
5634 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5636 if ( pFT_Library_SetLcdFilter )
5637 pFT_Library_SetLcdFilter( library, lcdfilter );
5638 pFT_Render_Glyph (ft_face->glyph, render_mode);
5640 src = ft_face->glyph->bitmap.buffer;
5641 src_pitch = ft_face->glyph->bitmap.pitch;
5642 src_width = ft_face->glyph->bitmap.width;
5643 src_height = ft_face->glyph->bitmap.rows;
5645 if ( render_mode == FT_RENDER_MODE_LCD)
5647 rgb_interval = 1;
5648 hmul = 3;
5649 vmul = 1;
5651 else
5653 rgb_interval = src_pitch;
5654 hmul = 1;
5655 vmul = 3;
5658 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5659 if ( x_shift < 0 ) x_shift = 0;
5660 if ( x_shift + (src_width / hmul) > width )
5661 x_shift = width - (src_width / hmul);
5663 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5664 if ( y_shift < 0 ) y_shift = 0;
5665 if ( y_shift + (src_height / vmul) > height )
5666 y_shift = height - (src_height / vmul);
5668 dst += x_shift + y_shift * ( pitch / 4 );
5669 while ( src_height )
5671 for ( x = 0; x < src_width / hmul; x++ )
5673 if ( rgb )
5675 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5676 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5677 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5678 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5680 else
5682 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5683 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5684 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5685 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5688 src += src_pitch * vmul;
5689 dst += pitch / 4;
5690 src_height -= vmul;
5693 break;
5696 default:
5697 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5698 return GDI_ERROR;
5701 break;
5703 #else
5704 return GDI_ERROR;
5705 #endif
5707 case GGO_NATIVE:
5709 int contour, point = 0, first_pt;
5710 FT_Outline *outline = &ft_face->glyph->outline;
5711 TTPOLYGONHEADER *pph;
5712 TTPOLYCURVE *ppc;
5713 DWORD pph_start, cpfx, type;
5715 if(buflen == 0) buf = NULL;
5717 if (needsTransform && buf) {
5718 pFT_Outline_Transform(outline, &transMat);
5721 for(contour = 0; contour < outline->n_contours; contour++) {
5722 pph_start = needed;
5723 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5724 first_pt = point;
5725 if(buf) {
5726 pph->dwType = TT_POLYGON_TYPE;
5727 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5729 needed += sizeof(*pph);
5730 point++;
5731 while(point <= outline->contours[contour]) {
5732 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5733 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5734 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5735 cpfx = 0;
5736 do {
5737 if(buf)
5738 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5739 cpfx++;
5740 point++;
5741 } while(point <= outline->contours[contour] &&
5742 (outline->tags[point] & FT_Curve_Tag_On) ==
5743 (outline->tags[point-1] & FT_Curve_Tag_On));
5744 /* At the end of a contour Windows adds the start point, but
5745 only for Beziers */
5746 if(point > outline->contours[contour] &&
5747 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5748 if(buf)
5749 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5750 cpfx++;
5751 } else if(point <= outline->contours[contour] &&
5752 outline->tags[point] & FT_Curve_Tag_On) {
5753 /* add closing pt for bezier */
5754 if(buf)
5755 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5756 cpfx++;
5757 point++;
5759 if(buf) {
5760 ppc->wType = type;
5761 ppc->cpfx = cpfx;
5763 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5765 if(buf)
5766 pph->cb = needed - pph_start;
5768 break;
5770 case GGO_BEZIER:
5772 /* Convert the quadratic Beziers to cubic Beziers.
5773 The parametric eqn for a cubic Bezier is, from PLRM:
5774 r(t) = at^3 + bt^2 + ct + r0
5775 with the control points:
5776 r1 = r0 + c/3
5777 r2 = r1 + (c + b)/3
5778 r3 = r0 + c + b + a
5780 A quadratic Bezier has the form:
5781 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5783 So equating powers of t leads to:
5784 r1 = 2/3 p1 + 1/3 p0
5785 r2 = 2/3 p1 + 1/3 p2
5786 and of course r0 = p0, r3 = p2
5789 int contour, point = 0, first_pt;
5790 FT_Outline *outline = &ft_face->glyph->outline;
5791 TTPOLYGONHEADER *pph;
5792 TTPOLYCURVE *ppc;
5793 DWORD pph_start, cpfx, type;
5794 FT_Vector cubic_control[4];
5795 if(buflen == 0) buf = NULL;
5797 if (needsTransform && buf) {
5798 pFT_Outline_Transform(outline, &transMat);
5801 for(contour = 0; contour < outline->n_contours; contour++) {
5802 pph_start = needed;
5803 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5804 first_pt = point;
5805 if(buf) {
5806 pph->dwType = TT_POLYGON_TYPE;
5807 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5809 needed += sizeof(*pph);
5810 point++;
5811 while(point <= outline->contours[contour]) {
5812 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5813 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5814 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5815 cpfx = 0;
5816 do {
5817 if(type == TT_PRIM_LINE) {
5818 if(buf)
5819 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5820 cpfx++;
5821 point++;
5822 } else {
5823 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5824 so cpfx = 3n */
5826 /* FIXME: Possible optimization in endpoint calculation
5827 if there are two consecutive curves */
5828 cubic_control[0] = outline->points[point-1];
5829 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5830 cubic_control[0].x += outline->points[point].x + 1;
5831 cubic_control[0].y += outline->points[point].y + 1;
5832 cubic_control[0].x >>= 1;
5833 cubic_control[0].y >>= 1;
5835 if(point+1 > outline->contours[contour])
5836 cubic_control[3] = outline->points[first_pt];
5837 else {
5838 cubic_control[3] = outline->points[point+1];
5839 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5840 cubic_control[3].x += outline->points[point].x + 1;
5841 cubic_control[3].y += outline->points[point].y + 1;
5842 cubic_control[3].x >>= 1;
5843 cubic_control[3].y >>= 1;
5846 /* r1 = 1/3 p0 + 2/3 p1
5847 r2 = 1/3 p2 + 2/3 p1 */
5848 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5849 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5850 cubic_control[2] = cubic_control[1];
5851 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5852 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5853 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5854 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5855 if(buf) {
5856 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5857 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5858 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5860 cpfx += 3;
5861 point++;
5863 } while(point <= outline->contours[contour] &&
5864 (outline->tags[point] & FT_Curve_Tag_On) ==
5865 (outline->tags[point-1] & FT_Curve_Tag_On));
5866 /* At the end of a contour Windows adds the start point,
5867 but only for Beziers and we've already done that.
5869 if(point <= outline->contours[contour] &&
5870 outline->tags[point] & FT_Curve_Tag_On) {
5871 /* This is the closing pt of a bezier, but we've already
5872 added it, so just inc point and carry on */
5873 point++;
5875 if(buf) {
5876 ppc->wType = type;
5877 ppc->cpfx = cpfx;
5879 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5881 if(buf)
5882 pph->cb = needed - pph_start;
5884 break;
5887 default:
5888 FIXME("Unsupported format %d\n", format);
5889 return GDI_ERROR;
5891 return needed;
5894 static BOOL get_bitmap_text_metrics(GdiFont *font)
5896 FT_Face ft_face = font->ft_face;
5897 FT_WinFNT_HeaderRec winfnt_header;
5898 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5899 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5900 font->potm->otmSize = size;
5902 #define TM font->potm->otmTextMetrics
5903 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5905 TM.tmHeight = winfnt_header.pixel_height;
5906 TM.tmAscent = winfnt_header.ascent;
5907 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5908 TM.tmInternalLeading = winfnt_header.internal_leading;
5909 TM.tmExternalLeading = winfnt_header.external_leading;
5910 TM.tmAveCharWidth = winfnt_header.avg_width;
5911 TM.tmMaxCharWidth = winfnt_header.max_width;
5912 TM.tmWeight = winfnt_header.weight;
5913 TM.tmOverhang = 0;
5914 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5915 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5916 TM.tmFirstChar = winfnt_header.first_char;
5917 TM.tmLastChar = winfnt_header.last_char;
5918 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5919 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5920 TM.tmItalic = winfnt_header.italic;
5921 TM.tmUnderlined = font->underline;
5922 TM.tmStruckOut = font->strikeout;
5923 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5924 TM.tmCharSet = winfnt_header.charset;
5926 else
5928 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5929 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5930 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5931 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5932 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5933 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5934 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5935 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5936 TM.tmOverhang = 0;
5937 TM.tmDigitizedAspectX = 96; /* FIXME */
5938 TM.tmDigitizedAspectY = 96; /* FIXME */
5939 TM.tmFirstChar = 1;
5940 TM.tmLastChar = 255;
5941 TM.tmDefaultChar = 32;
5942 TM.tmBreakChar = 32;
5943 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5944 TM.tmUnderlined = font->underline;
5945 TM.tmStruckOut = font->strikeout;
5946 /* NB inverted meaning of TMPF_FIXED_PITCH */
5947 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5948 TM.tmCharSet = font->charset;
5950 #undef TM
5952 return TRUE;
5956 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5958 double scale_x, scale_y;
5960 if (font->aveWidth)
5962 scale_x = (double)font->aveWidth;
5963 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5965 else
5966 scale_x = font->scale_y;
5968 scale_x *= fabs(font->font_desc.matrix.eM11);
5969 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5971 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5972 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5974 SCALE_Y(ptm->tmHeight);
5975 SCALE_Y(ptm->tmAscent);
5976 SCALE_Y(ptm->tmDescent);
5977 SCALE_Y(ptm->tmInternalLeading);
5978 SCALE_Y(ptm->tmExternalLeading);
5979 SCALE_Y(ptm->tmOverhang);
5981 SCALE_X(ptm->tmAveCharWidth);
5982 SCALE_X(ptm->tmMaxCharWidth);
5984 #undef SCALE_X
5985 #undef SCALE_Y
5988 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5990 double scale_x, scale_y;
5992 if (font->aveWidth)
5994 scale_x = (double)font->aveWidth;
5995 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5997 else
5998 scale_x = font->scale_y;
6000 scale_x *= fabs(font->font_desc.matrix.eM11);
6001 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6003 scale_font_metrics(font, &potm->otmTextMetrics);
6005 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6006 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6008 SCALE_Y(potm->otmAscent);
6009 SCALE_Y(potm->otmDescent);
6010 SCALE_Y(potm->otmLineGap);
6011 SCALE_Y(potm->otmsCapEmHeight);
6012 SCALE_Y(potm->otmsXHeight);
6013 SCALE_Y(potm->otmrcFontBox.top);
6014 SCALE_Y(potm->otmrcFontBox.bottom);
6015 SCALE_X(potm->otmrcFontBox.left);
6016 SCALE_X(potm->otmrcFontBox.right);
6017 SCALE_Y(potm->otmMacAscent);
6018 SCALE_Y(potm->otmMacDescent);
6019 SCALE_Y(potm->otmMacLineGap);
6020 SCALE_X(potm->otmptSubscriptSize.x);
6021 SCALE_Y(potm->otmptSubscriptSize.y);
6022 SCALE_X(potm->otmptSubscriptOffset.x);
6023 SCALE_Y(potm->otmptSubscriptOffset.y);
6024 SCALE_X(potm->otmptSuperscriptSize.x);
6025 SCALE_Y(potm->otmptSuperscriptSize.y);
6026 SCALE_X(potm->otmptSuperscriptOffset.x);
6027 SCALE_Y(potm->otmptSuperscriptOffset.y);
6028 SCALE_Y(potm->otmsStrikeoutSize);
6029 SCALE_Y(potm->otmsStrikeoutPosition);
6030 SCALE_Y(potm->otmsUnderscoreSize);
6031 SCALE_Y(potm->otmsUnderscorePosition);
6033 #undef SCALE_X
6034 #undef SCALE_Y
6037 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6039 if(!font->potm)
6041 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6043 /* Make sure that the font has sane width/height ratio */
6044 if (font->aveWidth)
6046 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6048 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6049 font->aveWidth = 0;
6053 *ptm = font->potm->otmTextMetrics;
6054 scale_font_metrics(font, ptm);
6055 return TRUE;
6058 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6060 int i;
6062 for(i = 0; i < ft_face->num_charmaps; i++)
6064 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6065 return TRUE;
6067 return FALSE;
6070 static BOOL get_outline_text_metrics(GdiFont *font)
6072 BOOL ret = FALSE;
6073 FT_Face ft_face = font->ft_face;
6074 UINT needed, lenfam, lensty;
6075 TT_OS2 *pOS2;
6076 TT_HoriHeader *pHori;
6077 TT_Postscript *pPost;
6078 FT_Fixed x_scale, y_scale;
6079 WCHAR *family_nameW, *style_nameW;
6080 static const WCHAR spaceW[] = {' ', '\0'};
6081 char *cp;
6082 INT ascent, descent;
6084 TRACE("font=%p\n", font);
6086 if(!FT_IS_SCALABLE(ft_face))
6087 return FALSE;
6089 needed = sizeof(*font->potm);
6091 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6092 family_nameW = strdupW(font->name);
6094 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6095 * sizeof(WCHAR);
6096 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6097 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6098 style_nameW, lensty/sizeof(WCHAR));
6100 /* These names should be read from the TT name table */
6102 /* length of otmpFamilyName */
6103 needed += lenfam;
6105 /* length of otmpFaceName */
6106 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6107 needed += lenfam; /* just the family name */
6108 } else {
6109 needed += lenfam + lensty; /* family + " " + style */
6112 /* length of otmpStyleName */
6113 needed += lensty;
6115 /* length of otmpFullName */
6116 needed += lenfam + lensty;
6119 x_scale = ft_face->size->metrics.x_scale;
6120 y_scale = ft_face->size->metrics.y_scale;
6122 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6123 if(!pOS2) {
6124 FIXME("Can't find OS/2 table - not TT font?\n");
6125 goto end;
6128 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6129 if(!pHori) {
6130 FIXME("Can't find HHEA table - not TT font?\n");
6131 goto end;
6134 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6136 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",
6137 pOS2->usWinAscent, pOS2->usWinDescent,
6138 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6139 ft_face->ascender, ft_face->descender, ft_face->height,
6140 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6141 ft_face->bbox.yMax, ft_face->bbox.yMin);
6143 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6144 font->potm->otmSize = needed;
6146 #define TM font->potm->otmTextMetrics
6148 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6149 ascent = pHori->Ascender;
6150 descent = -pHori->Descender;
6151 } else {
6152 ascent = pOS2->usWinAscent;
6153 descent = pOS2->usWinDescent;
6156 if(font->yMax) {
6157 TM.tmAscent = font->yMax;
6158 TM.tmDescent = -font->yMin;
6159 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6160 } else {
6161 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6162 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6163 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6164 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6167 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6169 /* MSDN says:
6170 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6172 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6173 ((ascent + descent) -
6174 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6176 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6177 if (TM.tmAveCharWidth == 0) {
6178 TM.tmAveCharWidth = 1;
6180 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6181 TM.tmWeight = FW_REGULAR;
6182 if (font->fake_bold)
6183 TM.tmWeight = FW_BOLD;
6184 else
6186 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6188 if (pOS2->usWeightClass > FW_MEDIUM)
6189 TM.tmWeight = pOS2->usWeightClass;
6191 else if (pOS2->usWeightClass <= FW_MEDIUM)
6192 TM.tmWeight = pOS2->usWeightClass;
6194 TM.tmOverhang = 0;
6195 TM.tmDigitizedAspectX = 300;
6196 TM.tmDigitizedAspectY = 300;
6197 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6198 * symbol range to 0 - f0ff
6201 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6203 TM.tmFirstChar = 0;
6204 switch(GetACP())
6206 case 1257: /* Baltic */
6207 TM.tmLastChar = 0xf8fd;
6208 break;
6209 default:
6210 TM.tmLastChar = 0xf0ff;
6212 TM.tmBreakChar = 0x20;
6213 TM.tmDefaultChar = 0x1f;
6215 else
6217 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6218 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6220 if(pOS2->usFirstCharIndex <= 1)
6221 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6222 else if (pOS2->usFirstCharIndex > 0xff)
6223 TM.tmBreakChar = 0x20;
6224 else
6225 TM.tmBreakChar = pOS2->usFirstCharIndex;
6226 TM.tmDefaultChar = TM.tmBreakChar - 1;
6228 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6229 TM.tmUnderlined = font->underline;
6230 TM.tmStruckOut = font->strikeout;
6232 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6233 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6234 (pOS2->version == 0xFFFFU ||
6235 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6236 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6237 else
6238 TM.tmPitchAndFamily = 0;
6240 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6242 case PAN_FAMILY_SCRIPT:
6243 TM.tmPitchAndFamily |= FF_SCRIPT;
6244 break;
6246 case PAN_FAMILY_DECORATIVE:
6247 TM.tmPitchAndFamily |= FF_DECORATIVE;
6248 break;
6250 case PAN_ANY:
6251 case PAN_NO_FIT:
6252 case PAN_FAMILY_TEXT_DISPLAY:
6253 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6254 /* which is clearly not what the panose spec says. */
6255 default:
6256 if(TM.tmPitchAndFamily == 0 || /* fixed */
6257 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6258 TM.tmPitchAndFamily = FF_MODERN;
6259 else
6261 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6263 case PAN_ANY:
6264 case PAN_NO_FIT:
6265 default:
6266 TM.tmPitchAndFamily |= FF_DONTCARE;
6267 break;
6269 case PAN_SERIF_COVE:
6270 case PAN_SERIF_OBTUSE_COVE:
6271 case PAN_SERIF_SQUARE_COVE:
6272 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6273 case PAN_SERIF_SQUARE:
6274 case PAN_SERIF_THIN:
6275 case PAN_SERIF_BONE:
6276 case PAN_SERIF_EXAGGERATED:
6277 case PAN_SERIF_TRIANGLE:
6278 TM.tmPitchAndFamily |= FF_ROMAN;
6279 break;
6281 case PAN_SERIF_NORMAL_SANS:
6282 case PAN_SERIF_OBTUSE_SANS:
6283 case PAN_SERIF_PERP_SANS:
6284 case PAN_SERIF_FLARED:
6285 case PAN_SERIF_ROUNDED:
6286 TM.tmPitchAndFamily |= FF_SWISS;
6287 break;
6290 break;
6293 if(FT_IS_SCALABLE(ft_face))
6294 TM.tmPitchAndFamily |= TMPF_VECTOR;
6296 if(FT_IS_SFNT(ft_face))
6298 if (font->ntmFlags & NTM_PS_OPENTYPE)
6299 TM.tmPitchAndFamily |= TMPF_DEVICE;
6300 else
6301 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6304 TM.tmCharSet = font->charset;
6306 font->potm->otmFiller = 0;
6307 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6308 font->potm->otmfsSelection = pOS2->fsSelection;
6309 font->potm->otmfsType = pOS2->fsType;
6310 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6311 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6312 font->potm->otmItalicAngle = 0; /* POST table */
6313 font->potm->otmEMSquare = ft_face->units_per_EM;
6314 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6315 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6316 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6317 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6318 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6319 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6320 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6321 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6322 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6323 font->potm->otmMacAscent = TM.tmAscent;
6324 font->potm->otmMacDescent = -TM.tmDescent;
6325 font->potm->otmMacLineGap = font->potm->otmLineGap;
6326 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6327 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6328 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6329 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6330 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6331 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6332 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6333 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6334 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6335 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6336 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6337 if(!pPost) {
6338 font->potm->otmsUnderscoreSize = 0;
6339 font->potm->otmsUnderscorePosition = 0;
6340 } else {
6341 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6342 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6344 #undef TM
6346 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6347 cp = (char*)font->potm + sizeof(*font->potm);
6348 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6349 strcpyW((WCHAR*)cp, family_nameW);
6350 cp += lenfam;
6351 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6352 strcpyW((WCHAR*)cp, style_nameW);
6353 cp += lensty;
6354 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6355 strcpyW((WCHAR*)cp, family_nameW);
6356 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6357 strcatW((WCHAR*)cp, spaceW);
6358 strcatW((WCHAR*)cp, style_nameW);
6359 cp += lenfam + lensty;
6360 } else
6361 cp += lenfam;
6362 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6363 strcpyW((WCHAR*)cp, family_nameW);
6364 strcatW((WCHAR*)cp, spaceW);
6365 strcatW((WCHAR*)cp, style_nameW);
6366 ret = TRUE;
6368 end:
6369 HeapFree(GetProcessHeap(), 0, style_nameW);
6370 HeapFree(GetProcessHeap(), 0, family_nameW);
6371 return ret;
6374 /*************************************************************
6375 * freetype_GetGlyphOutline
6377 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6378 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6380 struct freetype_physdev *physdev = get_freetype_dev( dev );
6381 DWORD ret;
6383 if (!physdev->font)
6385 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6386 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6389 GDI_CheckNotLock();
6390 EnterCriticalSection( &freetype_cs );
6391 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6392 LeaveCriticalSection( &freetype_cs );
6393 return ret;
6396 /*************************************************************
6397 * freetype_GetTextMetrics
6399 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6401 struct freetype_physdev *physdev = get_freetype_dev( dev );
6402 BOOL ret;
6404 if (!physdev->font)
6406 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6407 return dev->funcs->pGetTextMetrics( dev, metrics );
6410 GDI_CheckNotLock();
6411 EnterCriticalSection( &freetype_cs );
6412 ret = get_text_metrics( physdev->font, metrics );
6413 LeaveCriticalSection( &freetype_cs );
6414 return ret;
6417 /*************************************************************
6418 * freetype_GetOutlineTextMetrics
6420 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6422 struct freetype_physdev *physdev = get_freetype_dev( dev );
6423 UINT ret = 0;
6425 if (!physdev->font)
6427 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6428 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6431 TRACE("font=%p\n", physdev->font);
6433 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6435 GDI_CheckNotLock();
6436 EnterCriticalSection( &freetype_cs );
6438 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6440 if(cbSize >= physdev->font->potm->otmSize)
6442 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6443 scale_outline_font_metrics(physdev->font, potm);
6445 ret = physdev->font->potm->otmSize;
6447 LeaveCriticalSection( &freetype_cs );
6448 return ret;
6451 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6453 HFONTLIST *hfontlist;
6454 child->font = alloc_font();
6455 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6456 if(!child->font->ft_face)
6458 free_font(child->font);
6459 child->font = NULL;
6460 return FALSE;
6463 child->font->font_desc = font->font_desc;
6464 child->font->ntmFlags = child->face->ntmFlags;
6465 child->font->orientation = font->orientation;
6466 child->font->scale_y = font->scale_y;
6467 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6468 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6469 child->font->name = strdupW(child->face->family->FamilyName);
6470 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6471 child->font->base_font = font;
6472 list_add_head(&child_font_list, &child->font->entry);
6473 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6474 return TRUE;
6477 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6479 FT_UInt g;
6480 CHILD_FONT *child_font;
6482 if(font->base_font)
6483 font = font->base_font;
6485 *linked_font = font;
6487 if((*glyph = get_glyph_index(font, c)))
6489 *glyph = get_GSUB_vert_glyph(font, *glyph);
6490 return TRUE;
6493 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6495 if(!child_font->font)
6496 if(!load_child_font(font, child_font))
6497 continue;
6499 if(!child_font->font->ft_face)
6500 continue;
6501 g = get_glyph_index(child_font->font, c);
6502 g = get_GSUB_vert_glyph(child_font->font, g);
6503 if(g)
6505 *glyph = g;
6506 *linked_font = child_font->font;
6507 return TRUE;
6510 return FALSE;
6513 /*************************************************************
6514 * freetype_GetCharWidth
6516 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6518 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6519 UINT c;
6520 GLYPHMETRICS gm;
6521 FT_UInt glyph_index;
6522 GdiFont *linked_font;
6523 struct freetype_physdev *physdev = get_freetype_dev( dev );
6525 if (!physdev->font)
6527 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6528 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6531 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6533 GDI_CheckNotLock();
6534 EnterCriticalSection( &freetype_cs );
6535 for(c = firstChar; c <= lastChar; c++) {
6536 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6537 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6538 &gm, 0, NULL, &identity);
6539 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6541 LeaveCriticalSection( &freetype_cs );
6542 return TRUE;
6545 /*************************************************************
6546 * freetype_GetCharABCWidths
6548 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6550 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6551 UINT c;
6552 GLYPHMETRICS gm;
6553 FT_UInt glyph_index;
6554 GdiFont *linked_font;
6555 struct freetype_physdev *physdev = get_freetype_dev( dev );
6557 if (!physdev->font)
6559 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6560 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6563 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6565 GDI_CheckNotLock();
6566 EnterCriticalSection( &freetype_cs );
6568 for(c = firstChar; c <= lastChar; c++) {
6569 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6570 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6571 &gm, 0, NULL, &identity);
6572 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6573 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6574 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6575 FONT_GM(linked_font,glyph_index)->bbx;
6577 LeaveCriticalSection( &freetype_cs );
6578 return TRUE;
6581 /*************************************************************
6582 * freetype_GetCharABCWidthsI
6584 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6586 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6587 UINT c;
6588 GLYPHMETRICS gm;
6589 FT_UInt glyph_index;
6590 GdiFont *linked_font;
6591 struct freetype_physdev *physdev = get_freetype_dev( dev );
6593 if (!physdev->font)
6595 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6596 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6599 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6600 return FALSE;
6602 GDI_CheckNotLock();
6603 EnterCriticalSection( &freetype_cs );
6605 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6606 if (!pgi)
6607 for(c = firstChar; c < firstChar+count; c++) {
6608 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6609 &gm, 0, NULL, &identity);
6610 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6611 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6612 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6613 - FONT_GM(linked_font,c)->bbx;
6615 else
6616 for(c = 0; c < count; c++) {
6617 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6618 &gm, 0, NULL, &identity);
6619 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6620 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6621 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6622 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6625 LeaveCriticalSection( &freetype_cs );
6626 return TRUE;
6629 /*************************************************************
6630 * freetype_GetTextExtentExPoint
6632 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6633 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6635 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6636 INT idx;
6637 INT nfit = 0, ext;
6638 GLYPHMETRICS gm;
6639 TEXTMETRICW tm;
6640 FT_UInt glyph_index;
6641 GdiFont *linked_font;
6642 struct freetype_physdev *physdev = get_freetype_dev( dev );
6644 if (!physdev->font)
6646 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6647 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6650 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6652 GDI_CheckNotLock();
6653 EnterCriticalSection( &freetype_cs );
6655 size->cx = 0;
6656 get_text_metrics( physdev->font, &tm );
6657 size->cy = tm.tmHeight;
6659 for(idx = 0; idx < count; idx++) {
6660 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6661 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6662 &gm, 0, NULL, &identity);
6663 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6664 ext = size->cx;
6665 if (! pnfit || ext <= max_ext) {
6666 ++nfit;
6667 if (dxs)
6668 dxs[idx] = ext;
6672 if (pnfit)
6673 *pnfit = nfit;
6675 LeaveCriticalSection( &freetype_cs );
6676 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6677 return TRUE;
6680 /*************************************************************
6681 * freetype_GetTextExtentExPointI
6683 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6684 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6686 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6687 INT idx;
6688 INT nfit = 0, ext;
6689 GLYPHMETRICS gm;
6690 TEXTMETRICW tm;
6691 struct freetype_physdev *physdev = get_freetype_dev( dev );
6693 if (!physdev->font)
6695 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6696 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6699 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6701 GDI_CheckNotLock();
6702 EnterCriticalSection( &freetype_cs );
6704 size->cx = 0;
6705 get_text_metrics(physdev->font, &tm);
6706 size->cy = tm.tmHeight;
6708 for(idx = 0; idx < count; idx++) {
6709 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6710 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6711 ext = size->cx;
6712 if (! pnfit || ext <= max_ext) {
6713 ++nfit;
6714 if (dxs)
6715 dxs[idx] = ext;
6719 if (pnfit)
6720 *pnfit = nfit;
6722 LeaveCriticalSection( &freetype_cs );
6723 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6724 return TRUE;
6727 /*************************************************************
6728 * freetype_GetFontData
6730 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6732 struct freetype_physdev *physdev = get_freetype_dev( dev );
6734 if (!physdev->font)
6736 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6737 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6740 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6741 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6742 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6744 return get_font_data( physdev->font, table, offset, buf, cbData );
6747 /*************************************************************
6748 * freetype_GetTextFace
6750 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6752 INT n;
6753 struct freetype_physdev *physdev = get_freetype_dev( dev );
6755 if (!physdev->font)
6757 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6758 return dev->funcs->pGetTextFace( dev, count, str );
6761 n = strlenW(physdev->font->name) + 1;
6762 if (str)
6764 lstrcpynW(str, physdev->font->name, count);
6765 n = min(count, n);
6767 return n;
6770 /*************************************************************
6771 * freetype_GetTextCharsetInfo
6773 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6775 struct freetype_physdev *physdev = get_freetype_dev( dev );
6777 if (!physdev->font)
6779 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6780 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6782 if (fs) *fs = physdev->font->fs;
6783 return physdev->font->charset;
6786 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6788 GdiFont *font = dc->gdiFont, *linked_font;
6789 struct list *first_hfont;
6790 BOOL ret;
6792 GDI_CheckNotLock();
6793 EnterCriticalSection( &freetype_cs );
6794 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6795 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6796 if(font == linked_font)
6797 *new_hfont = dc->hFont;
6798 else
6800 first_hfont = list_head(&linked_font->hfontlist);
6801 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6803 LeaveCriticalSection( &freetype_cs );
6804 return ret;
6807 /* Retrieve a list of supported Unicode ranges for a given font.
6808 * Can be called with NULL gs to calculate the buffer size. Returns
6809 * the number of ranges found.
6811 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6813 DWORD num_ranges = 0;
6815 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6817 FT_UInt glyph_code;
6818 FT_ULong char_code, char_code_prev;
6820 glyph_code = 0;
6821 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6823 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6824 face->num_glyphs, glyph_code, char_code);
6826 if (!glyph_code) return 0;
6828 if (gs)
6830 gs->ranges[0].wcLow = (USHORT)char_code;
6831 gs->ranges[0].cGlyphs = 0;
6832 gs->cGlyphsSupported = 0;
6835 num_ranges = 1;
6836 while (glyph_code)
6838 if (char_code < char_code_prev)
6840 ERR("expected increasing char code from FT_Get_Next_Char\n");
6841 return 0;
6843 if (char_code - char_code_prev > 1)
6845 num_ranges++;
6846 if (gs)
6848 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6849 gs->ranges[num_ranges - 1].cGlyphs = 1;
6850 gs->cGlyphsSupported++;
6853 else if (gs)
6855 gs->ranges[num_ranges - 1].cGlyphs++;
6856 gs->cGlyphsSupported++;
6858 char_code_prev = char_code;
6859 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6862 else
6863 FIXME("encoding %u not supported\n", face->charmap->encoding);
6865 return num_ranges;
6868 /*************************************************************
6869 * freetype_GetFontUnicodeRanges
6871 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6873 struct freetype_physdev *physdev = get_freetype_dev( dev );
6874 DWORD size, num_ranges;
6876 if (!physdev->font)
6878 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6879 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6882 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6883 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6884 if (glyphset)
6886 glyphset->cbThis = size;
6887 glyphset->cRanges = num_ranges;
6888 glyphset->flAccel = 0;
6890 return size;
6893 /*************************************************************
6894 * freetype_FontIsLinked
6896 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6898 struct freetype_physdev *physdev = get_freetype_dev( dev );
6899 BOOL ret;
6901 if (!physdev->font)
6903 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6904 return dev->funcs->pFontIsLinked( dev );
6907 GDI_CheckNotLock();
6908 EnterCriticalSection( &freetype_cs );
6909 ret = !list_empty(&physdev->font->child_fonts);
6910 LeaveCriticalSection( &freetype_cs );
6911 return ret;
6914 static BOOL is_hinting_enabled(void)
6916 /* Use the >= 2.2.0 function if available */
6917 if(pFT_Get_TrueType_Engine_Type)
6919 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6920 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6922 #ifdef FT_DRIVER_HAS_HINTER
6923 else
6925 FT_Module mod;
6927 /* otherwise if we've been compiled with < 2.2.0 headers
6928 use the internal macro */
6929 mod = pFT_Get_Module(library, "truetype");
6930 if(mod && FT_DRIVER_HAS_HINTER(mod))
6931 return TRUE;
6933 #endif
6935 return FALSE;
6938 static BOOL is_subpixel_rendering_enabled( void )
6940 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6941 return pFT_Library_SetLcdFilter &&
6942 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6943 #else
6944 return FALSE;
6945 #endif
6948 /*************************************************************************
6949 * GetRasterizerCaps (GDI32.@)
6951 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6953 static int hinting = -1;
6954 static int subpixel = -1;
6956 if(hinting == -1)
6958 hinting = is_hinting_enabled();
6959 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6962 if ( subpixel == -1 )
6964 subpixel = is_subpixel_rendering_enabled();
6965 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6968 lprs->nSize = sizeof(RASTERIZER_STATUS);
6969 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6970 if ( subpixel )
6971 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6972 lprs->nLanguageID = 0;
6973 return TRUE;
6976 /*************************************************************
6977 * freetype_GdiRealizationInfo
6979 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6981 struct freetype_physdev *physdev = get_freetype_dev( dev );
6982 realization_info_t *info = ptr;
6984 if (!physdev->font)
6986 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6987 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6990 FIXME("(%p, %p): stub!\n", physdev->font, info);
6992 info->flags = 1;
6993 if(FT_IS_SCALABLE(physdev->font->ft_face))
6994 info->flags |= 2;
6996 info->cache_num = physdev->font->cache_num;
6997 info->unknown2 = -1;
6998 return TRUE;
7001 /*************************************************************************
7002 * Kerning support for TrueType fonts
7004 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7006 struct TT_kern_table
7008 USHORT version;
7009 USHORT nTables;
7012 struct TT_kern_subtable
7014 USHORT version;
7015 USHORT length;
7016 union
7018 USHORT word;
7019 struct
7021 USHORT horizontal : 1;
7022 USHORT minimum : 1;
7023 USHORT cross_stream: 1;
7024 USHORT override : 1;
7025 USHORT reserved1 : 4;
7026 USHORT format : 8;
7027 } bits;
7028 } coverage;
7031 struct TT_format0_kern_subtable
7033 USHORT nPairs;
7034 USHORT searchRange;
7035 USHORT entrySelector;
7036 USHORT rangeShift;
7039 struct TT_kern_pair
7041 USHORT left;
7042 USHORT right;
7043 short value;
7046 static DWORD parse_format0_kern_subtable(GdiFont *font,
7047 const struct TT_format0_kern_subtable *tt_f0_ks,
7048 const USHORT *glyph_to_char,
7049 KERNINGPAIR *kern_pair, DWORD cPairs)
7051 USHORT i, nPairs;
7052 const struct TT_kern_pair *tt_kern_pair;
7054 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7056 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7058 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7059 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7060 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7062 if (!kern_pair || !cPairs)
7063 return nPairs;
7065 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7067 nPairs = min(nPairs, cPairs);
7069 for (i = 0; i < nPairs; i++)
7071 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7072 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7073 /* this algorithm appears to better match what Windows does */
7074 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7075 if (kern_pair->iKernAmount < 0)
7077 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7078 kern_pair->iKernAmount -= font->ppem;
7080 else if (kern_pair->iKernAmount > 0)
7082 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7083 kern_pair->iKernAmount += font->ppem;
7085 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7087 TRACE("left %u right %u value %d\n",
7088 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7090 kern_pair++;
7092 TRACE("copied %u entries\n", nPairs);
7093 return nPairs;
7096 /*************************************************************
7097 * freetype_GetKerningPairs
7099 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7101 DWORD length;
7102 void *buf;
7103 const struct TT_kern_table *tt_kern_table;
7104 const struct TT_kern_subtable *tt_kern_subtable;
7105 USHORT i, nTables;
7106 USHORT *glyph_to_char;
7107 GdiFont *font;
7108 struct freetype_physdev *physdev = get_freetype_dev( dev );
7110 if (!(font = physdev->font))
7112 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7113 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7116 GDI_CheckNotLock();
7117 EnterCriticalSection( &freetype_cs );
7118 if (font->total_kern_pairs != (DWORD)-1)
7120 if (cPairs && kern_pair)
7122 cPairs = min(cPairs, font->total_kern_pairs);
7123 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7125 else cPairs = font->total_kern_pairs;
7127 LeaveCriticalSection( &freetype_cs );
7128 return cPairs;
7131 font->total_kern_pairs = 0;
7133 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7135 if (length == GDI_ERROR)
7137 TRACE("no kerning data in the font\n");
7138 LeaveCriticalSection( &freetype_cs );
7139 return 0;
7142 buf = HeapAlloc(GetProcessHeap(), 0, length);
7143 if (!buf)
7145 WARN("Out of memory\n");
7146 LeaveCriticalSection( &freetype_cs );
7147 return 0;
7150 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7152 /* build a glyph index to char code map */
7153 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7154 if (!glyph_to_char)
7156 WARN("Out of memory allocating a glyph index to char code map\n");
7157 HeapFree(GetProcessHeap(), 0, buf);
7158 LeaveCriticalSection( &freetype_cs );
7159 return 0;
7162 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7164 FT_UInt glyph_code;
7165 FT_ULong char_code;
7167 glyph_code = 0;
7168 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7170 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7171 font->ft_face->num_glyphs, glyph_code, char_code);
7173 while (glyph_code)
7175 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7177 /* FIXME: This doesn't match what Windows does: it does some fancy
7178 * things with duplicate glyph index to char code mappings, while
7179 * we just avoid overriding existing entries.
7181 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7182 glyph_to_char[glyph_code] = (USHORT)char_code;
7184 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7187 else
7189 ULONG n;
7191 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7192 for (n = 0; n <= 65535; n++)
7193 glyph_to_char[n] = (USHORT)n;
7196 tt_kern_table = buf;
7197 nTables = GET_BE_WORD(tt_kern_table->nTables);
7198 TRACE("version %u, nTables %u\n",
7199 GET_BE_WORD(tt_kern_table->version), nTables);
7201 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7203 for (i = 0; i < nTables; i++)
7205 struct TT_kern_subtable tt_kern_subtable_copy;
7207 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7208 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7209 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7211 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7212 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7213 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7215 /* According to the TrueType specification this is the only format
7216 * that will be properly interpreted by Windows and OS/2
7218 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7220 DWORD new_chunk, old_total = font->total_kern_pairs;
7222 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7223 glyph_to_char, NULL, 0);
7224 font->total_kern_pairs += new_chunk;
7226 if (!font->kern_pairs)
7227 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7228 font->total_kern_pairs * sizeof(*font->kern_pairs));
7229 else
7230 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7231 font->total_kern_pairs * sizeof(*font->kern_pairs));
7233 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7234 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7236 else
7237 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7239 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7242 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7243 HeapFree(GetProcessHeap(), 0, buf);
7245 if (cPairs && kern_pair)
7247 cPairs = min(cPairs, font->total_kern_pairs);
7248 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7250 else cPairs = font->total_kern_pairs;
7252 LeaveCriticalSection( &freetype_cs );
7253 return cPairs;
7256 static const struct gdi_dc_funcs freetype_funcs =
7258 NULL, /* pAbortDoc */
7259 NULL, /* pAbortPath */
7260 NULL, /* pAlphaBlend */
7261 NULL, /* pAngleArc */
7262 NULL, /* pArc */
7263 NULL, /* pArcTo */
7264 NULL, /* pBeginPath */
7265 NULL, /* pBlendImage */
7266 NULL, /* pChoosePixelFormat */
7267 NULL, /* pChord */
7268 NULL, /* pCloseFigure */
7269 NULL, /* pCopyBitmap */
7270 NULL, /* pCreateBitmap */
7271 NULL, /* pCreateCompatibleDC */
7272 freetype_CreateDC, /* pCreateDC */
7273 NULL, /* pDeleteBitmap */
7274 freetype_DeleteDC, /* pDeleteDC */
7275 NULL, /* pDeleteObject */
7276 NULL, /* pDescribePixelFormat */
7277 NULL, /* pDeviceCapabilities */
7278 NULL, /* pEllipse */
7279 NULL, /* pEndDoc */
7280 NULL, /* pEndPage */
7281 NULL, /* pEndPath */
7282 freetype_EnumFonts, /* pEnumFonts */
7283 NULL, /* pEnumICMProfiles */
7284 NULL, /* pExcludeClipRect */
7285 NULL, /* pExtDeviceMode */
7286 NULL, /* pExtEscape */
7287 NULL, /* pExtFloodFill */
7288 NULL, /* pExtSelectClipRgn */
7289 NULL, /* pExtTextOut */
7290 NULL, /* pFillPath */
7291 NULL, /* pFillRgn */
7292 NULL, /* pFlattenPath */
7293 freetype_FontIsLinked, /* pFontIsLinked */
7294 NULL, /* pFrameRgn */
7295 NULL, /* pGdiComment */
7296 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7297 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7298 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7299 freetype_GetCharWidth, /* pGetCharWidth */
7300 NULL, /* pGetDeviceCaps */
7301 NULL, /* pGetDeviceGammaRamp */
7302 freetype_GetFontData, /* pGetFontData */
7303 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7304 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7305 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7306 NULL, /* pGetICMProfile */
7307 NULL, /* pGetImage */
7308 freetype_GetKerningPairs, /* pGetKerningPairs */
7309 NULL, /* pGetNearestColor */
7310 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7311 NULL, /* pGetPixel */
7312 NULL, /* pGetPixelFormat */
7313 NULL, /* pGetSystemPaletteEntries */
7314 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7315 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7316 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7317 freetype_GetTextFace, /* pGetTextFace */
7318 freetype_GetTextMetrics, /* pGetTextMetrics */
7319 NULL, /* pGradientFill */
7320 NULL, /* pIntersectClipRect */
7321 NULL, /* pInvertRgn */
7322 NULL, /* pLineTo */
7323 NULL, /* pModifyWorldTransform */
7324 NULL, /* pMoveTo */
7325 NULL, /* pOffsetClipRgn */
7326 NULL, /* pOffsetViewportOrg */
7327 NULL, /* pOffsetWindowOrg */
7328 NULL, /* pPaintRgn */
7329 NULL, /* pPatBlt */
7330 NULL, /* pPie */
7331 NULL, /* pPolyBezier */
7332 NULL, /* pPolyBezierTo */
7333 NULL, /* pPolyDraw */
7334 NULL, /* pPolyPolygon */
7335 NULL, /* pPolyPolyline */
7336 NULL, /* pPolygon */
7337 NULL, /* pPolyline */
7338 NULL, /* pPolylineTo */
7339 NULL, /* pPutImage */
7340 NULL, /* pRealizeDefaultPalette */
7341 NULL, /* pRealizePalette */
7342 NULL, /* pRectangle */
7343 NULL, /* pResetDC */
7344 NULL, /* pRestoreDC */
7345 NULL, /* pRoundRect */
7346 NULL, /* pSaveDC */
7347 NULL, /* pScaleViewportExt */
7348 NULL, /* pScaleWindowExt */
7349 NULL, /* pSelectBitmap */
7350 NULL, /* pSelectBrush */
7351 NULL, /* pSelectClipPath */
7352 freetype_SelectFont, /* pSelectFont */
7353 NULL, /* pSelectPalette */
7354 NULL, /* pSelectPen */
7355 NULL, /* pSetArcDirection */
7356 NULL, /* pSetBkColor */
7357 NULL, /* pSetBkMode */
7358 NULL, /* pSetDCBrushColor */
7359 NULL, /* pSetDCPenColor */
7360 NULL, /* pSetDIBColorTable */
7361 NULL, /* pSetDIBitsToDevice */
7362 NULL, /* pSetDeviceClipping */
7363 NULL, /* pSetDeviceGammaRamp */
7364 NULL, /* pSetLayout */
7365 NULL, /* pSetMapMode */
7366 NULL, /* pSetMapperFlags */
7367 NULL, /* pSetPixel */
7368 NULL, /* pSetPixelFormat */
7369 NULL, /* pSetPolyFillMode */
7370 NULL, /* pSetROP2 */
7371 NULL, /* pSetRelAbs */
7372 NULL, /* pSetStretchBltMode */
7373 NULL, /* pSetTextAlign */
7374 NULL, /* pSetTextCharacterExtra */
7375 NULL, /* pSetTextColor */
7376 NULL, /* pSetTextJustification */
7377 NULL, /* pSetViewportExt */
7378 NULL, /* pSetViewportOrg */
7379 NULL, /* pSetWindowExt */
7380 NULL, /* pSetWindowOrg */
7381 NULL, /* pSetWorldTransform */
7382 NULL, /* pStartDoc */
7383 NULL, /* pStartPage */
7384 NULL, /* pStretchBlt */
7385 NULL, /* pStretchDIBits */
7386 NULL, /* pStrokeAndFillPath */
7387 NULL, /* pStrokePath */
7388 NULL, /* pSwapBuffers */
7389 NULL, /* pUnrealizePalette */
7390 NULL, /* pWidenPath */
7391 /* OpenGL not supported */
7394 #else /* HAVE_FREETYPE */
7396 /*************************************************************************/
7398 BOOL WineEngInit(void)
7400 return FALSE;
7402 BOOL WineEngDestroyFontInstance(HFONT hfont)
7404 return FALSE;
7407 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7409 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7410 return 1;
7413 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7415 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7416 return TRUE;
7419 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7421 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7422 return NULL;
7425 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7427 return FALSE;
7430 /*************************************************************************
7431 * GetRasterizerCaps (GDI32.@)
7433 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7435 lprs->nSize = sizeof(RASTERIZER_STATUS);
7436 lprs->wFlags = 0;
7437 lprs->nLanguageID = 0;
7438 return TRUE;
7441 #endif /* HAVE_FREETYPE */