gdi32: Add a helper to create a family.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob3afc2ea008a09f8e83409c36097865afc00b0a32
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;
1572 #define ADDFONT_EXTERNAL_FONT 0x01
1573 #define ADDFONT_FORCE_BITMAP 0x02
1574 #define ADDFONT_ADD_TO_CACHE 0x04
1576 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)
1578 int bitmap_num = 0;
1579 Family *family;
1580 WCHAR *StyleW;
1582 do {
1583 TT_OS2 *pOS2;
1584 TT_Header *pHeader;
1585 Face *face;
1586 struct list *face_elem_ptr;
1587 FT_WinFNT_HeaderRec winfnt_header;
1588 int internal_leading;
1589 FONTSIGNATURE fs;
1590 My_FT_Bitmap_Size *size = NULL;
1591 FT_ULong tmp_size;
1593 if(!FT_IS_SCALABLE(ft_face))
1594 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1596 family = get_family( ft_face, vertical );
1598 StyleW = towstr(CP_ACP, ft_face->style_name);
1600 internal_leading = 0;
1601 memset(&fs, 0, sizeof(fs));
1603 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1604 if(pOS2) {
1605 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1606 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1607 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1608 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1609 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1610 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1611 if(pOS2->version == 0) {
1612 FT_UInt dummy;
1614 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1615 fs.fsCsb[0] |= FS_LATIN1;
1616 else
1617 fs.fsCsb[0] |= FS_SYMBOL;
1620 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1621 CHARSETINFO csi;
1622 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1623 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1624 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1625 fs = csi.fs;
1626 internal_leading = winfnt_header.internal_leading;
1629 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1630 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1631 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1632 if(!strcmpiW(face->StyleName, StyleW) &&
1633 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1634 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1635 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1636 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1638 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1639 TRACE("Original font is newer so skipping this one\n");
1640 HeapFree(GetProcessHeap(), 0, StyleW);
1641 return;
1642 } else {
1643 TRACE("Replacing original with this one\n");
1644 list_remove(&face->entry);
1645 HeapFree(GetProcessHeap(), 0, face->file);
1646 HeapFree(GetProcessHeap(), 0, face->StyleName);
1647 HeapFree(GetProcessHeap(), 0, face->FullName);
1648 HeapFree(GetProcessHeap(), 0, face);
1649 break;
1653 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1654 face->cached_enum_data = NULL;
1655 face->StyleName = StyleW;
1656 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1657 if (file)
1659 face->file = strdupA(file);
1660 face->font_data_ptr = NULL;
1661 face->font_data_size = 0;
1663 else
1665 face->file = NULL;
1666 face->font_data_ptr = font_data_ptr;
1667 face->font_data_size = font_data_size;
1669 face->face_index = face_index;
1670 face->ntmFlags = 0;
1671 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1672 face->ntmFlags |= NTM_ITALIC;
1673 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1674 face->ntmFlags |= NTM_BOLD;
1675 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1676 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1677 face->family = family;
1678 face->vertical = vertical;
1679 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1680 face->fs = fs;
1682 if(FT_IS_SCALABLE(ft_face)) {
1683 memset(&face->size, 0, sizeof(face->size));
1684 face->scalable = TRUE;
1685 } else {
1686 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1687 size->height, size->width, size->size >> 6,
1688 size->x_ppem >> 6, size->y_ppem >> 6);
1689 face->size.height = size->height;
1690 face->size.width = size->width;
1691 face->size.size = size->size;
1692 face->size.x_ppem = size->x_ppem;
1693 face->size.y_ppem = size->y_ppem;
1694 face->size.internal_leading = internal_leading;
1695 face->scalable = FALSE;
1698 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1699 tmp_size = 0;
1700 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1702 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1703 face->ntmFlags |= NTM_PS_OPENTYPE;
1706 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1707 face->fs.fsCsb[0], face->fs.fsCsb[1],
1708 face->fs.fsUsb[0], face->fs.fsUsb[1],
1709 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1711 if(face->fs.fsCsb[0] == 0)
1713 int i;
1715 /* let's see if we can find any interesting cmaps */
1716 for(i = 0; i < ft_face->num_charmaps; i++) {
1717 switch(ft_face->charmaps[i]->encoding) {
1718 case FT_ENCODING_UNICODE:
1719 case FT_ENCODING_APPLE_ROMAN:
1720 face->fs.fsCsb[0] |= FS_LATIN1;
1721 break;
1722 case FT_ENCODING_MS_SYMBOL:
1723 face->fs.fsCsb[0] |= FS_SYMBOL;
1724 break;
1725 default:
1726 break;
1731 if(flags & ADDFONT_ADD_TO_CACHE)
1732 add_face_to_cache(face);
1734 AddFaceToFamily(face, family);
1736 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1738 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1739 debugstr_w(StyleW));
1742 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1744 FT_Face ft_face;
1745 TT_OS2 *pOS2;
1746 FT_Error err;
1747 FT_Long face_index = 0, num_faces;
1748 INT ret = 0;
1750 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1751 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1753 #ifdef HAVE_CARBON_CARBON_H
1754 if(file)
1756 char **mac_list = expand_mac_font(file);
1757 if(mac_list)
1759 BOOL had_one = FALSE;
1760 char **cursor;
1761 for(cursor = mac_list; *cursor; cursor++)
1763 had_one = TRUE;
1764 AddFontToList(*cursor, NULL, 0, flags);
1765 HeapFree(GetProcessHeap(), 0, *cursor);
1767 HeapFree(GetProcessHeap(), 0, mac_list);
1768 if(had_one)
1769 return 1;
1772 #endif /* HAVE_CARBON_CARBON_H */
1774 do {
1775 if (file)
1777 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1778 err = pFT_New_Face(library, file, face_index, &ft_face);
1779 } else
1781 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1782 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1785 if(err != 0) {
1786 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1787 return 0;
1790 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*/
1791 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1792 pFT_Done_Face(ft_face);
1793 return 0;
1796 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1797 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1798 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1799 pFT_Done_Face(ft_face);
1800 return 0;
1803 if(FT_IS_SFNT(ft_face))
1805 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1806 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1807 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))
1809 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1810 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1811 pFT_Done_Face(ft_face);
1812 return 0;
1815 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1816 we don't want to load these. */
1817 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1819 FT_ULong len = 0;
1821 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1823 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1824 pFT_Done_Face(ft_face);
1825 return 0;
1830 if(!ft_face->family_name || !ft_face->style_name) {
1831 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1832 pFT_Done_Face(ft_face);
1833 return 0;
1836 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1838 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1839 pFT_Done_Face(ft_face);
1840 return 0;
1843 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1844 ++ret;
1846 if (FT_HAS_VERTICAL(ft_face))
1848 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1849 ++ret;
1852 num_faces = ft_face->num_faces;
1853 pFT_Done_Face(ft_face);
1854 } while(num_faces > ++face_index);
1855 return ret;
1858 static void DumpFontList(void)
1860 Family *family;
1861 Face *face;
1862 struct list *family_elem_ptr, *face_elem_ptr;
1864 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1865 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1866 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1867 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1868 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1869 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1870 if(!face->scalable)
1871 TRACE(" %d", face->size.height);
1872 TRACE("\n");
1875 return;
1878 /***********************************************************
1879 * The replacement list is a way to map an entire font
1880 * family onto another family. For example adding
1882 * [HKCU\Software\Wine\Fonts\Replacements]
1883 * "Wingdings"="Winedings"
1885 * would enumerate the Winedings font both as Winedings and
1886 * Wingdings. However if a real Wingdings font is present the
1887 * replacement does not take place.
1890 static void LoadReplaceList(void)
1892 HKEY hkey;
1893 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1894 LPWSTR value;
1895 LPVOID data;
1896 CHAR familyA[400];
1898 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1899 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1901 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1902 &valuelen, &datalen, NULL, NULL);
1904 valuelen++; /* returned value doesn't include room for '\0' */
1905 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1906 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1908 dlen = datalen;
1909 vlen = valuelen;
1910 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1911 &dlen) == ERROR_SUCCESS) {
1912 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1913 /* "NewName"="Oldname" */
1914 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1916 if(!find_family_from_any_name(value))
1918 Family * const family = find_family_from_any_name(data);
1919 if (family != NULL)
1921 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1922 if (new_family != NULL)
1924 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1925 new_family->FamilyName = strdupW(value);
1926 new_family->EnglishName = NULL;
1927 list_init(&new_family->faces);
1928 new_family->replacement = &family->faces;
1929 list_add_tail(&font_list, &new_family->entry);
1932 else
1934 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1937 else
1939 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1941 /* reset dlen and vlen */
1942 dlen = datalen;
1943 vlen = valuelen;
1945 HeapFree(GetProcessHeap(), 0, data);
1946 HeapFree(GetProcessHeap(), 0, value);
1947 RegCloseKey(hkey);
1951 static const WCHAR *font_links_list[] =
1953 Lucida_Sans_Unicode,
1954 Microsoft_Sans_Serif,
1955 Tahoma
1958 static const struct font_links_defaults_list
1960 /* Keyed off substitution for "MS Shell Dlg" */
1961 const WCHAR *shelldlg;
1962 /* Maximum of four substitutes, plus terminating NULL pointer */
1963 const WCHAR *substitutes[5];
1964 } font_links_defaults_list[] =
1966 /* Non East-Asian */
1967 { Tahoma, /* FIXME unverified ordering */
1968 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
1970 /* Below lists are courtesy of
1971 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1973 /* Japanese */
1974 { MS_UI_Gothic,
1975 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
1977 /* Chinese Simplified */
1978 { SimSun,
1979 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
1981 /* Korean */
1982 { Gulim,
1983 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
1985 /* Chinese Traditional */
1986 { PMingLiU,
1987 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
1992 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
1994 SYSTEM_LINKS *font_link;
1996 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1998 if(!strcmpiW(font_link->font_name, name))
1999 return font_link;
2002 return NULL;
2005 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2007 const WCHAR *value;
2008 int i;
2009 FontSubst *psub;
2010 Family *family;
2011 Face *face;
2012 const char *file;
2013 WCHAR *fileW;
2015 if (values)
2017 SYSTEM_LINKS *font_link;
2019 psub = get_font_subst(&font_subst_list, name, -1);
2020 /* Don't store fonts that are only substitutes for other fonts */
2021 if(psub)
2023 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2024 return;
2027 font_link = find_font_link(name);
2028 if (font_link == NULL)
2030 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2031 font_link->font_name = strdupW(name);
2032 list_init(&font_link->links);
2033 list_add_tail(&system_links, &font_link->entry);
2036 memset(&font_link->fs, 0, sizeof font_link->fs);
2037 for (i = 0; values[i] != NULL; i++)
2039 const struct list *face_list;
2040 CHILD_FONT *child_font;
2042 value = values[i];
2043 if (!strcmpiW(name,value))
2044 continue;
2045 psub = get_font_subst(&font_subst_list, value, -1);
2046 if(psub)
2047 value = psub->to.name;
2048 family = find_family_from_name(value);
2049 if (!family)
2050 continue;
2051 file = NULL;
2052 /* Use first extant filename for this Family */
2053 face_list = get_face_list_from_family(family);
2054 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2056 if (!face->file)
2057 continue;
2058 file = strrchr(face->file, '/');
2059 if (!file)
2060 file = face->file;
2061 else
2062 file++;
2063 break;
2065 if (!file)
2066 continue;
2067 fileW = towstr(CP_UNIXCP, file);
2069 face = find_face_from_filename(fileW, value);
2070 if(!face)
2072 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2073 continue;
2076 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2077 child_font->face = face;
2078 child_font->font = NULL;
2079 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2080 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2081 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2082 list_add_tail(&font_link->links, &child_font->entry);
2084 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2085 HeapFree(GetProcessHeap(), 0, fileW);
2091 /*************************************************************
2092 * init_system_links
2094 static BOOL init_system_links(void)
2096 HKEY hkey;
2097 BOOL ret = FALSE;
2098 DWORD type, max_val, max_data, val_len, data_len, index;
2099 WCHAR *value, *data;
2100 WCHAR *entry, *next;
2101 SYSTEM_LINKS *font_link, *system_font_link;
2102 CHILD_FONT *child_font;
2103 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2104 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2105 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2106 Face *face;
2107 FontSubst *psub;
2108 UINT i, j;
2110 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2112 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2113 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2114 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2115 val_len = max_val + 1;
2116 data_len = max_data;
2117 index = 0;
2118 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2120 psub = get_font_subst(&font_subst_list, value, -1);
2121 /* Don't store fonts that are only substitutes for other fonts */
2122 if(psub)
2124 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2125 goto next;
2127 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2128 font_link->font_name = strdupW(value);
2129 memset(&font_link->fs, 0, sizeof font_link->fs);
2130 list_init(&font_link->links);
2131 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2133 WCHAR *face_name;
2134 CHILD_FONT *child_font;
2136 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2138 next = entry + strlenW(entry) + 1;
2140 face_name = strchrW(entry, ',');
2141 if(face_name)
2143 *face_name++ = 0;
2144 while(isspaceW(*face_name))
2145 face_name++;
2147 psub = get_font_subst(&font_subst_list, face_name, -1);
2148 if(psub)
2149 face_name = psub->to.name;
2151 face = find_face_from_filename(entry, face_name);
2152 if(!face)
2154 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2155 continue;
2158 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2159 child_font->face = face;
2160 child_font->font = NULL;
2161 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2162 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2163 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2164 list_add_tail(&font_link->links, &child_font->entry);
2166 list_add_tail(&system_links, &font_link->entry);
2167 next:
2168 val_len = max_val + 1;
2169 data_len = max_data;
2172 HeapFree(GetProcessHeap(), 0, value);
2173 HeapFree(GetProcessHeap(), 0, data);
2174 RegCloseKey(hkey);
2178 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2179 if (!psub) {
2180 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2181 goto skip_internal;
2184 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2186 const FontSubst *psub2;
2187 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2189 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2191 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2192 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2194 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2195 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2197 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2199 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2203 skip_internal:
2205 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2206 that Tahoma has */
2208 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2209 system_font_link->font_name = strdupW(System);
2210 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2211 list_init(&system_font_link->links);
2213 face = find_face_from_filename(tahoma_ttf, Tahoma);
2214 if(face)
2216 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2217 child_font->face = face;
2218 child_font->font = NULL;
2219 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2220 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2221 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2222 list_add_tail(&system_font_link->links, &child_font->entry);
2224 font_link = find_font_link(Tahoma);
2225 if (font_link != NULL)
2227 CHILD_FONT *font_link_entry;
2228 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2230 CHILD_FONT *new_child;
2231 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2232 new_child->face = font_link_entry->face;
2233 new_child->font = NULL;
2234 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2235 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2236 list_add_tail(&system_font_link->links, &new_child->entry);
2239 list_add_tail(&system_links, &system_font_link->entry);
2240 return ret;
2243 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2245 DIR *dir;
2246 struct dirent *dent;
2247 char path[MAX_PATH];
2249 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2251 dir = opendir(dirname);
2252 if(!dir) {
2253 WARN("Can't open directory %s\n", debugstr_a(dirname));
2254 return FALSE;
2256 while((dent = readdir(dir)) != NULL) {
2257 struct stat statbuf;
2259 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2260 continue;
2262 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2264 sprintf(path, "%s/%s", dirname, dent->d_name);
2266 if(stat(path, &statbuf) == -1)
2268 WARN("Can't stat %s\n", debugstr_a(path));
2269 continue;
2271 if(S_ISDIR(statbuf.st_mode))
2272 ReadFontDir(path, external_fonts);
2273 else
2275 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2276 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2277 AddFontToList(path, NULL, 0, addfont_flags);
2280 closedir(dir);
2281 return TRUE;
2284 static void load_fontconfig_fonts(void)
2286 #ifdef SONAME_LIBFONTCONFIG
2287 void *fc_handle = NULL;
2288 FcConfig *config;
2289 FcPattern *pat;
2290 FcObjectSet *os;
2291 FcFontSet *fontset;
2292 int i, len;
2293 char *file;
2294 const char *ext;
2296 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2297 if(!fc_handle) {
2298 TRACE("Wine cannot find the fontconfig library (%s).\n",
2299 SONAME_LIBFONTCONFIG);
2300 return;
2302 #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;}
2303 LOAD_FUNCPTR(FcConfigGetCurrent);
2304 LOAD_FUNCPTR(FcFontList);
2305 LOAD_FUNCPTR(FcFontSetDestroy);
2306 LOAD_FUNCPTR(FcInit);
2307 LOAD_FUNCPTR(FcObjectSetAdd);
2308 LOAD_FUNCPTR(FcObjectSetCreate);
2309 LOAD_FUNCPTR(FcObjectSetDestroy);
2310 LOAD_FUNCPTR(FcPatternCreate);
2311 LOAD_FUNCPTR(FcPatternDestroy);
2312 LOAD_FUNCPTR(FcPatternGetBool);
2313 LOAD_FUNCPTR(FcPatternGetString);
2314 #undef LOAD_FUNCPTR
2316 if(!pFcInit()) return;
2318 config = pFcConfigGetCurrent();
2319 pat = pFcPatternCreate();
2320 os = pFcObjectSetCreate();
2321 pFcObjectSetAdd(os, FC_FILE);
2322 pFcObjectSetAdd(os, FC_SCALABLE);
2323 fontset = pFcFontList(config, pat, os);
2324 if(!fontset) return;
2325 for(i = 0; i < fontset->nfont; i++) {
2326 FcBool scalable;
2328 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2329 continue;
2330 TRACE("fontconfig: %s\n", file);
2332 /* We're just interested in OT/TT fonts for now, so this hack just
2333 picks up the scalable fonts without extensions .pf[ab] to save time
2334 loading every other font */
2336 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2338 TRACE("not scalable\n");
2339 continue;
2342 len = strlen( file );
2343 if(len < 4) continue;
2344 ext = &file[ len - 3 ];
2345 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2346 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2348 pFcFontSetDestroy(fontset);
2349 pFcObjectSetDestroy(os);
2350 pFcPatternDestroy(pat);
2351 sym_not_found:
2352 #endif
2353 return;
2356 static BOOL load_font_from_data_dir(LPCWSTR file)
2358 BOOL ret = FALSE;
2359 const char *data_dir = wine_get_data_dir();
2361 if (!data_dir) data_dir = wine_get_build_dir();
2363 if (data_dir)
2365 INT len;
2366 char *unix_name;
2368 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2370 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2372 strcpy(unix_name, data_dir);
2373 strcat(unix_name, "/fonts/");
2375 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2377 EnterCriticalSection( &freetype_cs );
2378 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2379 LeaveCriticalSection( &freetype_cs );
2380 HeapFree(GetProcessHeap(), 0, unix_name);
2382 return ret;
2385 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2387 static const WCHAR slashW[] = {'\\','\0'};
2388 BOOL ret = FALSE;
2389 WCHAR windowsdir[MAX_PATH];
2390 char *unixname;
2392 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2393 strcatW(windowsdir, fontsW);
2394 strcatW(windowsdir, slashW);
2395 strcatW(windowsdir, file);
2396 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2397 EnterCriticalSection( &freetype_cs );
2398 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2399 LeaveCriticalSection( &freetype_cs );
2400 HeapFree(GetProcessHeap(), 0, unixname);
2402 return ret;
2405 static void load_system_fonts(void)
2407 HKEY hkey;
2408 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2409 const WCHAR * const *value;
2410 DWORD dlen, type;
2411 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2412 char *unixname;
2414 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2415 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2416 strcatW(windowsdir, fontsW);
2417 for(value = SystemFontValues; *value; value++) {
2418 dlen = sizeof(data);
2419 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2420 type == REG_SZ) {
2421 BOOL added = FALSE;
2423 sprintfW(pathW, fmtW, windowsdir, data);
2424 if((unixname = wine_get_unix_file_name(pathW))) {
2425 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2426 HeapFree(GetProcessHeap(), 0, unixname);
2428 if (!added)
2429 load_font_from_data_dir(data);
2432 RegCloseKey(hkey);
2436 /*************************************************************
2438 * This adds registry entries for any externally loaded fonts
2439 * (fonts from fontconfig or FontDirs). It also deletes entries
2440 * of no longer existing fonts.
2443 static void update_reg_entries(void)
2445 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2446 LPWSTR valueW;
2447 DWORD len, len_fam;
2448 Family *family;
2449 Face *face;
2450 struct list *family_elem_ptr, *face_elem_ptr;
2451 WCHAR *file;
2452 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2453 static const WCHAR spaceW[] = {' ', '\0'};
2454 char *path;
2456 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2457 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2458 ERR("Can't create Windows font reg key\n");
2459 goto end;
2462 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2463 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2464 ERR("Can't create Windows font reg key\n");
2465 goto end;
2468 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2469 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2470 ERR("Can't create external font reg key\n");
2471 goto end;
2474 /* enumerate the fonts and add external ones to the two keys */
2476 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2477 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2478 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2479 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2480 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2481 if(!face->external) continue;
2482 len = len_fam;
2483 if (!(face->ntmFlags & NTM_REGULAR))
2484 len = len_fam + strlenW(face->StyleName) + 1;
2485 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2486 strcpyW(valueW, family->FamilyName);
2487 if(len != len_fam) {
2488 strcatW(valueW, spaceW);
2489 strcatW(valueW, face->StyleName);
2491 strcatW(valueW, TrueType);
2493 file = wine_get_dos_file_name(face->file);
2494 if(file)
2495 len = strlenW(file) + 1;
2496 else
2498 if((path = strrchr(face->file, '/')) == NULL)
2499 path = face->file;
2500 else
2501 path++;
2502 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2504 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2505 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2507 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2508 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2509 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2511 HeapFree(GetProcessHeap(), 0, file);
2512 HeapFree(GetProcessHeap(), 0, valueW);
2515 end:
2516 if(external_key) RegCloseKey(external_key);
2517 if(win9x_key) RegCloseKey(win9x_key);
2518 if(winnt_key) RegCloseKey(winnt_key);
2519 return;
2522 static void delete_external_font_keys(void)
2524 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2525 DWORD dlen, vlen, datalen, valuelen, i, type;
2526 LPWSTR valueW;
2527 LPVOID data;
2529 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2530 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2531 ERR("Can't create Windows font reg key\n");
2532 goto end;
2535 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2536 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2537 ERR("Can't create Windows font reg key\n");
2538 goto end;
2541 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2542 ERR("Can't create external font reg key\n");
2543 goto end;
2546 /* Delete all external fonts added last time */
2548 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2549 &valuelen, &datalen, NULL, NULL);
2550 valuelen++; /* returned value doesn't include room for '\0' */
2551 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2552 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2554 dlen = datalen * sizeof(WCHAR);
2555 vlen = valuelen;
2556 i = 0;
2557 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2558 &dlen) == ERROR_SUCCESS) {
2560 RegDeleteValueW(winnt_key, valueW);
2561 RegDeleteValueW(win9x_key, valueW);
2562 /* reset dlen and vlen */
2563 dlen = datalen;
2564 vlen = valuelen;
2566 HeapFree(GetProcessHeap(), 0, data);
2567 HeapFree(GetProcessHeap(), 0, valueW);
2569 /* Delete the old external fonts key */
2570 RegCloseKey(external_key);
2571 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2573 end:
2574 if(win9x_key) RegCloseKey(win9x_key);
2575 if(winnt_key) RegCloseKey(winnt_key);
2578 /*************************************************************
2579 * WineEngAddFontResourceEx
2582 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2584 INT ret = 0;
2586 GDI_CheckNotLock();
2588 if (ft_handle) /* do it only if we have freetype up and running */
2590 char *unixname;
2592 if(flags)
2593 FIXME("Ignoring flags %x\n", flags);
2595 if((unixname = wine_get_unix_file_name(file)))
2597 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2599 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2600 EnterCriticalSection( &freetype_cs );
2601 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2602 LeaveCriticalSection( &freetype_cs );
2603 HeapFree(GetProcessHeap(), 0, unixname);
2605 if (!ret && !strchrW(file, '\\')) {
2606 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2607 ret = load_font_from_winfonts_dir(file);
2608 if (!ret) {
2609 /* Try in datadir/fonts (or builddir/fonts),
2610 * needed for Magic the Gathering Online
2612 ret = load_font_from_data_dir(file);
2616 return ret;
2619 /*************************************************************
2620 * WineEngAddFontMemResourceEx
2623 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2625 GDI_CheckNotLock();
2627 if (ft_handle) /* do it only if we have freetype up and running */
2629 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2631 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2632 memcpy(pFontCopy, pbFont, cbFont);
2634 EnterCriticalSection( &freetype_cs );
2635 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2636 LeaveCriticalSection( &freetype_cs );
2638 if (*pcFonts == 0)
2640 TRACE("AddFontToList failed\n");
2641 HeapFree(GetProcessHeap(), 0, pFontCopy);
2642 return 0;
2644 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2645 * For now return something unique but quite random
2647 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2648 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2651 *pcFonts = 0;
2652 return 0;
2655 /*************************************************************
2656 * WineEngRemoveFontResourceEx
2659 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2661 GDI_CheckNotLock();
2662 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2663 return TRUE;
2666 static const struct nls_update_font_list
2668 UINT ansi_cp, oem_cp;
2669 const char *oem, *fixed, *system;
2670 const char *courier, *serif, *small, *sserif;
2671 /* these are for font substitutes */
2672 const char *shelldlg, *tmsrmn;
2673 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2674 *helv_0, *tmsrmn_0;
2675 const struct subst
2677 const char *from, *to;
2678 } arial_0, courier_new_0, times_new_roman_0;
2679 } nls_update_font_list[] =
2681 /* Latin 1 (United States) */
2682 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2683 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2684 "Tahoma","Times New Roman",
2685 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2686 { 0 }, { 0 }, { 0 }
2688 /* Latin 1 (Multilingual) */
2689 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2690 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2691 "Tahoma","Times New Roman", /* FIXME unverified */
2692 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2693 { 0 }, { 0 }, { 0 }
2695 /* Eastern Europe */
2696 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2697 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2698 "Tahoma","Times New Roman", /* FIXME unverified */
2699 "Fixedsys,238", "System,238",
2700 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2701 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2702 { "Arial CE,0", "Arial,238" },
2703 { "Courier New CE,0", "Courier New,238" },
2704 { "Times New Roman CE,0", "Times New Roman,238" }
2706 /* Cyrillic */
2707 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2708 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2709 "Tahoma","Times New Roman", /* FIXME unverified */
2710 "Fixedsys,204", "System,204",
2711 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2712 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2713 { "Arial Cyr,0", "Arial,204" },
2714 { "Courier New Cyr,0", "Courier New,204" },
2715 { "Times New Roman Cyr,0", "Times New Roman,204" }
2717 /* Greek */
2718 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2719 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2720 "Tahoma","Times New Roman", /* FIXME unverified */
2721 "Fixedsys,161", "System,161",
2722 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2723 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2724 { "Arial Greek,0", "Arial,161" },
2725 { "Courier New Greek,0", "Courier New,161" },
2726 { "Times New Roman Greek,0", "Times New Roman,161" }
2728 /* Turkish */
2729 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2730 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2731 "Tahoma","Times New Roman", /* FIXME unverified */
2732 "Fixedsys,162", "System,162",
2733 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2734 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2735 { "Arial Tur,0", "Arial,162" },
2736 { "Courier New Tur,0", "Courier New,162" },
2737 { "Times New Roman Tur,0", "Times New Roman,162" }
2739 /* Hebrew */
2740 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2741 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2742 "Tahoma","Times New Roman", /* FIXME unverified */
2743 "Fixedsys,177", "System,177",
2744 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2745 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2746 { 0 }, { 0 }, { 0 }
2748 /* Arabic */
2749 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2750 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2751 "Tahoma","Times New Roman", /* FIXME unverified */
2752 "Fixedsys,178", "System,178",
2753 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2754 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2755 { 0 }, { 0 }, { 0 }
2757 /* Baltic */
2758 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2759 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2760 "Tahoma","Times New Roman", /* FIXME unverified */
2761 "Fixedsys,186", "System,186",
2762 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2763 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2764 { "Arial Baltic,0", "Arial,186" },
2765 { "Courier New Baltic,0", "Courier New,186" },
2766 { "Times New Roman Baltic,0", "Times New Roman,186" }
2768 /* Vietnamese */
2769 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2770 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2771 "Tahoma","Times New Roman", /* FIXME unverified */
2772 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2773 { 0 }, { 0 }, { 0 }
2775 /* Thai */
2776 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2777 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2778 "Tahoma","Times New Roman", /* FIXME unverified */
2779 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2780 { 0 }, { 0 }, { 0 }
2782 /* Japanese */
2783 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2784 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2785 "MS UI Gothic","MS Serif",
2786 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2787 { 0 }, { 0 }, { 0 }
2789 /* Chinese Simplified */
2790 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2791 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2792 "SimSun", "NSimSun",
2793 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2794 { 0 }, { 0 }, { 0 }
2796 /* Korean */
2797 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2798 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2799 "Gulim", "Batang",
2800 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2801 { 0 }, { 0 }, { 0 }
2803 /* Chinese Traditional */
2804 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2805 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2806 "PMingLiU", "MingLiU",
2807 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2808 { 0 }, { 0 }, { 0 }
2812 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2814 return ( ansi_cp == 932 /* CP932 for Japanese */
2815 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2816 || ansi_cp == 949 /* CP949 for Korean */
2817 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2820 static inline HKEY create_fonts_NT_registry_key(void)
2822 HKEY hkey = 0;
2824 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2825 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2826 return hkey;
2829 static inline HKEY create_fonts_9x_registry_key(void)
2831 HKEY hkey = 0;
2833 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2834 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2835 return hkey;
2838 static inline HKEY create_config_fonts_registry_key(void)
2840 HKEY hkey = 0;
2842 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2843 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2844 return hkey;
2847 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2849 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2850 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2851 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2852 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2855 static void set_value_key(HKEY hkey, const char *name, const char *value)
2857 if (value)
2858 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2859 else if (name)
2860 RegDeleteValueA(hkey, name);
2863 static void update_font_info(void)
2865 char buf[40], cpbuf[40];
2866 DWORD len, type;
2867 HKEY hkey = 0;
2868 UINT i, ansi_cp = 0, oem_cp = 0;
2869 BOOL done = FALSE;
2871 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2872 return;
2874 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2875 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2876 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2877 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2878 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2880 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2881 if (is_dbcs_ansi_cp(ansi_cp))
2882 use_default_fallback = TRUE;
2884 len = sizeof(buf);
2885 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2887 if (!strcmp( buf, cpbuf )) /* already set correctly */
2889 RegCloseKey(hkey);
2890 return;
2892 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2894 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2896 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2897 RegCloseKey(hkey);
2899 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2901 HKEY hkey;
2903 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2904 nls_update_font_list[i].oem_cp == oem_cp)
2906 hkey = create_config_fonts_registry_key();
2907 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2908 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2909 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2910 RegCloseKey(hkey);
2912 hkey = create_fonts_NT_registry_key();
2913 add_font_list(hkey, &nls_update_font_list[i]);
2914 RegCloseKey(hkey);
2916 hkey = create_fonts_9x_registry_key();
2917 add_font_list(hkey, &nls_update_font_list[i]);
2918 RegCloseKey(hkey);
2920 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2922 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2923 strlen(nls_update_font_list[i].shelldlg)+1);
2924 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2925 strlen(nls_update_font_list[i].tmsrmn)+1);
2927 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2928 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2929 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2930 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2931 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2932 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2933 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2934 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2936 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2937 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2938 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2940 RegCloseKey(hkey);
2942 done = TRUE;
2944 else
2946 /* Delete the FontSubstitutes from other locales */
2947 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2949 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2950 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2951 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2952 RegCloseKey(hkey);
2956 if (!done)
2957 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2960 static BOOL init_freetype(void)
2962 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2963 if(!ft_handle) {
2964 WINE_MESSAGE(
2965 "Wine cannot find the FreeType font library. To enable Wine to\n"
2966 "use TrueType fonts please install a version of FreeType greater than\n"
2967 "or equal to 2.0.5.\n"
2968 "http://www.freetype.org\n");
2969 return FALSE;
2972 #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;}
2974 LOAD_FUNCPTR(FT_Done_Face)
2975 LOAD_FUNCPTR(FT_Get_Char_Index)
2976 LOAD_FUNCPTR(FT_Get_First_Char)
2977 LOAD_FUNCPTR(FT_Get_Module)
2978 LOAD_FUNCPTR(FT_Get_Next_Char)
2979 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2980 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2981 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2982 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2983 LOAD_FUNCPTR(FT_Init_FreeType)
2984 LOAD_FUNCPTR(FT_Library_Version)
2985 LOAD_FUNCPTR(FT_Load_Glyph)
2986 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2987 LOAD_FUNCPTR(FT_Matrix_Multiply)
2988 #ifndef FT_MULFIX_INLINED
2989 LOAD_FUNCPTR(FT_MulFix)
2990 #endif
2991 LOAD_FUNCPTR(FT_New_Face)
2992 LOAD_FUNCPTR(FT_New_Memory_Face)
2993 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2994 LOAD_FUNCPTR(FT_Outline_Transform)
2995 LOAD_FUNCPTR(FT_Outline_Translate)
2996 LOAD_FUNCPTR(FT_Render_Glyph)
2997 LOAD_FUNCPTR(FT_Select_Charmap)
2998 LOAD_FUNCPTR(FT_Set_Charmap)
2999 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3000 LOAD_FUNCPTR(FT_Vector_Transform)
3001 LOAD_FUNCPTR(FT_Vector_Unit)
3002 #undef LOAD_FUNCPTR
3003 /* Don't warn if these ones are missing */
3004 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3005 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3006 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3007 #endif
3009 if(pFT_Init_FreeType(&library) != 0) {
3010 ERR("Can't init FreeType library\n");
3011 wine_dlclose(ft_handle, NULL, 0);
3012 ft_handle = NULL;
3013 return FALSE;
3015 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3017 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3018 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3019 ((FT_Version.minor << 8) & 0x00ff00) |
3020 ((FT_Version.patch ) & 0x0000ff);
3022 font_driver = &freetype_funcs;
3023 return TRUE;
3025 sym_not_found:
3026 WINE_MESSAGE(
3027 "Wine cannot find certain functions that it needs inside the FreeType\n"
3028 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3029 "FreeType to at least version 2.1.4.\n"
3030 "http://www.freetype.org\n");
3031 wine_dlclose(ft_handle, NULL, 0);
3032 ft_handle = NULL;
3033 return FALSE;
3036 static void init_font_list(void)
3038 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3039 static const WCHAR pathW[] = {'P','a','t','h',0};
3040 HKEY hkey;
3041 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3042 WCHAR windowsdir[MAX_PATH];
3043 char *unixname;
3044 const char *home;
3045 const char *data_dir;
3047 delete_external_font_keys();
3049 /* load the system bitmap fonts */
3050 load_system_fonts();
3052 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3053 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3054 strcatW(windowsdir, fontsW);
3055 if((unixname = wine_get_unix_file_name(windowsdir)))
3057 ReadFontDir(unixname, FALSE);
3058 HeapFree(GetProcessHeap(), 0, unixname);
3061 /* load the system truetype fonts */
3062 data_dir = wine_get_data_dir();
3063 if (!data_dir) data_dir = wine_get_build_dir();
3064 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3066 strcpy(unixname, data_dir);
3067 strcat(unixname, "/fonts/");
3068 ReadFontDir(unixname, TRUE);
3069 HeapFree(GetProcessHeap(), 0, unixname);
3072 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3073 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3074 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3075 will skip these. */
3076 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3077 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3078 &hkey) == ERROR_SUCCESS)
3080 LPWSTR data, valueW;
3081 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3082 &valuelen, &datalen, NULL, NULL);
3084 valuelen++; /* returned value doesn't include room for '\0' */
3085 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3086 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3087 if (valueW && data)
3089 dlen = datalen * sizeof(WCHAR);
3090 vlen = valuelen;
3091 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3092 &dlen) == ERROR_SUCCESS)
3094 if(data[0] && (data[1] == ':'))
3096 if((unixname = wine_get_unix_file_name(data)))
3098 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3099 HeapFree(GetProcessHeap(), 0, unixname);
3102 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3104 WCHAR pathW[MAX_PATH];
3105 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3106 BOOL added = FALSE;
3108 sprintfW(pathW, fmtW, windowsdir, data);
3109 if((unixname = wine_get_unix_file_name(pathW)))
3111 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3112 HeapFree(GetProcessHeap(), 0, unixname);
3114 if (!added)
3115 load_font_from_data_dir(data);
3117 /* reset dlen and vlen */
3118 dlen = datalen;
3119 vlen = valuelen;
3122 HeapFree(GetProcessHeap(), 0, data);
3123 HeapFree(GetProcessHeap(), 0, valueW);
3124 RegCloseKey(hkey);
3127 load_fontconfig_fonts();
3129 /* then look in any directories that we've specified in the config file */
3130 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3131 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3133 DWORD len;
3134 LPWSTR valueW;
3135 LPSTR valueA, ptr;
3137 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3139 len += sizeof(WCHAR);
3140 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3141 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3143 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3144 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3145 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3146 TRACE( "got font path %s\n", debugstr_a(valueA) );
3147 ptr = valueA;
3148 while (ptr)
3150 LPSTR next = strchr( ptr, ':' );
3151 if (next) *next++ = 0;
3152 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3153 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3155 strcpy( unixname, home );
3156 strcat( unixname, ptr + 1 );
3157 ReadFontDir( unixname, TRUE );
3158 HeapFree( GetProcessHeap(), 0, unixname );
3160 else
3161 ReadFontDir( ptr, TRUE );
3162 ptr = next;
3164 HeapFree( GetProcessHeap(), 0, valueA );
3166 HeapFree( GetProcessHeap(), 0, valueW );
3168 RegCloseKey(hkey);
3171 #ifdef __APPLE__
3172 /* Mac default font locations. */
3173 ReadFontDir( "/Library/Fonts", TRUE );
3174 ReadFontDir( "/Network/Library/Fonts", TRUE );
3175 ReadFontDir( "/System/Library/Fonts", TRUE );
3176 if ((home = getenv( "HOME" )))
3178 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3179 strcpy( unixname, home );
3180 strcat( unixname, "/Library/Fonts" );
3181 ReadFontDir( unixname, TRUE);
3182 HeapFree( GetProcessHeap(), 0, unixname );
3184 #endif
3187 static BOOL move_to_front(const WCHAR *name)
3189 Family *family, *cursor2;
3190 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3192 if(!strcmpiW(family->FamilyName, name))
3194 list_remove(&family->entry);
3195 list_add_head(&font_list, &family->entry);
3196 return TRUE;
3199 return FALSE;
3202 static BOOL set_default(const WCHAR **name_list)
3204 while (*name_list)
3206 if (move_to_front(*name_list)) return TRUE;
3207 name_list++;
3210 return FALSE;
3213 static void reorder_font_list(void)
3215 set_default( default_serif_list );
3216 set_default( default_fixed_list );
3217 set_default( default_sans_list );
3220 /*************************************************************
3221 * WineEngInit
3223 * Initialize FreeType library and create a list of available faces
3225 BOOL WineEngInit(void)
3227 HKEY hkey_font_cache;
3228 DWORD disposition;
3229 HANDLE font_mutex;
3231 /* update locale dependent font info in registry */
3232 update_font_info();
3234 if(!init_freetype()) return FALSE;
3236 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3238 ERR("Failed to create font mutex\n");
3239 return FALSE;
3241 WaitForSingleObject(font_mutex, INFINITE);
3243 create_font_cache_key(&hkey_font_cache, &disposition);
3245 if(disposition == REG_CREATED_NEW_KEY)
3246 init_font_list();
3247 else
3248 load_font_list_from_cache(hkey_font_cache);
3250 RegCloseKey(hkey_font_cache);
3252 reorder_font_list();
3254 DumpFontList();
3255 LoadSubstList();
3256 DumpSubstList();
3257 LoadReplaceList();
3259 if(disposition == REG_CREATED_NEW_KEY)
3260 update_reg_entries();
3262 init_system_links();
3264 ReleaseMutex(font_mutex);
3265 return TRUE;
3269 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3271 TT_OS2 *pOS2;
3272 TT_HoriHeader *pHori;
3274 LONG ppem;
3276 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3277 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3279 if(height == 0) height = 16;
3281 /* Calc. height of EM square:
3283 * For +ve lfHeight we have
3284 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3285 * Re-arranging gives:
3286 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3288 * For -ve lfHeight we have
3289 * |lfHeight| = ppem
3290 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3291 * with il = winAscent + winDescent - units_per_em]
3295 if(height > 0) {
3296 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3297 ppem = MulDiv(ft_face->units_per_EM, height,
3298 pHori->Ascender - pHori->Descender);
3299 else
3300 ppem = MulDiv(ft_face->units_per_EM, height,
3301 pOS2->usWinAscent + pOS2->usWinDescent);
3303 else
3304 ppem = -height;
3306 return ppem;
3309 static struct font_mapping *map_font_file( const char *name )
3311 struct font_mapping *mapping;
3312 struct stat st;
3313 int fd;
3315 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3316 if (fstat( fd, &st ) == -1) goto error;
3318 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3320 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3322 mapping->refcount++;
3323 close( fd );
3324 return mapping;
3327 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3328 goto error;
3330 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3331 close( fd );
3333 if (mapping->data == MAP_FAILED)
3335 HeapFree( GetProcessHeap(), 0, mapping );
3336 return NULL;
3338 mapping->refcount = 1;
3339 mapping->dev = st.st_dev;
3340 mapping->ino = st.st_ino;
3341 mapping->size = st.st_size;
3342 list_add_tail( &mappings_list, &mapping->entry );
3343 return mapping;
3345 error:
3346 close( fd );
3347 return NULL;
3350 static void unmap_font_file( struct font_mapping *mapping )
3352 if (!--mapping->refcount)
3354 list_remove( &mapping->entry );
3355 munmap( mapping->data, mapping->size );
3356 HeapFree( GetProcessHeap(), 0, mapping );
3360 static LONG load_VDMX(GdiFont*, LONG);
3362 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3364 FT_Error err;
3365 FT_Face ft_face;
3366 void *data_ptr;
3367 DWORD data_size;
3369 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3371 if (face->file)
3373 if (!(font->mapping = map_font_file( face->file )))
3375 WARN("failed to map %s\n", debugstr_a(face->file));
3376 return 0;
3378 data_ptr = font->mapping->data;
3379 data_size = font->mapping->size;
3381 else
3383 data_ptr = face->font_data_ptr;
3384 data_size = face->font_data_size;
3387 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3388 if(err) {
3389 ERR("FT_New_Face rets %d\n", err);
3390 return 0;
3393 /* set it here, as load_VDMX needs it */
3394 font->ft_face = ft_face;
3396 if(FT_IS_SCALABLE(ft_face)) {
3397 /* load the VDMX table if we have one */
3398 font->ppem = load_VDMX(font, height);
3399 if(font->ppem == 0)
3400 font->ppem = calc_ppem_for_height(ft_face, height);
3401 TRACE("height %d => ppem %d\n", height, font->ppem);
3403 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3404 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3405 } else {
3406 font->ppem = height;
3407 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3408 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3410 return ft_face;
3414 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3416 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3417 a single face with the requested charset. The idea is to check if
3418 the selected font supports the current ANSI codepage, if it does
3419 return the corresponding charset, else return the first charset */
3421 CHARSETINFO csi;
3422 int acp = GetACP(), i;
3423 DWORD fs0;
3425 *cp = acp;
3426 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3428 const SYSTEM_LINKS *font_link;
3430 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3431 return csi.ciCharset;
3433 font_link = find_font_link(family_name);
3434 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3435 return csi.ciCharset;
3438 for(i = 0; i < 32; i++) {
3439 fs0 = 1L << i;
3440 if(face->fs.fsCsb[0] & fs0) {
3441 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3442 *cp = csi.ciACP;
3443 return csi.ciCharset;
3445 else
3446 FIXME("TCI failing on %x\n", fs0);
3450 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3451 face->fs.fsCsb[0], face->file);
3452 *cp = acp;
3453 return DEFAULT_CHARSET;
3456 static GdiFont *alloc_font(void)
3458 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3459 ret->gmsize = 1;
3460 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3461 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3462 ret->potm = NULL;
3463 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3464 ret->total_kern_pairs = (DWORD)-1;
3465 ret->kern_pairs = NULL;
3466 list_init(&ret->hfontlist);
3467 list_init(&ret->child_fonts);
3468 return ret;
3471 static void free_font(GdiFont *font)
3473 struct list *cursor, *cursor2;
3474 DWORD i;
3476 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3478 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3479 list_remove(cursor);
3480 if(child->font)
3481 free_font(child->font);
3482 HeapFree(GetProcessHeap(), 0, child);
3485 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3487 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3488 DeleteObject(hfontlist->hfont);
3489 list_remove(&hfontlist->entry);
3490 HeapFree(GetProcessHeap(), 0, hfontlist);
3493 if (font->ft_face) pFT_Done_Face(font->ft_face);
3494 if (font->mapping) unmap_font_file( font->mapping );
3495 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3496 HeapFree(GetProcessHeap(), 0, font->potm);
3497 HeapFree(GetProcessHeap(), 0, font->name);
3498 for (i = 0; i < font->gmsize; i++)
3499 HeapFree(GetProcessHeap(),0,font->gm[i]);
3500 HeapFree(GetProcessHeap(), 0, font->gm);
3501 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3502 HeapFree(GetProcessHeap(), 0, font);
3506 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3508 FT_Face ft_face = font->ft_face;
3509 FT_ULong len;
3510 FT_Error err;
3512 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3514 if(!buf)
3515 len = 0;
3516 else
3517 len = cbData;
3519 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3521 /* make sure value of len is the value freetype says it needs */
3522 if (buf && len)
3524 FT_ULong needed = 0;
3525 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3526 if( !err && needed < len) len = needed;
3528 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3529 if (err)
3531 TRACE("Can't find table %c%c%c%c\n",
3532 /* bytes were reversed */
3533 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3534 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3535 return GDI_ERROR;
3537 return len;
3540 /*************************************************************
3541 * load_VDMX
3543 * load the vdmx entry for the specified height
3546 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3547 ( ( (FT_ULong)_x4 << 24 ) | \
3548 ( (FT_ULong)_x3 << 16 ) | \
3549 ( (FT_ULong)_x2 << 8 ) | \
3550 (FT_ULong)_x1 )
3552 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3554 typedef struct {
3555 BYTE bCharSet;
3556 BYTE xRatio;
3557 BYTE yStartRatio;
3558 BYTE yEndRatio;
3559 } Ratios;
3561 typedef struct {
3562 WORD recs;
3563 BYTE startsz;
3564 BYTE endsz;
3565 } VDMX_group;
3567 static LONG load_VDMX(GdiFont *font, LONG height)
3569 WORD hdr[3], tmp;
3570 VDMX_group group;
3571 BYTE devXRatio, devYRatio;
3572 USHORT numRecs, numRatios;
3573 DWORD result, offset = -1;
3574 LONG ppem = 0;
3575 int i;
3577 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3579 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3580 return ppem;
3582 /* FIXME: need the real device aspect ratio */
3583 devXRatio = 1;
3584 devYRatio = 1;
3586 numRecs = GET_BE_WORD(hdr[1]);
3587 numRatios = GET_BE_WORD(hdr[2]);
3589 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3590 for(i = 0; i < numRatios; i++) {
3591 Ratios ratio;
3593 offset = (3 * 2) + (i * sizeof(Ratios));
3594 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3595 offset = -1;
3597 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3599 if((ratio.xRatio == 0 &&
3600 ratio.yStartRatio == 0 &&
3601 ratio.yEndRatio == 0) ||
3602 (devXRatio == ratio.xRatio &&
3603 devYRatio >= ratio.yStartRatio &&
3604 devYRatio <= ratio.yEndRatio))
3606 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3607 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3608 offset = GET_BE_WORD(tmp);
3609 break;
3613 if(offset == -1) {
3614 FIXME("No suitable ratio found\n");
3615 return ppem;
3618 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3619 USHORT recs;
3620 BYTE startsz, endsz;
3621 WORD *vTable;
3623 recs = GET_BE_WORD(group.recs);
3624 startsz = group.startsz;
3625 endsz = group.endsz;
3627 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3629 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3630 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3631 if(result == GDI_ERROR) {
3632 FIXME("Failed to retrieve vTable\n");
3633 goto end;
3636 if(height > 0) {
3637 for(i = 0; i < recs; i++) {
3638 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3639 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3640 ppem = GET_BE_WORD(vTable[i * 3]);
3642 if(yMax + -yMin == height) {
3643 font->yMax = yMax;
3644 font->yMin = yMin;
3645 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3646 break;
3648 if(yMax + -yMin > height) {
3649 if(--i < 0) {
3650 ppem = 0;
3651 goto end; /* failed */
3653 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3654 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3655 ppem = GET_BE_WORD(vTable[i * 3]);
3656 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3657 break;
3660 if(!font->yMax) {
3661 ppem = 0;
3662 TRACE("ppem not found for height %d\n", height);
3665 end:
3666 HeapFree(GetProcessHeap(), 0, vTable);
3669 return ppem;
3672 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3674 if(font->font_desc.hash != fd->hash) return TRUE;
3675 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3676 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3677 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3678 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3681 static void calc_hash(FONT_DESC *pfd)
3683 DWORD hash = 0, *ptr, two_chars;
3684 WORD *pwc;
3685 unsigned int i;
3687 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3688 hash ^= *ptr;
3689 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3690 hash ^= *ptr;
3691 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3692 two_chars = *ptr;
3693 pwc = (WCHAR *)&two_chars;
3694 if(!*pwc) break;
3695 *pwc = toupperW(*pwc);
3696 pwc++;
3697 *pwc = toupperW(*pwc);
3698 hash ^= two_chars;
3699 if(!*pwc) break;
3701 hash ^= !pfd->can_use_bitmap;
3702 pfd->hash = hash;
3703 return;
3706 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3708 GdiFont *ret;
3709 FONT_DESC fd;
3710 HFONTLIST *hflist;
3711 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3713 fd.lf = *plf;
3714 fd.matrix = *pmat;
3715 fd.can_use_bitmap = can_use_bitmap;
3716 calc_hash(&fd);
3718 /* try the child list */
3719 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3720 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3721 if(!fontcmp(ret, &fd)) {
3722 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3723 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3724 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3725 if(hflist->hfont == hfont)
3726 return ret;
3731 /* try the in-use list */
3732 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3733 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3734 if(!fontcmp(ret, &fd)) {
3735 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3736 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3737 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3738 if(hflist->hfont == hfont)
3739 return ret;
3741 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3742 hflist->hfont = hfont;
3743 list_add_head(&ret->hfontlist, &hflist->entry);
3744 return ret;
3748 /* then the unused list */
3749 font_elem_ptr = list_head(&unused_gdi_font_list);
3750 while(font_elem_ptr) {
3751 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3752 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3753 if(!fontcmp(ret, &fd)) {
3754 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3755 assert(list_empty(&ret->hfontlist));
3756 TRACE("Found %p in unused list\n", ret);
3757 list_remove(&ret->entry);
3758 list_add_head(&gdi_font_list, &ret->entry);
3759 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3760 hflist->hfont = hfont;
3761 list_add_head(&ret->hfontlist, &hflist->entry);
3762 return ret;
3765 return NULL;
3768 static void add_to_cache(GdiFont *font)
3770 static DWORD cache_num = 1;
3772 font->cache_num = cache_num++;
3773 list_add_head(&gdi_font_list, &font->entry);
3776 /*************************************************************
3777 * create_child_font_list
3779 static BOOL create_child_font_list(GdiFont *font)
3781 BOOL ret = FALSE;
3782 SYSTEM_LINKS *font_link;
3783 CHILD_FONT *font_link_entry, *new_child;
3784 FontSubst *psub;
3785 WCHAR* font_name;
3787 psub = get_font_subst(&font_subst_list, font->name, -1);
3788 font_name = psub ? psub->to.name : font->name;
3789 font_link = find_font_link(font_name);
3790 if (font_link != NULL)
3792 TRACE("found entry in system list\n");
3793 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3795 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3796 new_child->face = font_link_entry->face;
3797 new_child->font = NULL;
3798 list_add_tail(&font->child_fonts, &new_child->entry);
3799 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3801 ret = TRUE;
3804 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3805 * Sans Serif. This is how asian windows get default fallbacks for fonts
3807 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3808 font->charset != OEM_CHARSET &&
3809 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3811 font_link = find_font_link(szDefaultFallbackLink);
3812 if (font_link != NULL)
3814 TRACE("found entry in default fallback list\n");
3815 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3817 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3818 new_child->face = font_link_entry->face;
3819 new_child->font = NULL;
3820 list_add_tail(&font->child_fonts, &new_child->entry);
3821 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3823 ret = TRUE;
3827 return ret;
3830 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3832 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3834 if (pFT_Set_Charmap)
3836 FT_Int i;
3837 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3839 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3841 for (i = 0; i < ft_face->num_charmaps; i++)
3843 if (ft_face->charmaps[i]->encoding == encoding)
3845 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3846 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3848 switch (ft_face->charmaps[i]->platform_id)
3850 default:
3851 cmap_def = ft_face->charmaps[i];
3852 break;
3853 case 0: /* Apple Unicode */
3854 cmap0 = ft_face->charmaps[i];
3855 break;
3856 case 1: /* Macintosh */
3857 cmap1 = ft_face->charmaps[i];
3858 break;
3859 case 2: /* ISO */
3860 cmap2 = ft_face->charmaps[i];
3861 break;
3862 case 3: /* Microsoft */
3863 cmap3 = ft_face->charmaps[i];
3864 break;
3868 if (cmap3) /* prefer Microsoft cmap table */
3869 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3870 else if (cmap1)
3871 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3872 else if (cmap2)
3873 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3874 else if (cmap0)
3875 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3876 else if (cmap_def)
3877 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3879 return ft_err == FT_Err_Ok;
3882 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3886 /*************************************************************
3887 * freetype_CreateDC
3889 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3890 LPCWSTR output, const DEVMODEW *devmode )
3892 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3894 if (!physdev) return FALSE;
3895 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3896 return TRUE;
3900 /*************************************************************
3901 * freetype_DeleteDC
3903 static BOOL freetype_DeleteDC( PHYSDEV dev )
3905 struct freetype_physdev *physdev = get_freetype_dev( dev );
3906 HeapFree( GetProcessHeap(), 0, physdev );
3907 return TRUE;
3911 /*************************************************************
3912 * freetype_SelectFont
3914 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3916 struct freetype_physdev *physdev = get_freetype_dev( dev );
3917 GdiFont *ret;
3918 Face *face, *best, *best_bitmap;
3919 Family *family, *last_resort_family;
3920 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
3921 INT height, width = 0;
3922 unsigned int score = 0, new_score;
3923 signed int diff = 0, newdiff;
3924 BOOL bd, it, can_use_bitmap, want_vertical;
3925 LOGFONTW lf;
3926 CHARSETINFO csi;
3927 HFONTLIST *hflist;
3928 FMAT2 dcmat;
3929 FontSubst *psub = NULL;
3930 DC *dc = get_dc_ptr( dev->hdc );
3931 const SYSTEM_LINKS *font_link;
3933 if (!hfont) /* notification that the font has been changed by another driver */
3935 dc->gdiFont = NULL;
3936 physdev->font = NULL;
3937 release_dc_ptr( dc );
3938 return 0;
3941 GetObjectW( hfont, sizeof(lf), &lf );
3942 lf.lfWidth = abs(lf.lfWidth);
3944 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3946 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3947 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3948 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3949 lf.lfEscapement);
3951 if(dc->GraphicsMode == GM_ADVANCED)
3953 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3954 /* Try to avoid not necessary glyph transformations */
3955 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3957 lf.lfHeight *= fabs(dcmat.eM11);
3958 lf.lfWidth *= fabs(dcmat.eM11);
3959 dcmat.eM11 = dcmat.eM22 = 1.0;
3962 else
3964 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3965 font scaling abilities. */
3966 dcmat.eM11 = dcmat.eM22 = 1.0;
3967 dcmat.eM21 = dcmat.eM12 = 0;
3968 if (dc->vport2WorldValid)
3970 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
3971 lf.lfOrientation = -lf.lfOrientation;
3972 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
3973 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
3977 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3978 dcmat.eM21, dcmat.eM22);
3980 GDI_CheckNotLock();
3981 EnterCriticalSection( &freetype_cs );
3983 /* check the cache first */
3984 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3985 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3986 goto done;
3989 if(list_empty(&font_list)) /* No fonts installed */
3991 TRACE("No fonts installed\n");
3992 goto done;
3995 TRACE("not in cache\n");
3996 ret = alloc_font();
3998 ret->font_desc.matrix = dcmat;
3999 ret->font_desc.lf = lf;
4000 ret->font_desc.can_use_bitmap = can_use_bitmap;
4001 calc_hash(&ret->font_desc);
4002 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4003 hflist->hfont = hfont;
4004 list_add_head(&ret->hfontlist, &hflist->entry);
4006 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4007 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4008 original value lfCharSet. Note this is a special case for
4009 Symbol and doesn't happen at least for "Wingdings*" */
4011 if(!strcmpiW(lf.lfFaceName, SymbolW))
4012 lf.lfCharSet = SYMBOL_CHARSET;
4014 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4015 switch(lf.lfCharSet) {
4016 case DEFAULT_CHARSET:
4017 csi.fs.fsCsb[0] = 0;
4018 break;
4019 default:
4020 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4021 csi.fs.fsCsb[0] = 0;
4022 break;
4026 family = NULL;
4027 if(lf.lfFaceName[0] != '\0') {
4028 CHILD_FONT *font_link_entry;
4029 LPWSTR FaceName = lf.lfFaceName;
4031 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4033 if(psub) {
4034 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4035 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4036 if (psub->to.charset != -1)
4037 lf.lfCharSet = psub->to.charset;
4040 /* We want a match on name and charset or just name if
4041 charset was DEFAULT_CHARSET. If the latter then
4042 we fixup the returned charset later in get_nearest_charset
4043 where we'll either use the charset of the current ansi codepage
4044 or if that's unavailable the first charset that the font supports.
4046 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4047 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4048 if (!strcmpiW(family->FamilyName, FaceName) ||
4049 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4051 font_link = find_font_link(family->FamilyName);
4052 face_list = get_face_list_from_family(family);
4053 LIST_FOR_EACH(face_elem_ptr, face_list) {
4054 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4055 if (!(face->scalable || can_use_bitmap))
4056 continue;
4057 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4058 goto found;
4059 if (font_link != NULL &&
4060 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4061 goto found;
4062 if (!csi.fs.fsCsb[0])
4063 goto found;
4068 /* Search by full face name. */
4069 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4070 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4071 face_list = get_face_list_from_family(family);
4072 LIST_FOR_EACH(face_elem_ptr, face_list) {
4073 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4074 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4075 (face->scalable || can_use_bitmap))
4077 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4078 goto found_face;
4079 font_link = find_font_link(family->FamilyName);
4080 if (font_link != NULL &&
4081 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4082 goto found_face;
4088 * Try check the SystemLink list first for a replacement font.
4089 * We may find good replacements there.
4091 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4093 if(!strcmpiW(font_link->font_name, FaceName) ||
4094 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4096 TRACE("found entry in system list\n");
4097 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4099 const SYSTEM_LINKS *links;
4101 face = font_link_entry->face;
4102 if (!(face->scalable || can_use_bitmap))
4103 continue;
4104 family = face->family;
4105 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4106 goto found;
4107 links = find_font_link(family->FamilyName);
4108 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4109 goto found;
4115 psub = NULL; /* substitution is no more relevant */
4117 /* If requested charset was DEFAULT_CHARSET then try using charset
4118 corresponding to the current ansi codepage */
4119 if (!csi.fs.fsCsb[0])
4121 INT acp = GetACP();
4122 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4123 FIXME("TCI failed on codepage %d\n", acp);
4124 csi.fs.fsCsb[0] = 0;
4125 } else
4126 lf.lfCharSet = csi.ciCharset;
4129 want_vertical = (lf.lfFaceName[0] == '@');
4131 /* Face families are in the top 4 bits of lfPitchAndFamily,
4132 so mask with 0xF0 before testing */
4134 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4135 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4136 strcpyW(lf.lfFaceName, defFixed);
4137 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4138 strcpyW(lf.lfFaceName, defSerif);
4139 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4140 strcpyW(lf.lfFaceName, defSans);
4141 else
4142 strcpyW(lf.lfFaceName, defSans);
4143 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4144 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4145 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4146 font_link = find_font_link(family->FamilyName);
4147 face_list = get_face_list_from_family(family);
4148 LIST_FOR_EACH(face_elem_ptr, face_list) {
4149 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4150 if (!(face->scalable || can_use_bitmap))
4151 continue;
4152 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4153 goto found;
4154 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4155 goto found;
4160 last_resort_family = NULL;
4161 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4162 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4163 font_link = find_font_link(family->FamilyName);
4164 face_list = get_face_list_from_family(family);
4165 LIST_FOR_EACH(face_elem_ptr, face_list) {
4166 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4167 if(face->vertical == want_vertical &&
4168 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4169 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4170 if(face->scalable)
4171 goto found;
4172 if(can_use_bitmap && !last_resort_family)
4173 last_resort_family = family;
4178 if(last_resort_family) {
4179 family = last_resort_family;
4180 csi.fs.fsCsb[0] = 0;
4181 goto found;
4184 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4185 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4186 face_list = get_face_list_from_family(family);
4187 LIST_FOR_EACH(face_elem_ptr, face_list) {
4188 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4189 if(face->scalable && face->vertical == want_vertical) {
4190 csi.fs.fsCsb[0] = 0;
4191 WARN("just using first face for now\n");
4192 goto found;
4194 if(can_use_bitmap && !last_resort_family)
4195 last_resort_family = family;
4198 if(!last_resort_family) {
4199 FIXME("can't find a single appropriate font - bailing\n");
4200 free_font(ret);
4201 ret = NULL;
4202 goto done;
4205 WARN("could only find a bitmap font - this will probably look awful!\n");
4206 family = last_resort_family;
4207 csi.fs.fsCsb[0] = 0;
4209 found:
4210 it = lf.lfItalic ? 1 : 0;
4211 bd = lf.lfWeight > 550 ? 1 : 0;
4213 height = lf.lfHeight;
4215 face = best = best_bitmap = NULL;
4216 font_link = find_font_link(family->FamilyName);
4217 face_list = get_face_list_from_family(family);
4218 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4220 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4221 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4222 !csi.fs.fsCsb[0])
4224 BOOL italic, bold;
4226 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4227 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4228 new_score = (italic ^ it) + (bold ^ bd);
4229 if(!best || new_score <= score)
4231 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4232 italic, bold, it, bd);
4233 score = new_score;
4234 best = face;
4235 if(best->scalable && score == 0) break;
4236 if(!best->scalable)
4238 if(height > 0)
4239 newdiff = height - (signed int)(best->size.height);
4240 else
4241 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4242 if(!best_bitmap || new_score < score ||
4243 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4245 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4246 diff = newdiff;
4247 best_bitmap = best;
4248 if(score == 0 && diff == 0) break;
4254 if(best)
4255 face = best->scalable ? best : best_bitmap;
4256 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4257 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4259 found_face:
4260 height = lf.lfHeight;
4262 ret->fs = face->fs;
4264 if(csi.fs.fsCsb[0]) {
4265 ret->charset = lf.lfCharSet;
4266 ret->codepage = csi.ciACP;
4268 else
4269 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4271 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4272 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4274 ret->aveWidth = height ? lf.lfWidth : 0;
4276 if(!face->scalable) {
4277 /* Windows uses integer scaling factors for bitmap fonts */
4278 INT scale, scaled_height;
4279 GdiFont *cachedfont;
4281 /* FIXME: rotation of bitmap fonts is ignored */
4282 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4283 if (ret->aveWidth)
4284 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4285 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4286 dcmat.eM11 = dcmat.eM22 = 1.0;
4287 /* As we changed the matrix, we need to search the cache for the font again,
4288 * otherwise we might explode the cache. */
4289 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4290 TRACE("Found cached font after non-scalable matrix rescale!\n");
4291 free_font( ret );
4292 ret = cachedfont;
4293 goto done;
4295 calc_hash(&ret->font_desc);
4297 if (height != 0) height = diff;
4298 height += face->size.height;
4300 scale = (height + face->size.height - 1) / face->size.height;
4301 scaled_height = scale * face->size.height;
4302 /* Only jump to the next height if the difference <= 25% original height */
4303 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4304 /* The jump between unscaled and doubled is delayed by 1 */
4305 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4306 ret->scale_y = scale;
4308 width = face->size.x_ppem >> 6;
4309 height = face->size.y_ppem >> 6;
4311 else
4312 ret->scale_y = 1.0;
4313 TRACE("font scale y: %f\n", ret->scale_y);
4315 ret->ft_face = OpenFontFace(ret, face, width, height);
4317 if (!ret->ft_face)
4319 free_font( ret );
4320 ret = NULL;
4321 goto done;
4324 ret->ntmFlags = face->ntmFlags;
4326 if (ret->charset == SYMBOL_CHARSET &&
4327 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4328 /* No ops */
4330 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4331 /* No ops */
4333 else {
4334 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4337 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4338 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4339 ret->underline = lf.lfUnderline ? 0xff : 0;
4340 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4341 create_child_font_list(ret);
4343 if (face->vertical) /* We need to try to load the GSUB table */
4345 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4346 if (length != GDI_ERROR)
4348 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4349 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4350 TRACE("Loaded GSUB table of %i bytes\n",length);
4354 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4356 add_to_cache(ret);
4357 done:
4358 if (ret)
4360 dc->gdiFont = ret;
4361 physdev->font = ret;
4363 LeaveCriticalSection( &freetype_cs );
4364 release_dc_ptr( dc );
4365 return ret ? hfont : 0;
4368 static void dump_gdi_font_list(void)
4370 GdiFont *gdiFont;
4371 struct list *elem_ptr;
4373 TRACE("---------- gdiFont Cache ----------\n");
4374 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4375 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4376 TRACE("gdiFont=%p %s %d\n",
4377 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4380 TRACE("---------- Unused gdiFont Cache ----------\n");
4381 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4382 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4383 TRACE("gdiFont=%p %s %d\n",
4384 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4387 TRACE("---------- Child gdiFont Cache ----------\n");
4388 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4389 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4390 TRACE("gdiFont=%p %s %d\n",
4391 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4395 /*************************************************************
4396 * WineEngDestroyFontInstance
4398 * free the gdiFont associated with this handle
4401 BOOL WineEngDestroyFontInstance(HFONT handle)
4403 GdiFont *gdiFont;
4404 HFONTLIST *hflist;
4405 BOOL ret = FALSE;
4406 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4407 int i = 0;
4409 GDI_CheckNotLock();
4410 EnterCriticalSection( &freetype_cs );
4412 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4414 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4415 while(hfontlist_elem_ptr) {
4416 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4417 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4418 if(hflist->hfont == handle) {
4419 TRACE("removing child font %p from child list\n", gdiFont);
4420 list_remove(&gdiFont->entry);
4421 LeaveCriticalSection( &freetype_cs );
4422 return TRUE;
4427 TRACE("destroying hfont=%p\n", handle);
4428 if(TRACE_ON(font))
4429 dump_gdi_font_list();
4431 font_elem_ptr = list_head(&gdi_font_list);
4432 while(font_elem_ptr) {
4433 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4434 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4436 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4437 while(hfontlist_elem_ptr) {
4438 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4439 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4440 if(hflist->hfont == handle) {
4441 list_remove(&hflist->entry);
4442 HeapFree(GetProcessHeap(), 0, hflist);
4443 ret = TRUE;
4446 if(list_empty(&gdiFont->hfontlist)) {
4447 TRACE("Moving to Unused list\n");
4448 list_remove(&gdiFont->entry);
4449 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4454 font_elem_ptr = list_head(&unused_gdi_font_list);
4455 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4456 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4457 while(font_elem_ptr) {
4458 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4459 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4460 TRACE("freeing %p\n", gdiFont);
4461 list_remove(&gdiFont->entry);
4462 free_font(gdiFont);
4464 LeaveCriticalSection( &freetype_cs );
4465 return ret;
4468 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4470 HRSRC rsrc;
4471 HGLOBAL hMem;
4472 WCHAR *p;
4473 int i;
4475 id += IDS_FIRST_SCRIPT;
4476 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4477 if (!rsrc) return 0;
4478 hMem = LoadResource( gdi32_module, rsrc );
4479 if (!hMem) return 0;
4481 p = LockResource( hMem );
4482 id &= 0x000f;
4483 while (id--) p += *p + 1;
4485 i = min(LF_FACESIZE - 1, *p);
4486 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4487 buffer[i] = 0;
4488 return i;
4492 /***************************************************
4493 * create_enum_charset_list
4495 * This function creates charset enumeration list because in DEFAULT_CHARSET
4496 * case, the ANSI codepage's charset takes precedence over other charsets.
4497 * This function works as a filter other than DEFAULT_CHARSET case.
4499 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4501 CHARSETINFO csi;
4502 DWORD n = 0;
4504 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4505 csi.fs.fsCsb[0] != 0) {
4506 list->element[n].mask = csi.fs.fsCsb[0];
4507 list->element[n].charset = csi.ciCharset;
4508 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4509 n++;
4511 else { /* charset is DEFAULT_CHARSET or invalid. */
4512 INT acp, i;
4514 /* Set the current codepage's charset as the first element. */
4515 acp = GetACP();
4516 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4517 csi.fs.fsCsb[0] != 0) {
4518 list->element[n].mask = csi.fs.fsCsb[0];
4519 list->element[n].charset = csi.ciCharset;
4520 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4521 n++;
4524 /* Fill out left elements. */
4525 for (i = 0; i < 32; i++) {
4526 FONTSIGNATURE fs;
4527 fs.fsCsb[0] = 1L << i;
4528 fs.fsCsb[1] = 0;
4529 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4530 continue; /* skip, already added. */
4531 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4532 continue; /* skip, this is an invalid fsCsb bit. */
4534 list->element[n].mask = fs.fsCsb[0];
4535 list->element[n].charset = csi.ciCharset;
4536 load_script_name( i, list->element[n].name );
4537 n++;
4540 list->total = n;
4542 return n;
4545 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4546 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4548 GdiFont *font;
4549 LONG width, height;
4551 if (face->cached_enum_data)
4553 TRACE("Cached\n");
4554 *pelf = face->cached_enum_data->elf;
4555 *pntm = face->cached_enum_data->ntm;
4556 *ptype = face->cached_enum_data->type;
4557 return;
4560 font = alloc_font();
4562 if(face->scalable) {
4563 height = -2048; /* 2048 is the most common em size */
4564 width = 0;
4565 } else {
4566 height = face->size.y_ppem >> 6;
4567 width = face->size.x_ppem >> 6;
4569 font->scale_y = 1.0;
4571 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4573 free_font(font);
4574 return;
4577 font->name = strdupW(face->family->FamilyName);
4578 font->ntmFlags = face->ntmFlags;
4580 if (get_outline_text_metrics(font))
4582 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4584 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4586 lstrcpynW(pelf->elfLogFont.lfFaceName,
4587 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4588 LF_FACESIZE);
4589 lstrcpynW(pelf->elfFullName,
4590 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4591 LF_FULLFACESIZE);
4592 lstrcpynW(pelf->elfStyle,
4593 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4594 LF_FACESIZE);
4596 else
4598 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4600 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4602 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4603 if (face->FullName)
4604 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4605 else
4606 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4607 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4610 pntm->ntmTm.ntmFlags = face->ntmFlags;
4611 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4612 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4613 pntm->ntmFontSig = face->fs;
4615 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4617 pelf->elfLogFont.lfEscapement = 0;
4618 pelf->elfLogFont.lfOrientation = 0;
4619 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4620 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4621 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4622 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4623 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4624 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4625 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4626 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4627 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4628 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4629 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4631 *ptype = 0;
4632 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4633 *ptype |= TRUETYPE_FONTTYPE;
4634 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4635 *ptype |= DEVICE_FONTTYPE;
4636 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4637 *ptype |= RASTER_FONTTYPE;
4639 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4640 if (face->cached_enum_data)
4642 face->cached_enum_data->elf = *pelf;
4643 face->cached_enum_data->ntm = *pntm;
4644 face->cached_enum_data->type = *ptype;
4647 free_font(font);
4650 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
4652 static const WCHAR spaceW[] = { ' ', 0 };
4654 strcpyW(full_name, family_name);
4655 strcatW(full_name, spaceW);
4656 strcatW(full_name, style_name);
4659 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4661 const struct list *face_list, *face_elem_ptr;
4663 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4665 face_list = get_face_list_from_family(family);
4666 LIST_FOR_EACH(face_elem_ptr, face_list)
4668 WCHAR full_family_name[LF_FULLFACESIZE];
4669 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4671 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4673 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4674 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4675 continue;
4678 create_full_name(full_family_name, family->FamilyName, face->StyleName);
4679 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4682 return FALSE;
4685 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
4687 WCHAR full_family_name[LF_FULLFACESIZE];
4689 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
4691 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4693 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4694 debugstr_w(family_name), debugstr_w(face->StyleName));
4695 return FALSE;
4698 create_full_name(full_family_name, family_name, face->StyleName);
4699 return !strcmpiW(lf->lfFaceName, full_family_name);
4702 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
4703 FONTENUMPROCW proc, LPARAM lparam)
4705 ENUMLOGFONTEXW elf;
4706 NEWTEXTMETRICEXW ntm;
4707 DWORD type = 0;
4708 int i;
4710 GetEnumStructs(face, &elf, &ntm, &type);
4711 for(i = 0; i < list->total; i++) {
4712 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4713 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4714 load_script_name( IDS_OEM_DOS, elf.elfScript );
4715 i = list->total; /* break out of loop after enumeration */
4716 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4717 continue;
4718 else {
4719 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4720 strcpyW(elf.elfScript, list->element[i].name);
4721 if (!elf.elfScript[0])
4722 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4724 /* Font Replacement */
4725 if (family != face->family)
4727 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
4728 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
4730 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4731 debugstr_w(elf.elfLogFont.lfFaceName),
4732 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4733 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4734 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4735 ntm.ntmTm.ntmFlags);
4736 /* release section before callback (FIXME) */
4737 LeaveCriticalSection( &freetype_cs );
4738 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4739 EnterCriticalSection( &freetype_cs );
4741 return TRUE;
4744 /*************************************************************
4745 * freetype_EnumFonts
4747 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4749 Family *family;
4750 Face *face;
4751 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4752 LOGFONTW lf;
4753 struct enum_charset_list enum_charsets;
4755 if (!plf)
4757 lf.lfCharSet = DEFAULT_CHARSET;
4758 lf.lfPitchAndFamily = 0;
4759 lf.lfFaceName[0] = 0;
4760 plf = &lf;
4763 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4765 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4767 GDI_CheckNotLock();
4768 EnterCriticalSection( &freetype_cs );
4769 if(plf->lfFaceName[0]) {
4770 FontSubst *psub;
4771 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4773 if(psub) {
4774 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4775 debugstr_w(psub->to.name));
4776 lf = *plf;
4777 strcpyW(lf.lfFaceName, psub->to.name);
4778 plf = &lf;
4781 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4782 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4783 if(family_matches(family, plf)) {
4784 face_list = get_face_list_from_family(family);
4785 LIST_FOR_EACH(face_elem_ptr, face_list) {
4786 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4787 if (!face_matches(family->FamilyName, face, plf)) continue;
4788 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4792 } else {
4793 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4794 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4795 face_list = get_face_list_from_family(family);
4796 face_elem_ptr = list_head(face_list);
4797 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4798 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4801 LeaveCriticalSection( &freetype_cs );
4802 return TRUE;
4805 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4807 pt->x.value = vec->x >> 6;
4808 pt->x.fract = (vec->x & 0x3f) << 10;
4809 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4810 pt->y.value = vec->y >> 6;
4811 pt->y.fract = (vec->y & 0x3f) << 10;
4812 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4813 return;
4816 /***************************************************
4817 * According to the MSDN documentation on WideCharToMultiByte,
4818 * certain codepages cannot set the default_used parameter.
4819 * This returns TRUE if the codepage can set that parameter, false else
4820 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4822 static BOOL codepage_sets_default_used(UINT codepage)
4824 switch (codepage)
4826 case CP_UTF7:
4827 case CP_UTF8:
4828 case CP_SYMBOL:
4829 return FALSE;
4830 default:
4831 return TRUE;
4836 * GSUB Table handling functions
4839 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4841 const GSUB_CoverageFormat1* cf1;
4843 cf1 = table;
4845 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4847 int count = GET_BE_WORD(cf1->GlyphCount);
4848 int i;
4849 TRACE("Coverage Format 1, %i glyphs\n",count);
4850 for (i = 0; i < count; i++)
4851 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4852 return i;
4853 return -1;
4855 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4857 const GSUB_CoverageFormat2* cf2;
4858 int i;
4859 int count;
4860 cf2 = (const GSUB_CoverageFormat2*)cf1;
4862 count = GET_BE_WORD(cf2->RangeCount);
4863 TRACE("Coverage Format 2, %i ranges\n",count);
4864 for (i = 0; i < count; i++)
4866 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4867 return -1;
4868 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4869 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4871 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4872 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4875 return -1;
4877 else
4878 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4880 return -1;
4883 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4885 const GSUB_ScriptList *script;
4886 const GSUB_Script *deflt = NULL;
4887 int i;
4888 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4890 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4891 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4893 const GSUB_Script *scr;
4894 int offset;
4896 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4897 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4899 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4900 return scr;
4901 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4902 deflt = scr;
4904 return deflt;
4907 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4909 int i;
4910 int offset;
4911 const GSUB_LangSys *Lang;
4913 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4915 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4917 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4918 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4920 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4921 return Lang;
4923 offset = GET_BE_WORD(script->DefaultLangSys);
4924 if (offset)
4926 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4927 return Lang;
4929 return NULL;
4932 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4934 int i;
4935 const GSUB_FeatureList *feature;
4936 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4938 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4939 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4941 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4942 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4944 const GSUB_Feature *feat;
4945 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4946 return feat;
4949 return NULL;
4952 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4954 int i;
4955 int offset;
4956 const GSUB_LookupList *lookup;
4957 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4959 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4960 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4962 const GSUB_LookupTable *look;
4963 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4964 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4965 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4966 if (GET_BE_WORD(look->LookupType) != 1)
4967 FIXME("We only handle SubType 1\n");
4968 else
4970 int j;
4972 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4974 const GSUB_SingleSubstFormat1 *ssf1;
4975 offset = GET_BE_WORD(look->SubTable[j]);
4976 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4977 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4979 int offset = GET_BE_WORD(ssf1->Coverage);
4980 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4981 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4983 TRACE(" Glyph 0x%x ->",glyph);
4984 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4985 TRACE(" 0x%x\n",glyph);
4988 else
4990 const GSUB_SingleSubstFormat2 *ssf2;
4991 INT index;
4992 INT offset;
4994 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4995 offset = GET_BE_WORD(ssf1->Coverage);
4996 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4997 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4998 TRACE(" Coverage index %i\n",index);
4999 if (index != -1)
5001 TRACE(" Glyph is 0x%x ->",glyph);
5002 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5003 TRACE("0x%x\n",glyph);
5009 return glyph;
5012 static const char* get_opentype_script(const GdiFont *font)
5015 * I am not sure if this is the correct way to generate our script tag
5018 switch (font->charset)
5020 case ANSI_CHARSET: return "latn";
5021 case BALTIC_CHARSET: return "latn"; /* ?? */
5022 case CHINESEBIG5_CHARSET: return "hani";
5023 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5024 case GB2312_CHARSET: return "hani";
5025 case GREEK_CHARSET: return "grek";
5026 case HANGUL_CHARSET: return "hang";
5027 case RUSSIAN_CHARSET: return "cyrl";
5028 case SHIFTJIS_CHARSET: return "kana";
5029 case TURKISH_CHARSET: return "latn"; /* ?? */
5030 case VIETNAMESE_CHARSET: return "latn";
5031 case JOHAB_CHARSET: return "latn"; /* ?? */
5032 case ARABIC_CHARSET: return "arab";
5033 case HEBREW_CHARSET: return "hebr";
5034 case THAI_CHARSET: return "thai";
5035 default: return "latn";
5039 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5041 const GSUB_Header *header;
5042 const GSUB_Script *script;
5043 const GSUB_LangSys *language;
5044 const GSUB_Feature *feature;
5046 if (!font->GSUB_Table)
5047 return glyph;
5049 header = font->GSUB_Table;
5051 script = GSUB_get_script_table(header, get_opentype_script(font));
5052 if (!script)
5054 TRACE("Script not found\n");
5055 return glyph;
5057 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5058 if (!language)
5060 TRACE("Language not found\n");
5061 return glyph;
5063 feature = GSUB_get_feature(header, language, "vrt2");
5064 if (!feature)
5065 feature = GSUB_get_feature(header, language, "vert");
5066 if (!feature)
5068 TRACE("vrt2/vert feature not found\n");
5069 return glyph;
5071 return GSUB_apply_feature(header, feature, glyph);
5074 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5076 FT_UInt glyphId;
5078 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5079 WCHAR wc = (WCHAR)glyph;
5080 BOOL default_used;
5081 BOOL *default_used_pointer;
5082 FT_UInt ret;
5083 char buf;
5084 default_used_pointer = NULL;
5085 default_used = FALSE;
5086 if (codepage_sets_default_used(font->codepage))
5087 default_used_pointer = &default_used;
5088 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5089 ret = 0;
5090 else
5091 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5092 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5093 return ret;
5096 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5098 if (glyph < 0x100) glyph += 0xf000;
5099 /* there is a number of old pre-Unicode "broken" TTFs, which
5100 do have symbols at U+00XX instead of U+f0XX */
5101 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5102 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5104 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5106 return glyphId;
5109 /*************************************************************
5110 * freetype_GetGlyphIndices
5112 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5114 struct freetype_physdev *physdev = get_freetype_dev( dev );
5115 int i;
5116 WORD default_char;
5117 BOOL got_default = FALSE;
5119 if (!physdev->font)
5121 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5122 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5125 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5127 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5128 got_default = TRUE;
5131 GDI_CheckNotLock();
5132 EnterCriticalSection( &freetype_cs );
5134 for(i = 0; i < count; i++)
5136 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5137 if (pgi[i] == 0)
5139 if (!got_default)
5141 if (FT_IS_SFNT(physdev->font->ft_face))
5143 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5144 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5146 else
5148 TEXTMETRICW textm;
5149 get_text_metrics(physdev->font, &textm);
5150 default_char = textm.tmDefaultChar;
5152 got_default = TRUE;
5154 pgi[i] = default_char;
5157 LeaveCriticalSection( &freetype_cs );
5158 return count;
5161 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5163 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5164 return !memcmp(matrix, &identity, sizeof(FMAT2));
5167 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5169 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5170 return !memcmp(matrix, &identity, sizeof(MAT2));
5173 static inline BYTE get_max_level( UINT format )
5175 switch( format )
5177 case GGO_GRAY2_BITMAP: return 4;
5178 case GGO_GRAY4_BITMAP: return 16;
5179 case GGO_GRAY8_BITMAP: return 64;
5181 return 255;
5184 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5186 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5187 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5188 const MAT2* lpmat)
5190 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5191 FT_Face ft_face = incoming_font->ft_face;
5192 GdiFont *font = incoming_font;
5193 FT_UInt glyph_index;
5194 DWORD width, height, pitch, needed = 0;
5195 FT_Bitmap ft_bitmap;
5196 FT_Error err;
5197 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5198 FT_Angle angle = 0;
5199 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5200 double widthRatio = 1.0;
5201 FT_Matrix transMat = identityMat;
5202 FT_Matrix transMatUnrotated;
5203 BOOL needsTransform = FALSE;
5204 BOOL tategaki = (font->GSUB_Table != NULL);
5205 UINT original_index;
5207 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5208 buflen, buf, lpmat);
5210 TRACE("font transform %f %f %f %f\n",
5211 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5212 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5214 if(format & GGO_GLYPH_INDEX) {
5215 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5216 original_index = glyph;
5217 format &= ~GGO_GLYPH_INDEX;
5218 } else {
5219 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5220 ft_face = font->ft_face;
5221 original_index = glyph_index;
5224 if(format & GGO_UNHINTED) {
5225 load_flags |= FT_LOAD_NO_HINTING;
5226 format &= ~GGO_UNHINTED;
5229 /* tategaki never appears to happen to lower glyph index */
5230 if (glyph_index < TATEGAKI_LOWER_BOUND )
5231 tategaki = FALSE;
5233 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5234 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5235 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5236 font->gmsize * sizeof(GM*));
5237 } else {
5238 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5239 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5241 *lpgm = FONT_GM(font,original_index)->gm;
5242 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5243 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5244 lpgm->gmCellIncX, lpgm->gmCellIncY);
5245 return 1; /* FIXME */
5249 if (!font->gm[original_index / GM_BLOCK_SIZE])
5250 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5252 /* Scaling factor */
5253 if (font->aveWidth)
5255 TEXTMETRICW tm;
5257 get_text_metrics(font, &tm);
5259 widthRatio = (double)font->aveWidth;
5260 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5262 else
5263 widthRatio = font->scale_y;
5265 /* Scaling transform */
5266 if (widthRatio != 1.0 || font->scale_y != 1.0)
5268 FT_Matrix scaleMat;
5269 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5270 scaleMat.xy = 0;
5271 scaleMat.yx = 0;
5272 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5274 pFT_Matrix_Multiply(&scaleMat, &transMat);
5275 needsTransform = TRUE;
5278 /* Slant transform */
5279 if (font->fake_italic) {
5280 FT_Matrix slantMat;
5282 slantMat.xx = (1 << 16);
5283 slantMat.xy = ((1 << 16) >> 2);
5284 slantMat.yx = 0;
5285 slantMat.yy = (1 << 16);
5286 pFT_Matrix_Multiply(&slantMat, &transMat);
5287 needsTransform = TRUE;
5290 /* Rotation transform */
5291 transMatUnrotated = transMat;
5292 if(font->orientation && !tategaki) {
5293 FT_Matrix rotationMat;
5294 FT_Vector vecAngle;
5295 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5296 pFT_Vector_Unit(&vecAngle, angle);
5297 rotationMat.xx = vecAngle.x;
5298 rotationMat.xy = -vecAngle.y;
5299 rotationMat.yx = -rotationMat.xy;
5300 rotationMat.yy = rotationMat.xx;
5302 pFT_Matrix_Multiply(&rotationMat, &transMat);
5303 needsTransform = TRUE;
5306 /* World transform */
5307 if (!is_identity_FMAT2(&font->font_desc.matrix))
5309 FT_Matrix worldMat;
5310 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5311 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5312 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5313 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5314 pFT_Matrix_Multiply(&worldMat, &transMat);
5315 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5316 needsTransform = TRUE;
5319 /* Extra transformation specified by caller */
5320 if (!is_identity_MAT2(lpmat))
5322 FT_Matrix extraMat;
5323 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5324 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5325 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5326 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5327 pFT_Matrix_Multiply(&extraMat, &transMat);
5328 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5329 needsTransform = TRUE;
5332 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5333 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5334 format == GGO_GRAY8_BITMAP))
5336 load_flags |= FT_LOAD_NO_BITMAP;
5339 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5341 if(err) {
5342 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5343 return GDI_ERROR;
5346 if(!needsTransform) {
5347 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5348 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5349 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5351 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5352 bottom = (ft_face->glyph->metrics.horiBearingY -
5353 ft_face->glyph->metrics.height) & -64;
5354 lpgm->gmCellIncX = adv;
5355 lpgm->gmCellIncY = 0;
5356 } else {
5357 INT xc, yc;
5358 FT_Vector vec;
5360 left = right = 0;
5362 for(xc = 0; xc < 2; xc++) {
5363 for(yc = 0; yc < 2; yc++) {
5364 vec.x = (ft_face->glyph->metrics.horiBearingX +
5365 xc * ft_face->glyph->metrics.width);
5366 vec.y = ft_face->glyph->metrics.horiBearingY -
5367 yc * ft_face->glyph->metrics.height;
5368 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5369 pFT_Vector_Transform(&vec, &transMat);
5370 if(xc == 0 && yc == 0) {
5371 left = right = vec.x;
5372 top = bottom = vec.y;
5373 } else {
5374 if(vec.x < left) left = vec.x;
5375 else if(vec.x > right) right = vec.x;
5376 if(vec.y < bottom) bottom = vec.y;
5377 else if(vec.y > top) top = vec.y;
5381 left = left & -64;
5382 right = (right + 63) & -64;
5383 bottom = bottom & -64;
5384 top = (top + 63) & -64;
5386 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5387 vec.x = ft_face->glyph->metrics.horiAdvance;
5388 vec.y = 0;
5389 pFT_Vector_Transform(&vec, &transMat);
5390 lpgm->gmCellIncX = (vec.x+63) >> 6;
5391 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5393 vec.x = ft_face->glyph->metrics.horiAdvance;
5394 vec.y = 0;
5395 pFT_Vector_Transform(&vec, &transMatUnrotated);
5396 adv = (vec.x+63) >> 6;
5399 lsb = left >> 6;
5400 bbx = (right - left) >> 6;
5401 lpgm->gmBlackBoxX = (right - left) >> 6;
5402 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5403 lpgm->gmptGlyphOrigin.x = left >> 6;
5404 lpgm->gmptGlyphOrigin.y = top >> 6;
5406 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5407 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5408 lpgm->gmCellIncX, lpgm->gmCellIncY);
5410 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5411 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5413 FONT_GM(font,original_index)->gm = *lpgm;
5414 FONT_GM(font,original_index)->adv = adv;
5415 FONT_GM(font,original_index)->lsb = lsb;
5416 FONT_GM(font,original_index)->bbx = bbx;
5417 FONT_GM(font,original_index)->init = TRUE;
5420 if(format == GGO_METRICS)
5422 return 1; /* FIXME */
5425 if(ft_face->glyph->format != ft_glyph_format_outline &&
5426 (format == GGO_NATIVE || format == GGO_BEZIER))
5428 TRACE("loaded a bitmap\n");
5429 return GDI_ERROR;
5432 switch(format) {
5433 case GGO_BITMAP:
5434 width = lpgm->gmBlackBoxX;
5435 height = lpgm->gmBlackBoxY;
5436 pitch = ((width + 31) >> 5) << 2;
5437 needed = pitch * height;
5439 if(!buf || !buflen) break;
5441 switch(ft_face->glyph->format) {
5442 case ft_glyph_format_bitmap:
5444 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5445 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5446 INT h = ft_face->glyph->bitmap.rows;
5447 while(h--) {
5448 memcpy(dst, src, w);
5449 src += ft_face->glyph->bitmap.pitch;
5450 dst += pitch;
5452 break;
5455 case ft_glyph_format_outline:
5456 ft_bitmap.width = width;
5457 ft_bitmap.rows = height;
5458 ft_bitmap.pitch = pitch;
5459 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5460 ft_bitmap.buffer = buf;
5462 if(needsTransform)
5463 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5465 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5467 /* Note: FreeType will only set 'black' bits for us. */
5468 memset(buf, 0, needed);
5469 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5470 break;
5472 default:
5473 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5474 return GDI_ERROR;
5476 break;
5478 case GGO_GRAY2_BITMAP:
5479 case GGO_GRAY4_BITMAP:
5480 case GGO_GRAY8_BITMAP:
5481 case WINE_GGO_GRAY16_BITMAP:
5483 unsigned int max_level, row, col;
5484 BYTE *start, *ptr;
5486 width = lpgm->gmBlackBoxX;
5487 height = lpgm->gmBlackBoxY;
5488 pitch = (width + 3) / 4 * 4;
5489 needed = pitch * height;
5491 if(!buf || !buflen) break;
5493 max_level = get_max_level( format );
5495 switch(ft_face->glyph->format) {
5496 case ft_glyph_format_bitmap:
5498 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5499 INT h = ft_face->glyph->bitmap.rows;
5500 INT x;
5501 memset( buf, 0, needed );
5502 while(h--) {
5503 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5504 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5505 src += ft_face->glyph->bitmap.pitch;
5506 dst += pitch;
5508 return needed;
5510 case ft_glyph_format_outline:
5512 ft_bitmap.width = width;
5513 ft_bitmap.rows = height;
5514 ft_bitmap.pitch = pitch;
5515 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5516 ft_bitmap.buffer = buf;
5518 if(needsTransform)
5519 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5521 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5523 memset(ft_bitmap.buffer, 0, buflen);
5525 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5527 if (max_level != 255)
5529 for (row = 0, start = buf; row < height; row++)
5531 for (col = 0, ptr = start; col < width; col++, ptr++)
5532 *ptr = (((int)*ptr) * max_level + 128) / 256;
5533 start += pitch;
5536 return needed;
5539 default:
5540 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5541 return GDI_ERROR;
5543 break;
5546 case WINE_GGO_HRGB_BITMAP:
5547 case WINE_GGO_HBGR_BITMAP:
5548 case WINE_GGO_VRGB_BITMAP:
5549 case WINE_GGO_VBGR_BITMAP:
5550 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5552 switch (ft_face->glyph->format)
5554 case FT_GLYPH_FORMAT_BITMAP:
5556 BYTE *src, *dst;
5557 INT src_pitch, x;
5559 width = lpgm->gmBlackBoxX;
5560 height = lpgm->gmBlackBoxY;
5561 pitch = width * 4;
5562 needed = pitch * height;
5564 if (!buf || !buflen) break;
5566 memset(buf, 0, buflen);
5567 dst = buf;
5568 src = ft_face->glyph->bitmap.buffer;
5569 src_pitch = ft_face->glyph->bitmap.pitch;
5571 height = min( height, ft_face->glyph->bitmap.rows );
5572 while ( height-- )
5574 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5576 if ( src[x / 8] & masks[x % 8] )
5577 ((unsigned int *)dst)[x] = ~0u;
5579 src += src_pitch;
5580 dst += pitch;
5583 break;
5586 case FT_GLYPH_FORMAT_OUTLINE:
5588 unsigned int *dst;
5589 BYTE *src;
5590 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5591 INT x_shift, y_shift;
5592 BOOL rgb;
5593 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5594 FT_Render_Mode render_mode =
5595 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5596 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5598 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5600 if ( render_mode == FT_RENDER_MODE_LCD)
5602 lpgm->gmBlackBoxX += 2;
5603 lpgm->gmptGlyphOrigin.x -= 1;
5605 else
5607 lpgm->gmBlackBoxY += 2;
5608 lpgm->gmptGlyphOrigin.y += 1;
5612 width = lpgm->gmBlackBoxX;
5613 height = lpgm->gmBlackBoxY;
5614 pitch = width * 4;
5615 needed = pitch * height;
5617 if (!buf || !buflen) break;
5619 memset(buf, 0, buflen);
5620 dst = buf;
5621 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5623 if ( needsTransform )
5624 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5626 if ( pFT_Library_SetLcdFilter )
5627 pFT_Library_SetLcdFilter( library, lcdfilter );
5628 pFT_Render_Glyph (ft_face->glyph, render_mode);
5630 src = ft_face->glyph->bitmap.buffer;
5631 src_pitch = ft_face->glyph->bitmap.pitch;
5632 src_width = ft_face->glyph->bitmap.width;
5633 src_height = ft_face->glyph->bitmap.rows;
5635 if ( render_mode == FT_RENDER_MODE_LCD)
5637 rgb_interval = 1;
5638 hmul = 3;
5639 vmul = 1;
5641 else
5643 rgb_interval = src_pitch;
5644 hmul = 1;
5645 vmul = 3;
5648 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5649 if ( x_shift < 0 ) x_shift = 0;
5650 if ( x_shift + (src_width / hmul) > width )
5651 x_shift = width - (src_width / hmul);
5653 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5654 if ( y_shift < 0 ) y_shift = 0;
5655 if ( y_shift + (src_height / vmul) > height )
5656 y_shift = height - (src_height / vmul);
5658 dst += x_shift + y_shift * ( pitch / 4 );
5659 while ( src_height )
5661 for ( x = 0; x < src_width / hmul; x++ )
5663 if ( rgb )
5665 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5666 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5667 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5668 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5670 else
5672 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5673 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5674 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5675 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5678 src += src_pitch * vmul;
5679 dst += pitch / 4;
5680 src_height -= vmul;
5683 break;
5686 default:
5687 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5688 return GDI_ERROR;
5691 break;
5693 #else
5694 return GDI_ERROR;
5695 #endif
5697 case GGO_NATIVE:
5699 int contour, point = 0, first_pt;
5700 FT_Outline *outline = &ft_face->glyph->outline;
5701 TTPOLYGONHEADER *pph;
5702 TTPOLYCURVE *ppc;
5703 DWORD pph_start, cpfx, type;
5705 if(buflen == 0) buf = NULL;
5707 if (needsTransform && buf) {
5708 pFT_Outline_Transform(outline, &transMat);
5711 for(contour = 0; contour < outline->n_contours; contour++) {
5712 pph_start = needed;
5713 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5714 first_pt = point;
5715 if(buf) {
5716 pph->dwType = TT_POLYGON_TYPE;
5717 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5719 needed += sizeof(*pph);
5720 point++;
5721 while(point <= outline->contours[contour]) {
5722 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5723 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5724 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5725 cpfx = 0;
5726 do {
5727 if(buf)
5728 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5729 cpfx++;
5730 point++;
5731 } while(point <= outline->contours[contour] &&
5732 (outline->tags[point] & FT_Curve_Tag_On) ==
5733 (outline->tags[point-1] & FT_Curve_Tag_On));
5734 /* At the end of a contour Windows adds the start point, but
5735 only for Beziers */
5736 if(point > outline->contours[contour] &&
5737 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5738 if(buf)
5739 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5740 cpfx++;
5741 } else if(point <= outline->contours[contour] &&
5742 outline->tags[point] & FT_Curve_Tag_On) {
5743 /* add closing pt for bezier */
5744 if(buf)
5745 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5746 cpfx++;
5747 point++;
5749 if(buf) {
5750 ppc->wType = type;
5751 ppc->cpfx = cpfx;
5753 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5755 if(buf)
5756 pph->cb = needed - pph_start;
5758 break;
5760 case GGO_BEZIER:
5762 /* Convert the quadratic Beziers to cubic Beziers.
5763 The parametric eqn for a cubic Bezier is, from PLRM:
5764 r(t) = at^3 + bt^2 + ct + r0
5765 with the control points:
5766 r1 = r0 + c/3
5767 r2 = r1 + (c + b)/3
5768 r3 = r0 + c + b + a
5770 A quadratic Bezier has the form:
5771 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5773 So equating powers of t leads to:
5774 r1 = 2/3 p1 + 1/3 p0
5775 r2 = 2/3 p1 + 1/3 p2
5776 and of course r0 = p0, r3 = p2
5779 int contour, point = 0, first_pt;
5780 FT_Outline *outline = &ft_face->glyph->outline;
5781 TTPOLYGONHEADER *pph;
5782 TTPOLYCURVE *ppc;
5783 DWORD pph_start, cpfx, type;
5784 FT_Vector cubic_control[4];
5785 if(buflen == 0) buf = NULL;
5787 if (needsTransform && buf) {
5788 pFT_Outline_Transform(outline, &transMat);
5791 for(contour = 0; contour < outline->n_contours; contour++) {
5792 pph_start = needed;
5793 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5794 first_pt = point;
5795 if(buf) {
5796 pph->dwType = TT_POLYGON_TYPE;
5797 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5799 needed += sizeof(*pph);
5800 point++;
5801 while(point <= outline->contours[contour]) {
5802 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5803 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5804 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5805 cpfx = 0;
5806 do {
5807 if(type == TT_PRIM_LINE) {
5808 if(buf)
5809 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5810 cpfx++;
5811 point++;
5812 } else {
5813 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5814 so cpfx = 3n */
5816 /* FIXME: Possible optimization in endpoint calculation
5817 if there are two consecutive curves */
5818 cubic_control[0] = outline->points[point-1];
5819 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5820 cubic_control[0].x += outline->points[point].x + 1;
5821 cubic_control[0].y += outline->points[point].y + 1;
5822 cubic_control[0].x >>= 1;
5823 cubic_control[0].y >>= 1;
5825 if(point+1 > outline->contours[contour])
5826 cubic_control[3] = outline->points[first_pt];
5827 else {
5828 cubic_control[3] = outline->points[point+1];
5829 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5830 cubic_control[3].x += outline->points[point].x + 1;
5831 cubic_control[3].y += outline->points[point].y + 1;
5832 cubic_control[3].x >>= 1;
5833 cubic_control[3].y >>= 1;
5836 /* r1 = 1/3 p0 + 2/3 p1
5837 r2 = 1/3 p2 + 2/3 p1 */
5838 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5839 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5840 cubic_control[2] = cubic_control[1];
5841 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5842 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5843 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5844 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5845 if(buf) {
5846 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5847 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5848 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5850 cpfx += 3;
5851 point++;
5853 } while(point <= outline->contours[contour] &&
5854 (outline->tags[point] & FT_Curve_Tag_On) ==
5855 (outline->tags[point-1] & FT_Curve_Tag_On));
5856 /* At the end of a contour Windows adds the start point,
5857 but only for Beziers and we've already done that.
5859 if(point <= outline->contours[contour] &&
5860 outline->tags[point] & FT_Curve_Tag_On) {
5861 /* This is the closing pt of a bezier, but we've already
5862 added it, so just inc point and carry on */
5863 point++;
5865 if(buf) {
5866 ppc->wType = type;
5867 ppc->cpfx = cpfx;
5869 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5871 if(buf)
5872 pph->cb = needed - pph_start;
5874 break;
5877 default:
5878 FIXME("Unsupported format %d\n", format);
5879 return GDI_ERROR;
5881 return needed;
5884 static BOOL get_bitmap_text_metrics(GdiFont *font)
5886 FT_Face ft_face = font->ft_face;
5887 FT_WinFNT_HeaderRec winfnt_header;
5888 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5889 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5890 font->potm->otmSize = size;
5892 #define TM font->potm->otmTextMetrics
5893 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5895 TM.tmHeight = winfnt_header.pixel_height;
5896 TM.tmAscent = winfnt_header.ascent;
5897 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5898 TM.tmInternalLeading = winfnt_header.internal_leading;
5899 TM.tmExternalLeading = winfnt_header.external_leading;
5900 TM.tmAveCharWidth = winfnt_header.avg_width;
5901 TM.tmMaxCharWidth = winfnt_header.max_width;
5902 TM.tmWeight = winfnt_header.weight;
5903 TM.tmOverhang = 0;
5904 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5905 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5906 TM.tmFirstChar = winfnt_header.first_char;
5907 TM.tmLastChar = winfnt_header.last_char;
5908 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5909 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5910 TM.tmItalic = winfnt_header.italic;
5911 TM.tmUnderlined = font->underline;
5912 TM.tmStruckOut = font->strikeout;
5913 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5914 TM.tmCharSet = winfnt_header.charset;
5916 else
5918 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5919 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5920 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5921 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5922 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5923 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5924 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5925 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5926 TM.tmOverhang = 0;
5927 TM.tmDigitizedAspectX = 96; /* FIXME */
5928 TM.tmDigitizedAspectY = 96; /* FIXME */
5929 TM.tmFirstChar = 1;
5930 TM.tmLastChar = 255;
5931 TM.tmDefaultChar = 32;
5932 TM.tmBreakChar = 32;
5933 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5934 TM.tmUnderlined = font->underline;
5935 TM.tmStruckOut = font->strikeout;
5936 /* NB inverted meaning of TMPF_FIXED_PITCH */
5937 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5938 TM.tmCharSet = font->charset;
5940 #undef TM
5942 return TRUE;
5946 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5948 double scale_x, scale_y;
5950 if (font->aveWidth)
5952 scale_x = (double)font->aveWidth;
5953 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5955 else
5956 scale_x = font->scale_y;
5958 scale_x *= fabs(font->font_desc.matrix.eM11);
5959 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5961 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5962 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5964 SCALE_Y(ptm->tmHeight);
5965 SCALE_Y(ptm->tmAscent);
5966 SCALE_Y(ptm->tmDescent);
5967 SCALE_Y(ptm->tmInternalLeading);
5968 SCALE_Y(ptm->tmExternalLeading);
5969 SCALE_Y(ptm->tmOverhang);
5971 SCALE_X(ptm->tmAveCharWidth);
5972 SCALE_X(ptm->tmMaxCharWidth);
5974 #undef SCALE_X
5975 #undef SCALE_Y
5978 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5980 double scale_x, scale_y;
5982 if (font->aveWidth)
5984 scale_x = (double)font->aveWidth;
5985 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5987 else
5988 scale_x = font->scale_y;
5990 scale_x *= fabs(font->font_desc.matrix.eM11);
5991 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5993 scale_font_metrics(font, &potm->otmTextMetrics);
5995 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5996 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5998 SCALE_Y(potm->otmAscent);
5999 SCALE_Y(potm->otmDescent);
6000 SCALE_Y(potm->otmLineGap);
6001 SCALE_Y(potm->otmsCapEmHeight);
6002 SCALE_Y(potm->otmsXHeight);
6003 SCALE_Y(potm->otmrcFontBox.top);
6004 SCALE_Y(potm->otmrcFontBox.bottom);
6005 SCALE_X(potm->otmrcFontBox.left);
6006 SCALE_X(potm->otmrcFontBox.right);
6007 SCALE_Y(potm->otmMacAscent);
6008 SCALE_Y(potm->otmMacDescent);
6009 SCALE_Y(potm->otmMacLineGap);
6010 SCALE_X(potm->otmptSubscriptSize.x);
6011 SCALE_Y(potm->otmptSubscriptSize.y);
6012 SCALE_X(potm->otmptSubscriptOffset.x);
6013 SCALE_Y(potm->otmptSubscriptOffset.y);
6014 SCALE_X(potm->otmptSuperscriptSize.x);
6015 SCALE_Y(potm->otmptSuperscriptSize.y);
6016 SCALE_X(potm->otmptSuperscriptOffset.x);
6017 SCALE_Y(potm->otmptSuperscriptOffset.y);
6018 SCALE_Y(potm->otmsStrikeoutSize);
6019 SCALE_Y(potm->otmsStrikeoutPosition);
6020 SCALE_Y(potm->otmsUnderscoreSize);
6021 SCALE_Y(potm->otmsUnderscorePosition);
6023 #undef SCALE_X
6024 #undef SCALE_Y
6027 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6029 if(!font->potm)
6031 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6033 /* Make sure that the font has sane width/height ratio */
6034 if (font->aveWidth)
6036 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6038 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6039 font->aveWidth = 0;
6043 *ptm = font->potm->otmTextMetrics;
6044 scale_font_metrics(font, ptm);
6045 return TRUE;
6048 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6050 int i;
6052 for(i = 0; i < ft_face->num_charmaps; i++)
6054 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6055 return TRUE;
6057 return FALSE;
6060 static BOOL get_outline_text_metrics(GdiFont *font)
6062 BOOL ret = FALSE;
6063 FT_Face ft_face = font->ft_face;
6064 UINT needed, lenfam, lensty;
6065 TT_OS2 *pOS2;
6066 TT_HoriHeader *pHori;
6067 TT_Postscript *pPost;
6068 FT_Fixed x_scale, y_scale;
6069 WCHAR *family_nameW, *style_nameW;
6070 static const WCHAR spaceW[] = {' ', '\0'};
6071 char *cp;
6072 INT ascent, descent;
6074 TRACE("font=%p\n", font);
6076 if(!FT_IS_SCALABLE(ft_face))
6077 return FALSE;
6079 needed = sizeof(*font->potm);
6081 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6082 family_nameW = strdupW(font->name);
6084 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6085 * sizeof(WCHAR);
6086 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6087 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6088 style_nameW, lensty/sizeof(WCHAR));
6090 /* These names should be read from the TT name table */
6092 /* length of otmpFamilyName */
6093 needed += lenfam;
6095 /* length of otmpFaceName */
6096 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6097 needed += lenfam; /* just the family name */
6098 } else {
6099 needed += lenfam + lensty; /* family + " " + style */
6102 /* length of otmpStyleName */
6103 needed += lensty;
6105 /* length of otmpFullName */
6106 needed += lenfam + lensty;
6109 x_scale = ft_face->size->metrics.x_scale;
6110 y_scale = ft_face->size->metrics.y_scale;
6112 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6113 if(!pOS2) {
6114 FIXME("Can't find OS/2 table - not TT font?\n");
6115 goto end;
6118 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6119 if(!pHori) {
6120 FIXME("Can't find HHEA table - not TT font?\n");
6121 goto end;
6124 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6126 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",
6127 pOS2->usWinAscent, pOS2->usWinDescent,
6128 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6129 ft_face->ascender, ft_face->descender, ft_face->height,
6130 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6131 ft_face->bbox.yMax, ft_face->bbox.yMin);
6133 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6134 font->potm->otmSize = needed;
6136 #define TM font->potm->otmTextMetrics
6138 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6139 ascent = pHori->Ascender;
6140 descent = -pHori->Descender;
6141 } else {
6142 ascent = pOS2->usWinAscent;
6143 descent = pOS2->usWinDescent;
6146 if(font->yMax) {
6147 TM.tmAscent = font->yMax;
6148 TM.tmDescent = -font->yMin;
6149 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6150 } else {
6151 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6152 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6153 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6154 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6157 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6159 /* MSDN says:
6160 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6162 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6163 ((ascent + descent) -
6164 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6166 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6167 if (TM.tmAveCharWidth == 0) {
6168 TM.tmAveCharWidth = 1;
6170 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6171 TM.tmWeight = FW_REGULAR;
6172 if (font->fake_bold)
6173 TM.tmWeight = FW_BOLD;
6174 else
6176 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6178 if (pOS2->usWeightClass > FW_MEDIUM)
6179 TM.tmWeight = pOS2->usWeightClass;
6181 else if (pOS2->usWeightClass <= FW_MEDIUM)
6182 TM.tmWeight = pOS2->usWeightClass;
6184 TM.tmOverhang = 0;
6185 TM.tmDigitizedAspectX = 300;
6186 TM.tmDigitizedAspectY = 300;
6187 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6188 * symbol range to 0 - f0ff
6191 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6193 TM.tmFirstChar = 0;
6194 switch(GetACP())
6196 case 1257: /* Baltic */
6197 TM.tmLastChar = 0xf8fd;
6198 break;
6199 default:
6200 TM.tmLastChar = 0xf0ff;
6202 TM.tmBreakChar = 0x20;
6203 TM.tmDefaultChar = 0x1f;
6205 else
6207 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6208 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6210 if(pOS2->usFirstCharIndex <= 1)
6211 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6212 else if (pOS2->usFirstCharIndex > 0xff)
6213 TM.tmBreakChar = 0x20;
6214 else
6215 TM.tmBreakChar = pOS2->usFirstCharIndex;
6216 TM.tmDefaultChar = TM.tmBreakChar - 1;
6218 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6219 TM.tmUnderlined = font->underline;
6220 TM.tmStruckOut = font->strikeout;
6222 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6223 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6224 (pOS2->version == 0xFFFFU ||
6225 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6226 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6227 else
6228 TM.tmPitchAndFamily = 0;
6230 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6232 case PAN_FAMILY_SCRIPT:
6233 TM.tmPitchAndFamily |= FF_SCRIPT;
6234 break;
6236 case PAN_FAMILY_DECORATIVE:
6237 TM.tmPitchAndFamily |= FF_DECORATIVE;
6238 break;
6240 case PAN_ANY:
6241 case PAN_NO_FIT:
6242 case PAN_FAMILY_TEXT_DISPLAY:
6243 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6244 /* which is clearly not what the panose spec says. */
6245 default:
6246 if(TM.tmPitchAndFamily == 0 || /* fixed */
6247 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6248 TM.tmPitchAndFamily = FF_MODERN;
6249 else
6251 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6253 case PAN_ANY:
6254 case PAN_NO_FIT:
6255 default:
6256 TM.tmPitchAndFamily |= FF_DONTCARE;
6257 break;
6259 case PAN_SERIF_COVE:
6260 case PAN_SERIF_OBTUSE_COVE:
6261 case PAN_SERIF_SQUARE_COVE:
6262 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6263 case PAN_SERIF_SQUARE:
6264 case PAN_SERIF_THIN:
6265 case PAN_SERIF_BONE:
6266 case PAN_SERIF_EXAGGERATED:
6267 case PAN_SERIF_TRIANGLE:
6268 TM.tmPitchAndFamily |= FF_ROMAN;
6269 break;
6271 case PAN_SERIF_NORMAL_SANS:
6272 case PAN_SERIF_OBTUSE_SANS:
6273 case PAN_SERIF_PERP_SANS:
6274 case PAN_SERIF_FLARED:
6275 case PAN_SERIF_ROUNDED:
6276 TM.tmPitchAndFamily |= FF_SWISS;
6277 break;
6280 break;
6283 if(FT_IS_SCALABLE(ft_face))
6284 TM.tmPitchAndFamily |= TMPF_VECTOR;
6286 if(FT_IS_SFNT(ft_face))
6288 if (font->ntmFlags & NTM_PS_OPENTYPE)
6289 TM.tmPitchAndFamily |= TMPF_DEVICE;
6290 else
6291 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6294 TM.tmCharSet = font->charset;
6296 font->potm->otmFiller = 0;
6297 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6298 font->potm->otmfsSelection = pOS2->fsSelection;
6299 font->potm->otmfsType = pOS2->fsType;
6300 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6301 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6302 font->potm->otmItalicAngle = 0; /* POST table */
6303 font->potm->otmEMSquare = ft_face->units_per_EM;
6304 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6305 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6306 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6307 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6308 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6309 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6310 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6311 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6312 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6313 font->potm->otmMacAscent = TM.tmAscent;
6314 font->potm->otmMacDescent = -TM.tmDescent;
6315 font->potm->otmMacLineGap = font->potm->otmLineGap;
6316 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6317 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6318 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6319 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6320 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6321 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6322 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6323 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6324 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6325 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6326 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6327 if(!pPost) {
6328 font->potm->otmsUnderscoreSize = 0;
6329 font->potm->otmsUnderscorePosition = 0;
6330 } else {
6331 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6332 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6334 #undef TM
6336 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6337 cp = (char*)font->potm + sizeof(*font->potm);
6338 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6339 strcpyW((WCHAR*)cp, family_nameW);
6340 cp += lenfam;
6341 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6342 strcpyW((WCHAR*)cp, style_nameW);
6343 cp += lensty;
6344 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6345 strcpyW((WCHAR*)cp, family_nameW);
6346 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6347 strcatW((WCHAR*)cp, spaceW);
6348 strcatW((WCHAR*)cp, style_nameW);
6349 cp += lenfam + lensty;
6350 } else
6351 cp += lenfam;
6352 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6353 strcpyW((WCHAR*)cp, family_nameW);
6354 strcatW((WCHAR*)cp, spaceW);
6355 strcatW((WCHAR*)cp, style_nameW);
6356 ret = TRUE;
6358 end:
6359 HeapFree(GetProcessHeap(), 0, style_nameW);
6360 HeapFree(GetProcessHeap(), 0, family_nameW);
6361 return ret;
6364 /*************************************************************
6365 * freetype_GetGlyphOutline
6367 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6368 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6370 struct freetype_physdev *physdev = get_freetype_dev( dev );
6371 DWORD ret;
6373 if (!physdev->font)
6375 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6376 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6379 GDI_CheckNotLock();
6380 EnterCriticalSection( &freetype_cs );
6381 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6382 LeaveCriticalSection( &freetype_cs );
6383 return ret;
6386 /*************************************************************
6387 * freetype_GetTextMetrics
6389 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6391 struct freetype_physdev *physdev = get_freetype_dev( dev );
6392 BOOL ret;
6394 if (!physdev->font)
6396 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6397 return dev->funcs->pGetTextMetrics( dev, metrics );
6400 GDI_CheckNotLock();
6401 EnterCriticalSection( &freetype_cs );
6402 ret = get_text_metrics( physdev->font, metrics );
6403 LeaveCriticalSection( &freetype_cs );
6404 return ret;
6407 /*************************************************************
6408 * freetype_GetOutlineTextMetrics
6410 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6412 struct freetype_physdev *physdev = get_freetype_dev( dev );
6413 UINT ret = 0;
6415 if (!physdev->font)
6417 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6418 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6421 TRACE("font=%p\n", physdev->font);
6423 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6425 GDI_CheckNotLock();
6426 EnterCriticalSection( &freetype_cs );
6428 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6430 if(cbSize >= physdev->font->potm->otmSize)
6432 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6433 scale_outline_font_metrics(physdev->font, potm);
6435 ret = physdev->font->potm->otmSize;
6437 LeaveCriticalSection( &freetype_cs );
6438 return ret;
6441 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6443 HFONTLIST *hfontlist;
6444 child->font = alloc_font();
6445 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6446 if(!child->font->ft_face)
6448 free_font(child->font);
6449 child->font = NULL;
6450 return FALSE;
6453 child->font->font_desc = font->font_desc;
6454 child->font->ntmFlags = child->face->ntmFlags;
6455 child->font->orientation = font->orientation;
6456 child->font->scale_y = font->scale_y;
6457 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6458 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6459 child->font->name = strdupW(child->face->family->FamilyName);
6460 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6461 child->font->base_font = font;
6462 list_add_head(&child_font_list, &child->font->entry);
6463 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6464 return TRUE;
6467 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6469 FT_UInt g;
6470 CHILD_FONT *child_font;
6472 if(font->base_font)
6473 font = font->base_font;
6475 *linked_font = font;
6477 if((*glyph = get_glyph_index(font, c)))
6479 *glyph = get_GSUB_vert_glyph(font, *glyph);
6480 return TRUE;
6483 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6485 if(!child_font->font)
6486 if(!load_child_font(font, child_font))
6487 continue;
6489 if(!child_font->font->ft_face)
6490 continue;
6491 g = get_glyph_index(child_font->font, c);
6492 g = get_GSUB_vert_glyph(child_font->font, g);
6493 if(g)
6495 *glyph = g;
6496 *linked_font = child_font->font;
6497 return TRUE;
6500 return FALSE;
6503 /*************************************************************
6504 * freetype_GetCharWidth
6506 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6508 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6509 UINT c;
6510 GLYPHMETRICS gm;
6511 FT_UInt glyph_index;
6512 GdiFont *linked_font;
6513 struct freetype_physdev *physdev = get_freetype_dev( dev );
6515 if (!physdev->font)
6517 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6518 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6521 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6523 GDI_CheckNotLock();
6524 EnterCriticalSection( &freetype_cs );
6525 for(c = firstChar; c <= lastChar; c++) {
6526 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6527 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6528 &gm, 0, NULL, &identity);
6529 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6531 LeaveCriticalSection( &freetype_cs );
6532 return TRUE;
6535 /*************************************************************
6536 * freetype_GetCharABCWidths
6538 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6540 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6541 UINT c;
6542 GLYPHMETRICS gm;
6543 FT_UInt glyph_index;
6544 GdiFont *linked_font;
6545 struct freetype_physdev *physdev = get_freetype_dev( dev );
6547 if (!physdev->font)
6549 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6550 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6553 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6555 GDI_CheckNotLock();
6556 EnterCriticalSection( &freetype_cs );
6558 for(c = firstChar; c <= lastChar; c++) {
6559 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6560 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6561 &gm, 0, NULL, &identity);
6562 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6563 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6564 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6565 FONT_GM(linked_font,glyph_index)->bbx;
6567 LeaveCriticalSection( &freetype_cs );
6568 return TRUE;
6571 /*************************************************************
6572 * freetype_GetCharABCWidthsI
6574 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6576 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6577 UINT c;
6578 GLYPHMETRICS gm;
6579 FT_UInt glyph_index;
6580 GdiFont *linked_font;
6581 struct freetype_physdev *physdev = get_freetype_dev( dev );
6583 if (!physdev->font)
6585 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6586 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6589 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6590 return FALSE;
6592 GDI_CheckNotLock();
6593 EnterCriticalSection( &freetype_cs );
6595 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6596 if (!pgi)
6597 for(c = firstChar; c < firstChar+count; c++) {
6598 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6599 &gm, 0, NULL, &identity);
6600 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6601 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6602 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6603 - FONT_GM(linked_font,c)->bbx;
6605 else
6606 for(c = 0; c < count; c++) {
6607 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6608 &gm, 0, NULL, &identity);
6609 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6610 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6611 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6612 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6615 LeaveCriticalSection( &freetype_cs );
6616 return TRUE;
6619 /*************************************************************
6620 * freetype_GetTextExtentExPoint
6622 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6623 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6625 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6626 INT idx;
6627 INT nfit = 0, ext;
6628 GLYPHMETRICS gm;
6629 TEXTMETRICW tm;
6630 FT_UInt glyph_index;
6631 GdiFont *linked_font;
6632 struct freetype_physdev *physdev = get_freetype_dev( dev );
6634 if (!physdev->font)
6636 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6637 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6640 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6642 GDI_CheckNotLock();
6643 EnterCriticalSection( &freetype_cs );
6645 size->cx = 0;
6646 get_text_metrics( physdev->font, &tm );
6647 size->cy = tm.tmHeight;
6649 for(idx = 0; idx < count; idx++) {
6650 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6651 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6652 &gm, 0, NULL, &identity);
6653 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6654 ext = size->cx;
6655 if (! pnfit || ext <= max_ext) {
6656 ++nfit;
6657 if (dxs)
6658 dxs[idx] = ext;
6662 if (pnfit)
6663 *pnfit = nfit;
6665 LeaveCriticalSection( &freetype_cs );
6666 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6667 return TRUE;
6670 /*************************************************************
6671 * freetype_GetTextExtentExPointI
6673 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6674 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6676 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6677 INT idx;
6678 INT nfit = 0, ext;
6679 GLYPHMETRICS gm;
6680 TEXTMETRICW tm;
6681 struct freetype_physdev *physdev = get_freetype_dev( dev );
6683 if (!physdev->font)
6685 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6686 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6689 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6691 GDI_CheckNotLock();
6692 EnterCriticalSection( &freetype_cs );
6694 size->cx = 0;
6695 get_text_metrics(physdev->font, &tm);
6696 size->cy = tm.tmHeight;
6698 for(idx = 0; idx < count; idx++) {
6699 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6700 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6701 ext = size->cx;
6702 if (! pnfit || ext <= max_ext) {
6703 ++nfit;
6704 if (dxs)
6705 dxs[idx] = ext;
6709 if (pnfit)
6710 *pnfit = nfit;
6712 LeaveCriticalSection( &freetype_cs );
6713 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6714 return TRUE;
6717 /*************************************************************
6718 * freetype_GetFontData
6720 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6722 struct freetype_physdev *physdev = get_freetype_dev( dev );
6724 if (!physdev->font)
6726 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6727 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6730 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6731 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6732 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6734 return get_font_data( physdev->font, table, offset, buf, cbData );
6737 /*************************************************************
6738 * freetype_GetTextFace
6740 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6742 INT n;
6743 struct freetype_physdev *physdev = get_freetype_dev( dev );
6745 if (!physdev->font)
6747 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6748 return dev->funcs->pGetTextFace( dev, count, str );
6751 n = strlenW(physdev->font->name) + 1;
6752 if (str)
6754 lstrcpynW(str, physdev->font->name, count);
6755 n = min(count, n);
6757 return n;
6760 /*************************************************************
6761 * freetype_GetTextCharsetInfo
6763 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6765 struct freetype_physdev *physdev = get_freetype_dev( dev );
6767 if (!physdev->font)
6769 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6770 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6772 if (fs) *fs = physdev->font->fs;
6773 return physdev->font->charset;
6776 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6778 GdiFont *font = dc->gdiFont, *linked_font;
6779 struct list *first_hfont;
6780 BOOL ret;
6782 GDI_CheckNotLock();
6783 EnterCriticalSection( &freetype_cs );
6784 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6785 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6786 if(font == linked_font)
6787 *new_hfont = dc->hFont;
6788 else
6790 first_hfont = list_head(&linked_font->hfontlist);
6791 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6793 LeaveCriticalSection( &freetype_cs );
6794 return ret;
6797 /* Retrieve a list of supported Unicode ranges for a given font.
6798 * Can be called with NULL gs to calculate the buffer size. Returns
6799 * the number of ranges found.
6801 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6803 DWORD num_ranges = 0;
6805 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6807 FT_UInt glyph_code;
6808 FT_ULong char_code, char_code_prev;
6810 glyph_code = 0;
6811 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6813 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6814 face->num_glyphs, glyph_code, char_code);
6816 if (!glyph_code) return 0;
6818 if (gs)
6820 gs->ranges[0].wcLow = (USHORT)char_code;
6821 gs->ranges[0].cGlyphs = 0;
6822 gs->cGlyphsSupported = 0;
6825 num_ranges = 1;
6826 while (glyph_code)
6828 if (char_code < char_code_prev)
6830 ERR("expected increasing char code from FT_Get_Next_Char\n");
6831 return 0;
6833 if (char_code - char_code_prev > 1)
6835 num_ranges++;
6836 if (gs)
6838 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6839 gs->ranges[num_ranges - 1].cGlyphs = 1;
6840 gs->cGlyphsSupported++;
6843 else if (gs)
6845 gs->ranges[num_ranges - 1].cGlyphs++;
6846 gs->cGlyphsSupported++;
6848 char_code_prev = char_code;
6849 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6852 else
6853 FIXME("encoding %u not supported\n", face->charmap->encoding);
6855 return num_ranges;
6858 /*************************************************************
6859 * freetype_GetFontUnicodeRanges
6861 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6863 struct freetype_physdev *physdev = get_freetype_dev( dev );
6864 DWORD size, num_ranges;
6866 if (!physdev->font)
6868 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6869 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6872 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6873 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6874 if (glyphset)
6876 glyphset->cbThis = size;
6877 glyphset->cRanges = num_ranges;
6878 glyphset->flAccel = 0;
6880 return size;
6883 /*************************************************************
6884 * freetype_FontIsLinked
6886 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6888 struct freetype_physdev *physdev = get_freetype_dev( dev );
6889 BOOL ret;
6891 if (!physdev->font)
6893 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6894 return dev->funcs->pFontIsLinked( dev );
6897 GDI_CheckNotLock();
6898 EnterCriticalSection( &freetype_cs );
6899 ret = !list_empty(&physdev->font->child_fonts);
6900 LeaveCriticalSection( &freetype_cs );
6901 return ret;
6904 static BOOL is_hinting_enabled(void)
6906 /* Use the >= 2.2.0 function if available */
6907 if(pFT_Get_TrueType_Engine_Type)
6909 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6910 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6912 #ifdef FT_DRIVER_HAS_HINTER
6913 else
6915 FT_Module mod;
6917 /* otherwise if we've been compiled with < 2.2.0 headers
6918 use the internal macro */
6919 mod = pFT_Get_Module(library, "truetype");
6920 if(mod && FT_DRIVER_HAS_HINTER(mod))
6921 return TRUE;
6923 #endif
6925 return FALSE;
6928 static BOOL is_subpixel_rendering_enabled( void )
6930 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6931 return pFT_Library_SetLcdFilter &&
6932 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6933 #else
6934 return FALSE;
6935 #endif
6938 /*************************************************************************
6939 * GetRasterizerCaps (GDI32.@)
6941 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6943 static int hinting = -1;
6944 static int subpixel = -1;
6946 if(hinting == -1)
6948 hinting = is_hinting_enabled();
6949 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6952 if ( subpixel == -1 )
6954 subpixel = is_subpixel_rendering_enabled();
6955 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6958 lprs->nSize = sizeof(RASTERIZER_STATUS);
6959 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6960 if ( subpixel )
6961 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6962 lprs->nLanguageID = 0;
6963 return TRUE;
6966 /*************************************************************
6967 * freetype_GdiRealizationInfo
6969 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6971 struct freetype_physdev *physdev = get_freetype_dev( dev );
6972 realization_info_t *info = ptr;
6974 if (!physdev->font)
6976 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6977 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6980 FIXME("(%p, %p): stub!\n", physdev->font, info);
6982 info->flags = 1;
6983 if(FT_IS_SCALABLE(physdev->font->ft_face))
6984 info->flags |= 2;
6986 info->cache_num = physdev->font->cache_num;
6987 info->unknown2 = -1;
6988 return TRUE;
6991 /*************************************************************************
6992 * Kerning support for TrueType fonts
6994 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6996 struct TT_kern_table
6998 USHORT version;
6999 USHORT nTables;
7002 struct TT_kern_subtable
7004 USHORT version;
7005 USHORT length;
7006 union
7008 USHORT word;
7009 struct
7011 USHORT horizontal : 1;
7012 USHORT minimum : 1;
7013 USHORT cross_stream: 1;
7014 USHORT override : 1;
7015 USHORT reserved1 : 4;
7016 USHORT format : 8;
7017 } bits;
7018 } coverage;
7021 struct TT_format0_kern_subtable
7023 USHORT nPairs;
7024 USHORT searchRange;
7025 USHORT entrySelector;
7026 USHORT rangeShift;
7029 struct TT_kern_pair
7031 USHORT left;
7032 USHORT right;
7033 short value;
7036 static DWORD parse_format0_kern_subtable(GdiFont *font,
7037 const struct TT_format0_kern_subtable *tt_f0_ks,
7038 const USHORT *glyph_to_char,
7039 KERNINGPAIR *kern_pair, DWORD cPairs)
7041 USHORT i, nPairs;
7042 const struct TT_kern_pair *tt_kern_pair;
7044 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7046 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7048 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7049 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7050 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7052 if (!kern_pair || !cPairs)
7053 return nPairs;
7055 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7057 nPairs = min(nPairs, cPairs);
7059 for (i = 0; i < nPairs; i++)
7061 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7062 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7063 /* this algorithm appears to better match what Windows does */
7064 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7065 if (kern_pair->iKernAmount < 0)
7067 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7068 kern_pair->iKernAmount -= font->ppem;
7070 else if (kern_pair->iKernAmount > 0)
7072 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7073 kern_pair->iKernAmount += font->ppem;
7075 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7077 TRACE("left %u right %u value %d\n",
7078 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7080 kern_pair++;
7082 TRACE("copied %u entries\n", nPairs);
7083 return nPairs;
7086 /*************************************************************
7087 * freetype_GetKerningPairs
7089 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7091 DWORD length;
7092 void *buf;
7093 const struct TT_kern_table *tt_kern_table;
7094 const struct TT_kern_subtable *tt_kern_subtable;
7095 USHORT i, nTables;
7096 USHORT *glyph_to_char;
7097 GdiFont *font;
7098 struct freetype_physdev *physdev = get_freetype_dev( dev );
7100 if (!(font = physdev->font))
7102 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7103 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7106 GDI_CheckNotLock();
7107 EnterCriticalSection( &freetype_cs );
7108 if (font->total_kern_pairs != (DWORD)-1)
7110 if (cPairs && kern_pair)
7112 cPairs = min(cPairs, font->total_kern_pairs);
7113 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7115 else cPairs = font->total_kern_pairs;
7117 LeaveCriticalSection( &freetype_cs );
7118 return cPairs;
7121 font->total_kern_pairs = 0;
7123 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7125 if (length == GDI_ERROR)
7127 TRACE("no kerning data in the font\n");
7128 LeaveCriticalSection( &freetype_cs );
7129 return 0;
7132 buf = HeapAlloc(GetProcessHeap(), 0, length);
7133 if (!buf)
7135 WARN("Out of memory\n");
7136 LeaveCriticalSection( &freetype_cs );
7137 return 0;
7140 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7142 /* build a glyph index to char code map */
7143 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7144 if (!glyph_to_char)
7146 WARN("Out of memory allocating a glyph index to char code map\n");
7147 HeapFree(GetProcessHeap(), 0, buf);
7148 LeaveCriticalSection( &freetype_cs );
7149 return 0;
7152 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7154 FT_UInt glyph_code;
7155 FT_ULong char_code;
7157 glyph_code = 0;
7158 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7160 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7161 font->ft_face->num_glyphs, glyph_code, char_code);
7163 while (glyph_code)
7165 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7167 /* FIXME: This doesn't match what Windows does: it does some fancy
7168 * things with duplicate glyph index to char code mappings, while
7169 * we just avoid overriding existing entries.
7171 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7172 glyph_to_char[glyph_code] = (USHORT)char_code;
7174 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7177 else
7179 ULONG n;
7181 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7182 for (n = 0; n <= 65535; n++)
7183 glyph_to_char[n] = (USHORT)n;
7186 tt_kern_table = buf;
7187 nTables = GET_BE_WORD(tt_kern_table->nTables);
7188 TRACE("version %u, nTables %u\n",
7189 GET_BE_WORD(tt_kern_table->version), nTables);
7191 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7193 for (i = 0; i < nTables; i++)
7195 struct TT_kern_subtable tt_kern_subtable_copy;
7197 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7198 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7199 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7201 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7202 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7203 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7205 /* According to the TrueType specification this is the only format
7206 * that will be properly interpreted by Windows and OS/2
7208 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7210 DWORD new_chunk, old_total = font->total_kern_pairs;
7212 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7213 glyph_to_char, NULL, 0);
7214 font->total_kern_pairs += new_chunk;
7216 if (!font->kern_pairs)
7217 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7218 font->total_kern_pairs * sizeof(*font->kern_pairs));
7219 else
7220 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7221 font->total_kern_pairs * sizeof(*font->kern_pairs));
7223 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7224 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7226 else
7227 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7229 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7232 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7233 HeapFree(GetProcessHeap(), 0, buf);
7235 if (cPairs && kern_pair)
7237 cPairs = min(cPairs, font->total_kern_pairs);
7238 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7240 else cPairs = font->total_kern_pairs;
7242 LeaveCriticalSection( &freetype_cs );
7243 return cPairs;
7246 static const struct gdi_dc_funcs freetype_funcs =
7248 NULL, /* pAbortDoc */
7249 NULL, /* pAbortPath */
7250 NULL, /* pAlphaBlend */
7251 NULL, /* pAngleArc */
7252 NULL, /* pArc */
7253 NULL, /* pArcTo */
7254 NULL, /* pBeginPath */
7255 NULL, /* pBlendImage */
7256 NULL, /* pChoosePixelFormat */
7257 NULL, /* pChord */
7258 NULL, /* pCloseFigure */
7259 NULL, /* pCopyBitmap */
7260 NULL, /* pCreateBitmap */
7261 NULL, /* pCreateCompatibleDC */
7262 freetype_CreateDC, /* pCreateDC */
7263 NULL, /* pDeleteBitmap */
7264 freetype_DeleteDC, /* pDeleteDC */
7265 NULL, /* pDeleteObject */
7266 NULL, /* pDescribePixelFormat */
7267 NULL, /* pDeviceCapabilities */
7268 NULL, /* pEllipse */
7269 NULL, /* pEndDoc */
7270 NULL, /* pEndPage */
7271 NULL, /* pEndPath */
7272 freetype_EnumFonts, /* pEnumFonts */
7273 NULL, /* pEnumICMProfiles */
7274 NULL, /* pExcludeClipRect */
7275 NULL, /* pExtDeviceMode */
7276 NULL, /* pExtEscape */
7277 NULL, /* pExtFloodFill */
7278 NULL, /* pExtSelectClipRgn */
7279 NULL, /* pExtTextOut */
7280 NULL, /* pFillPath */
7281 NULL, /* pFillRgn */
7282 NULL, /* pFlattenPath */
7283 freetype_FontIsLinked, /* pFontIsLinked */
7284 NULL, /* pFrameRgn */
7285 NULL, /* pGdiComment */
7286 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7287 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7288 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7289 freetype_GetCharWidth, /* pGetCharWidth */
7290 NULL, /* pGetDeviceCaps */
7291 NULL, /* pGetDeviceGammaRamp */
7292 freetype_GetFontData, /* pGetFontData */
7293 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7294 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7295 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7296 NULL, /* pGetICMProfile */
7297 NULL, /* pGetImage */
7298 freetype_GetKerningPairs, /* pGetKerningPairs */
7299 NULL, /* pGetNearestColor */
7300 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7301 NULL, /* pGetPixel */
7302 NULL, /* pGetPixelFormat */
7303 NULL, /* pGetSystemPaletteEntries */
7304 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7305 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7306 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7307 freetype_GetTextFace, /* pGetTextFace */
7308 freetype_GetTextMetrics, /* pGetTextMetrics */
7309 NULL, /* pGradientFill */
7310 NULL, /* pIntersectClipRect */
7311 NULL, /* pInvertRgn */
7312 NULL, /* pLineTo */
7313 NULL, /* pModifyWorldTransform */
7314 NULL, /* pMoveTo */
7315 NULL, /* pOffsetClipRgn */
7316 NULL, /* pOffsetViewportOrg */
7317 NULL, /* pOffsetWindowOrg */
7318 NULL, /* pPaintRgn */
7319 NULL, /* pPatBlt */
7320 NULL, /* pPie */
7321 NULL, /* pPolyBezier */
7322 NULL, /* pPolyBezierTo */
7323 NULL, /* pPolyDraw */
7324 NULL, /* pPolyPolygon */
7325 NULL, /* pPolyPolyline */
7326 NULL, /* pPolygon */
7327 NULL, /* pPolyline */
7328 NULL, /* pPolylineTo */
7329 NULL, /* pPutImage */
7330 NULL, /* pRealizeDefaultPalette */
7331 NULL, /* pRealizePalette */
7332 NULL, /* pRectangle */
7333 NULL, /* pResetDC */
7334 NULL, /* pRestoreDC */
7335 NULL, /* pRoundRect */
7336 NULL, /* pSaveDC */
7337 NULL, /* pScaleViewportExt */
7338 NULL, /* pScaleWindowExt */
7339 NULL, /* pSelectBitmap */
7340 NULL, /* pSelectBrush */
7341 NULL, /* pSelectClipPath */
7342 freetype_SelectFont, /* pSelectFont */
7343 NULL, /* pSelectPalette */
7344 NULL, /* pSelectPen */
7345 NULL, /* pSetArcDirection */
7346 NULL, /* pSetBkColor */
7347 NULL, /* pSetBkMode */
7348 NULL, /* pSetDCBrushColor */
7349 NULL, /* pSetDCPenColor */
7350 NULL, /* pSetDIBColorTable */
7351 NULL, /* pSetDIBitsToDevice */
7352 NULL, /* pSetDeviceClipping */
7353 NULL, /* pSetDeviceGammaRamp */
7354 NULL, /* pSetLayout */
7355 NULL, /* pSetMapMode */
7356 NULL, /* pSetMapperFlags */
7357 NULL, /* pSetPixel */
7358 NULL, /* pSetPixelFormat */
7359 NULL, /* pSetPolyFillMode */
7360 NULL, /* pSetROP2 */
7361 NULL, /* pSetRelAbs */
7362 NULL, /* pSetStretchBltMode */
7363 NULL, /* pSetTextAlign */
7364 NULL, /* pSetTextCharacterExtra */
7365 NULL, /* pSetTextColor */
7366 NULL, /* pSetTextJustification */
7367 NULL, /* pSetViewportExt */
7368 NULL, /* pSetViewportOrg */
7369 NULL, /* pSetWindowExt */
7370 NULL, /* pSetWindowOrg */
7371 NULL, /* pSetWorldTransform */
7372 NULL, /* pStartDoc */
7373 NULL, /* pStartPage */
7374 NULL, /* pStretchBlt */
7375 NULL, /* pStretchDIBits */
7376 NULL, /* pStrokeAndFillPath */
7377 NULL, /* pStrokePath */
7378 NULL, /* pSwapBuffers */
7379 NULL, /* pUnrealizePalette */
7380 NULL, /* pWidenPath */
7381 /* OpenGL not supported */
7384 #else /* HAVE_FREETYPE */
7386 /*************************************************************************/
7388 BOOL WineEngInit(void)
7390 return FALSE;
7392 BOOL WineEngDestroyFontInstance(HFONT hfont)
7394 return FALSE;
7397 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7399 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7400 return 1;
7403 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7405 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7406 return TRUE;
7409 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7411 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7412 return NULL;
7415 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7417 return FALSE;
7420 /*************************************************************************
7421 * GetRasterizerCaps (GDI32.@)
7423 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7425 lprs->nSize = sizeof(RASTERIZER_STATUS);
7426 lprs->wFlags = 0;
7427 lprs->nLanguageID = 0;
7428 return TRUE;
7431 #endif /* HAVE_FREETYPE */