gdi32: Add a helper to create a new FreeType face.
[wine.git] / dlls / gdi32 / freetype.c
blob44222cfa53228321653187ebf6ef31f2518c53ce
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 #include "resource.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FREETYPE
98 #ifdef HAVE_FT2BUILD_H
99 #include <ft2build.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
103 #endif
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
106 #endif
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
112 #endif
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
115 #endif
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
118 #endif
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
121 #endif
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
124 #endif
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
127 #endif
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
130 #endif
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
173 #else
174 MAKE_FUNCPTR(FT_MulFix);
175 #endif
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetString);
205 #endif
207 #undef MAKE_FUNCPTR
209 #ifndef FT_MAKE_TAG
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
213 #endif
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
217 #endif
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
220 #endif
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
223 #endif
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
226 #endif
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
230 #else
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
232 #endif
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
235 typedef struct {
236 FT_Short height;
237 FT_Short width;
238 FT_Pos size;
239 FT_Pos x_ppem;
240 FT_Pos y_ppem;
241 FT_Short internal_leading;
242 } Bitmap_Size;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
247 typedef struct {
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
250 } My_FT_Bitmap_Size;
252 struct enum_data
254 ENUMLOGFONTEXW elf;
255 NEWTEXTMETRICEXW ntm;
256 DWORD type;
259 typedef struct tagFace {
260 struct list entry;
261 WCHAR *StyleName;
262 WCHAR *FullName;
263 char *file;
264 void *font_data_ptr;
265 DWORD font_data_size;
266 FT_Long face_index;
267 FONTSIGNATURE fs;
268 DWORD ntmFlags;
269 FT_Fixed font_version;
270 BOOL scalable;
271 BOOL vertical;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
277 } Face;
279 typedef struct tagFamily {
280 struct list entry;
281 const WCHAR *FamilyName;
282 const WCHAR *EnglishName;
283 struct list faces;
284 struct list *replacement;
285 } Family;
287 typedef struct {
288 GLYPHMETRICS gm;
289 INT adv; /* These three hold to widths of the unrotated chars */
290 INT lsb;
291 INT bbx;
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct {
313 struct list entry;
314 Face *face;
315 GdiFont *font;
316 } CHILD_FONT;
318 struct tagGdiFont {
319 struct list entry;
320 GM **gm;
321 DWORD gmsize;
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
329 FT_Face ft_face;
330 struct font_mapping *mapping;
331 LPWSTR name;
332 int charset;
333 int codepage;
334 BOOL fake_italic;
335 BOOL fake_bold;
336 BYTE underline;
337 BYTE strikeout;
338 INT orientation;
339 FONT_DESC font_desc;
340 LONG aveWidth, ppem;
341 double scale_y;
342 SHORT yMax;
343 SHORT yMin;
344 DWORD ntmFlags;
345 FONTSIGNATURE fs;
346 GdiFont *base_font;
347 VOID *GSUB_Table;
348 DWORD cache_num;
351 typedef struct {
352 struct list entry;
353 const WCHAR *font_name;
354 FONTSIGNATURE fs;
355 struct list links;
356 } SYSTEM_LINKS;
358 struct enum_charset_element {
359 DWORD mask;
360 DWORD charset;
361 WCHAR name[LF_FACESIZE];
364 struct enum_charset_list {
365 DWORD total;
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 struct freetype_physdev
384 struct gdi_physdev dev;
385 GdiFont *font;
388 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
390 return (struct freetype_physdev *)dev;
393 static const struct gdi_dc_funcs freetype_funcs;
395 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR * const SystemFontValues[] = {
416 System_Value,
417 OEMFont_Value,
418 FixedSys_Value,
419 NULL
422 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
428 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
438 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
439 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR *default_serif_list[] =
448 times_new_roman,
449 liberation_serif,
450 bitstream_vera_serif,
451 NULL
454 static const WCHAR *default_fixed_list[] =
456 courier_new,
457 liberation_mono,
458 bitstream_vera_sans_mono,
459 NULL
462 static const WCHAR *default_sans_list[] =
464 arial,
465 liberation_sans,
466 bitstream_vera_sans,
467 NULL
470 typedef struct {
471 WCHAR *name;
472 INT charset;
473 } NameCs;
475 typedef struct tagFontSubst {
476 struct list entry;
477 NameCs from;
478 NameCs to;
479 } FontSubst;
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
487 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
488 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
489 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
491 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
501 struct font_mapping
503 struct list entry;
504 int refcount;
505 dev_t dev;
506 ino_t ino;
507 void *data;
508 size_t size;
511 static struct list mappings_list = LIST_INIT( mappings_list );
513 static CRITICAL_SECTION freetype_cs;
514 static CRITICAL_SECTION_DEBUG critsect_debug =
516 0, 0, &freetype_cs,
517 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
518 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback = FALSE;
527 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
528 static BOOL get_outline_text_metrics(GdiFont *font);
529 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
531 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
546 * Key Meaning
547 * FIXEDFON.FON FixedSys
548 * FONTS.FON System
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
562 * I have
563 * woafont=app850.fon
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
575 typedef struct {
576 DWORD version;
577 WORD ScriptList;
578 WORD FeatureList;
579 WORD LookupList;
580 } GSUB_Header;
582 typedef struct {
583 CHAR ScriptTag[4];
584 WORD Script;
585 } GSUB_ScriptRecord;
587 typedef struct {
588 WORD ScriptCount;
589 GSUB_ScriptRecord ScriptRecord[1];
590 } GSUB_ScriptList;
592 typedef struct {
593 CHAR LangSysTag[4];
594 WORD LangSys;
595 } GSUB_LangSysRecord;
597 typedef struct {
598 WORD DefaultLangSys;
599 WORD LangSysCount;
600 GSUB_LangSysRecord LangSysRecord[1];
601 } GSUB_Script;
603 typedef struct {
604 WORD LookupOrder; /* Reserved */
605 WORD ReqFeatureIndex;
606 WORD FeatureCount;
607 WORD FeatureIndex[1];
608 } GSUB_LangSys;
610 typedef struct {
611 CHAR FeatureTag[4];
612 WORD Feature;
613 } GSUB_FeatureRecord;
615 typedef struct {
616 WORD FeatureCount;
617 GSUB_FeatureRecord FeatureRecord[1];
618 } GSUB_FeatureList;
620 typedef struct {
621 WORD FeatureParams; /* Reserved */
622 WORD LookupCount;
623 WORD LookupListIndex[1];
624 } GSUB_Feature;
626 typedef struct {
627 WORD LookupCount;
628 WORD Lookup[1];
629 } GSUB_LookupList;
631 typedef struct {
632 WORD LookupType;
633 WORD LookupFlag;
634 WORD SubTableCount;
635 WORD SubTable[1];
636 } GSUB_LookupTable;
638 typedef struct {
639 WORD CoverageFormat;
640 WORD GlyphCount;
641 WORD GlyphArray[1];
642 } GSUB_CoverageFormat1;
644 typedef struct {
645 WORD Start;
646 WORD End;
647 WORD StartCoverageIndex;
648 } GSUB_RangeRecord;
650 typedef struct {
651 WORD CoverageFormat;
652 WORD RangeCount;
653 GSUB_RangeRecord RangeRecord[1];
654 } GSUB_CoverageFormat2;
656 typedef struct {
657 WORD SubstFormat; /* = 1 */
658 WORD Coverage;
659 WORD DeltaGlyphID;
660 } GSUB_SingleSubstFormat1;
662 typedef struct {
663 WORD SubstFormat; /* = 2 */
664 WORD Coverage;
665 WORD GlyphCount;
666 WORD Substitute[1];
667 }GSUB_SingleSubstFormat2;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
672 FSRef ref;
673 OSErr err;
674 static char cached_path[MAX_PATH];
675 static const char *wine = "/Wine", *fonts = "/Fonts";
677 if(*cached_path) return cached_path;
679 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
680 if(err != noErr)
682 WARN("can't create cached data folder\n");
683 return NULL;
685 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
686 if(err != noErr)
688 WARN("can't create cached data path\n");
689 *cached_path = '\0';
690 return NULL;
692 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
694 ERR("Could not create full path\n");
695 *cached_path = '\0';
696 return NULL;
698 strcat(cached_path, wine);
700 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
702 WARN("Couldn't mkdir %s\n", cached_path);
703 *cached_path = '\0';
704 return NULL;
706 strcat(cached_path, fonts);
707 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
709 WARN("Couldn't mkdir %s\n", cached_path);
710 *cached_path = '\0';
711 return NULL;
713 return cached_path;
716 /******************************************************************
717 * expand_mac_font
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
721 * find_cache_dir()).
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path)
729 FSRef ref;
730 SInt16 res_ref;
731 OSStatus s;
732 unsigned int idx;
733 const char *out_dir;
734 const char *filename;
735 int output_len;
736 struct {
737 char **array;
738 unsigned int size, max_size;
739 } ret;
741 TRACE("path %s\n", path);
743 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
744 if(s != noErr)
746 WARN("failed to get ref\n");
747 return NULL;
750 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
751 if(s != noErr)
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref = FSOpenResFile(&ref, fsRdPerm);
755 if(res_ref == -1)
757 TRACE("unable to open resource fork\n");
758 return NULL;
762 ret.size = 0;
763 ret.max_size = 10;
764 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
765 if(!ret.array)
767 CloseResFile(res_ref);
768 return NULL;
771 out_dir = find_cache_dir();
773 filename = strrchr(path, '/');
774 if(!filename) filename = path;
775 else filename++;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
780 UseResFile(res_ref);
781 idx = 1;
782 while(1)
784 FamRec *fam_rec;
785 unsigned short *num_faces_ptr, num_faces, face;
786 AsscEntry *assoc;
787 Handle fond;
788 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
790 fond = Get1IndResource(fond_res, idx);
791 if(!fond) break;
792 TRACE("got fond resource %d\n", idx);
793 HLock(fond);
795 fam_rec = *(FamRec**)fond;
796 num_faces_ptr = (unsigned short *)(fam_rec + 1);
797 num_faces = GET_BE_WORD(*num_faces_ptr);
798 num_faces++;
799 assoc = (AsscEntry*)(num_faces_ptr + 1);
800 TRACE("num faces %04x\n", num_faces);
801 for(face = 0; face < num_faces; face++, assoc++)
803 Handle sfnt;
804 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
805 unsigned short size, font_id;
806 char *output;
808 size = GET_BE_WORD(assoc->fontSize);
809 font_id = GET_BE_WORD(assoc->fontID);
810 if(size != 0)
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
813 continue;
816 TRACE("trying to load sfnt id %04x\n", font_id);
817 sfnt = GetResource(sfnt_res, font_id);
818 if(!sfnt)
820 TRACE("can't get sfnt resource %04x\n", font_id);
821 continue;
824 output = HeapAlloc(GetProcessHeap(), 0, output_len);
825 if(output)
827 int fd;
829 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
831 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
832 if(fd != -1 || errno == EEXIST)
834 if(fd != -1)
836 unsigned char *sfnt_data;
838 HLock(sfnt);
839 sfnt_data = *(unsigned char**)sfnt;
840 write(fd, sfnt_data, GetHandleSize(sfnt));
841 HUnlock(sfnt);
842 close(fd);
844 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
846 ret.max_size *= 2;
847 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
849 ret.array[ret.size++] = output;
851 else
853 WARN("unable to create %s\n", output);
854 HeapFree(GetProcessHeap(), 0, output);
857 ReleaseResource(sfnt);
859 HUnlock(fond);
860 ReleaseResource(fond);
861 idx++;
863 CloseResFile(res_ref);
865 return ret.array;
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed FT_FixedFromFloat(double f)
880 return f * 0x10000;
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
889 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
893 static const struct list *get_face_list_from_family(const Family *family)
895 if (!list_empty(&family->faces))
896 return &family->faces;
897 else
898 return family->replacement;
901 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
903 Family *family;
904 Face *face;
905 const char *file;
906 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
907 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
909 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
912 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
914 const struct list *face_list;
915 if(face_name && strcmpiW(face_name, family->FamilyName))
916 continue;
917 face_list = get_face_list_from_family(family);
918 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
920 if (!face->file)
921 continue;
922 file = strrchr(face->file, '/');
923 if(!file)
924 file = face->file;
925 else
926 file++;
927 if(!strcasecmp(file, file_nameA))
929 HeapFree(GetProcessHeap(), 0, file_nameA);
930 return face;
934 HeapFree(GetProcessHeap(), 0, file_nameA);
935 return NULL;
938 static Family *find_family_from_name(const WCHAR *name)
940 Family *family;
942 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
944 if(!strcmpiW(family->FamilyName, name))
945 return family;
948 return NULL;
951 static Family *find_family_from_any_name(const WCHAR *name)
953 Family *family;
955 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
957 if(!strcmpiW(family->FamilyName, name))
958 return family;
959 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
960 return family;
963 return NULL;
966 static void DumpSubstList(void)
968 FontSubst *psub;
970 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
972 if(psub->from.charset != -1 || psub->to.charset != -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
974 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
975 else
976 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
977 debugstr_w(psub->to.name));
979 return;
982 static LPWSTR strdupW(LPCWSTR p)
984 LPWSTR ret;
985 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
986 ret = HeapAlloc(GetProcessHeap(), 0, len);
987 memcpy(ret, p, len);
988 return ret;
991 static LPSTR strdupA(LPCSTR p)
993 LPSTR ret;
994 DWORD len = (strlen(p) + 1);
995 ret = HeapAlloc(GetProcessHeap(), 0, len);
996 memcpy(ret, p, len);
997 return ret;
1000 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1001 INT from_charset)
1003 FontSubst *element;
1005 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1007 if(!strcmpiW(element->from.name, from_name) &&
1008 (element->from.charset == from_charset ||
1009 element->from.charset == -1))
1010 return element;
1013 return NULL;
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1020 FontSubst *from_exist, *to_exist;
1022 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1024 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1026 list_remove(&from_exist->entry);
1027 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1028 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1029 HeapFree(GetProcessHeap(), 0, from_exist);
1030 from_exist = NULL;
1033 if(!from_exist)
1035 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1037 if(to_exist)
1039 HeapFree(GetProcessHeap(), 0, subst->to.name);
1040 subst->to.name = strdupW(to_exist->to.name);
1043 list_add_tail(subst_list, &subst->entry);
1045 return TRUE;
1048 HeapFree(GetProcessHeap(), 0, subst->from.name);
1049 HeapFree(GetProcessHeap(), 0, subst->to.name);
1050 HeapFree(GetProcessHeap(), 0, subst);
1051 return FALSE;
1054 static WCHAR *towstr(UINT cp, const char *str)
1056 int len;
1057 WCHAR *wstr;
1059 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1060 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1061 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1062 return wstr;
1065 static void split_subst_info(NameCs *nc, LPSTR str)
1067 CHAR *p = strrchr(str, ',');
1069 nc->charset = -1;
1070 if(p && *(p+1)) {
1071 nc->charset = strtol(p+1, NULL, 10);
1072 *p = '\0';
1074 nc->name = towstr(CP_ACP, str);
1077 static void LoadSubstList(void)
1079 FontSubst *psub;
1080 HKEY hkey;
1081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1082 LPSTR value;
1083 LPVOID data;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey) == ERROR_SUCCESS) {
1089 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1090 &valuelen, &datalen, NULL, NULL);
1092 valuelen++; /* returned value doesn't include room for '\0' */
1093 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1094 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1096 dlen = datalen;
1097 vlen = valuelen;
1098 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1099 &dlen) == ERROR_SUCCESS) {
1100 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1102 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1103 split_subst_info(&psub->from, value);
1104 split_subst_info(&psub->to, data);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1109 psub->to.charset == DEFAULT_CHARSET) {
1110 HeapFree(GetProcessHeap(), 0, psub->to.name);
1111 HeapFree(GetProcessHeap(), 0, psub->from.name);
1112 HeapFree(GetProcessHeap(), 0, psub);
1113 } else {
1114 add_font_subst(&font_subst_list, psub, 0);
1116 /* reset dlen and vlen */
1117 dlen = datalen;
1118 vlen = valuelen;
1120 HeapFree(GetProcessHeap(), 0, data);
1121 HeapFree(GetProcessHeap(), 0, value);
1122 RegCloseKey(hkey);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1137 FT_SfntName name;
1138 FT_UInt num_names, name_index;
1140 if(FT_IS_SFNT(ft_face))
1142 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1144 for(name_index = 0; name_index < num_names; name_index++)
1146 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1148 if((name.platform_id == req->platform_id) &&
1149 (name.encoding_id == req->encoding_id) &&
1150 (name.language_id == req->language_id) &&
1151 (name.name_id == req->name_id))
1153 req->string = name.string;
1154 req->string_len = name.string_len;
1155 return TRUE;
1160 req->string = NULL;
1161 req->string_len = 0;
1162 return FALSE;
1165 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1167 WCHAR *ret = NULL;
1168 FT_SfntName name;
1170 name.platform_id = TT_PLATFORM_MICROSOFT;
1171 name.encoding_id = TT_MS_ID_UNICODE_CS;
1172 name.language_id = language_id;
1173 name.name_id = name_id;
1175 if(get_name_table_entry(ft_face, &name))
1177 FT_UInt i;
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1181 for(i = 0; i < name.string_len / 2; i++)
1183 WORD *tmp = (WORD *)&name.string[i * 2];
1184 ret[i] = GET_BE_WORD(*tmp);
1186 ret[i] = 0;
1187 TRACE("Got localised name %s\n", debugstr_w(ret));
1190 return ret;
1193 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1195 DWORD type, needed;
1196 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1197 if(r != ERROR_SUCCESS) return r;
1198 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1199 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1202 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1204 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1207 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1209 DWORD needed;
1210 DWORD num_strikes, max_strike_key_len;
1212 /* If we have a File Name key then this is a real font, not just the parent
1213 key of a bunch of non-scalable strikes */
1214 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1216 DWORD italic, bold;
1217 Face *face;
1218 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1219 face->cached_enum_data = NULL;
1221 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1222 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1224 face->StyleName = strdupW(face_name);
1225 face->family = family;
1226 face->vertical = (family->FamilyName[0] == '@');
1228 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1230 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1231 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1232 face->FullName = fullName;
1234 else
1235 face->FullName = NULL;
1237 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1238 reg_load_dword(hkey_face, face_italic_value, &italic);
1239 reg_load_dword(hkey_face, face_bold_value, &bold);
1240 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1241 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1243 needed = sizeof(face->fs);
1244 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1246 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1248 face->scalable = TRUE;
1249 memset(&face->size, 0, sizeof(face->size));
1251 else
1253 face->scalable = FALSE;
1254 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1255 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1256 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1257 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1258 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1260 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1261 face->size.height, face->size.width, face->size.size >> 6,
1262 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1265 face->ntmFlags = 0;
1266 if (italic) face->ntmFlags |= NTM_ITALIC;
1267 if (bold) face->ntmFlags |= NTM_BOLD;
1268 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1270 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1271 face->fs.fsCsb[0], face->fs.fsCsb[1],
1272 face->fs.fsUsb[0], face->fs.fsUsb[1],
1273 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1275 if(!italic && !bold)
1276 list_add_head(&family->faces, &face->entry);
1277 else
1278 list_add_tail(&family->faces, &face->entry);
1280 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1283 /* do we have any bitmap strikes? */
1284 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1285 NULL, NULL, NULL, NULL);
1286 if(num_strikes != 0)
1288 WCHAR strike_name[10];
1289 DWORD strike_index = 0;
1291 needed = sizeof(strike_name) / sizeof(WCHAR);
1292 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1293 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1295 HKEY hkey_strike;
1296 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1297 load_face(hkey_strike, face_name, family);
1298 RegCloseKey(hkey_strike);
1299 needed = sizeof(strike_name) / sizeof(WCHAR);
1304 static void load_font_list_from_cache(HKEY hkey_font_cache)
1306 DWORD max_family_key_len, size;
1307 WCHAR *family_name;
1308 DWORD family_index = 0;
1309 Family *family;
1310 HKEY hkey_family;
1312 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1313 NULL, NULL, NULL, NULL);
1314 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1316 size = max_family_key_len + 1;
1317 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1318 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1320 WCHAR *english_family = NULL;
1321 DWORD face_index = 0;
1322 WCHAR *face_name;
1323 DWORD max_face_key_len;
1325 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1326 TRACE("opened family key %s\n", debugstr_w(family_name));
1327 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1329 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1330 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1333 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1334 family->FamilyName = strdupW(family_name);
1335 family->EnglishName = english_family;
1336 list_init(&family->faces);
1337 family->replacement = &family->faces;
1338 list_add_tail(&font_list, &family->entry);
1340 if(english_family)
1342 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1343 subst->from.name = strdupW(english_family);
1344 subst->from.charset = -1;
1345 subst->to.name = strdupW(family_name);
1346 subst->to.charset = -1;
1347 add_font_subst(&font_subst_list, subst, 0);
1350 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1351 NULL, NULL, NULL, NULL);
1353 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1354 size = max_face_key_len + 1;
1355 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1356 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1358 HKEY hkey_face;
1360 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1361 load_face(hkey_face, face_name, family);
1362 RegCloseKey(hkey_face);
1363 size = max_face_key_len + 1;
1365 HeapFree(GetProcessHeap(), 0, face_name);
1366 RegCloseKey(hkey_family);
1367 size = max_family_key_len + 1;
1370 HeapFree(GetProcessHeap(), 0, family_name);
1373 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1375 LONG ret;
1376 HKEY hkey_wine_fonts;
1378 /* We don't want to create the fonts key as volatile, so open this first */
1379 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1380 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1381 if(ret != ERROR_SUCCESS)
1383 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1384 return ret;
1387 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1388 KEY_ALL_ACCESS, NULL, hkey, disposition);
1389 RegCloseKey(hkey_wine_fonts);
1390 return ret;
1393 static void add_face_to_cache(Face *face)
1395 HKEY hkey_font_cache, hkey_family, hkey_face;
1396 WCHAR *face_key_name;
1398 create_font_cache_key(&hkey_font_cache, NULL);
1400 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1401 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1402 if(face->family->EnglishName)
1403 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1404 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1406 if(face->scalable)
1407 face_key_name = face->StyleName;
1408 else
1410 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1411 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1412 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1414 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1415 &hkey_face, NULL);
1416 if(!face->scalable)
1417 HeapFree(GetProcessHeap(), 0, face_key_name);
1419 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1420 if (face->FullName)
1421 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1422 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1424 reg_save_dword(hkey_face, face_index_value, face->face_index);
1425 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1426 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1427 reg_save_dword(hkey_face, face_version_value, face->font_version);
1428 reg_save_dword(hkey_face, face_external_value, face->external);
1430 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1432 if(!face->scalable)
1434 reg_save_dword(hkey_face, face_height_value, face->size.height);
1435 reg_save_dword(hkey_face, face_width_value, face->size.width);
1436 reg_save_dword(hkey_face, face_size_value, face->size.size);
1437 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1438 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1439 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1441 RegCloseKey(hkey_face);
1442 RegCloseKey(hkey_family);
1443 RegCloseKey(hkey_font_cache);
1446 static inline int TestStyles(DWORD flags, DWORD styles)
1448 return (flags & styles) == styles;
1451 static inline int style_order(Face *face)
1453 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1454 return 3;
1455 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1456 return 2;
1457 if (TestStyles(face->ntmFlags, NTM_BOLD))
1458 return 1;
1459 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1460 return 0;
1462 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1463 debugstr_w(face->family->FamilyName),
1464 debugstr_w(face->StyleName),
1465 face->ntmFlags);
1467 return 9999;
1470 static WCHAR *prepend_at(WCHAR *family)
1472 WCHAR *str;
1474 if (!family)
1475 return NULL;
1477 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1478 str[0] = '@';
1479 strcpyW(str + 1, family);
1480 HeapFree(GetProcessHeap(), 0, family);
1481 return str;
1484 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1486 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1487 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1489 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1490 if (!*name)
1492 *name = *english;
1493 *english = NULL;
1495 else if (!strcmpiW( *name, *english ))
1497 HeapFree( GetProcessHeap(), 0, *english );
1498 *english = NULL;
1501 if (vertical)
1503 *name = prepend_at( *name );
1504 *english = prepend_at( *english );
1508 /****************************************************************
1509 * NB This function stores the ptrs to the strings to save copying.
1510 * Don't free them after calling.
1512 static Family *create_family( WCHAR *name, WCHAR *english_name )
1514 Family *family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1515 family->FamilyName = name;
1516 family->EnglishName = english_name;
1517 list_init( &family->faces );
1518 family->replacement = &family->faces;
1520 return family;
1523 static Family *get_family( FT_Face ft_face, BOOL vertical )
1525 Family *family;
1526 WCHAR *name, *english_name;
1528 get_family_names( ft_face, &name, &english_name, vertical );
1530 family = find_family_from_name( name );
1532 if (!family)
1534 family = create_family( name, english_name );
1535 list_add_tail( &font_list, &family->entry );
1537 if (english_name)
1539 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1540 subst->from.name = strdupW( english_name );
1541 subst->from.charset = -1;
1542 subst->to.name = strdupW( name );
1543 subst->to.charset = -1;
1544 add_font_subst( &font_subst_list, subst, 0 );
1547 else
1549 HeapFree( GetProcessHeap(), 0, name );
1550 HeapFree( GetProcessHeap(), 0, english_name );
1553 return family;
1556 static inline FT_Fixed get_font_version( FT_Face ft_face )
1558 FT_Fixed version = 0;
1559 TT_Header *header;
1561 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1562 if (header) version = header->Font_Revision;
1564 return version;
1567 static inline DWORD get_ntm_flags( FT_Face ft_face )
1569 DWORD flags = 0;
1570 FT_ULong table_size = 0;
1572 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1573 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1574 if (flags == 0) flags = NTM_REGULAR;
1576 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1577 flags |= NTM_PS_OPENTYPE;
1579 return flags;
1582 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1584 int internal_leading = 0;
1585 FT_WinFNT_HeaderRec winfnt_header;
1587 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1588 internal_leading = winfnt_header.internal_leading;
1590 return internal_leading;
1593 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1595 TT_OS2 *os2;
1596 FT_UInt dummy;
1597 CHARSETINFO csi;
1598 FT_WinFNT_HeaderRec winfnt_header;
1599 int i;
1601 memset( fs, 0, sizeof(*fs) );
1603 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1604 if (os2)
1606 fs->fsUsb[0] = os2->ulUnicodeRange1;
1607 fs->fsUsb[1] = os2->ulUnicodeRange2;
1608 fs->fsUsb[2] = os2->ulUnicodeRange3;
1609 fs->fsUsb[3] = os2->ulUnicodeRange4;
1611 if (os2->version == 0)
1613 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1614 fs->fsCsb[0] = FS_LATIN1;
1615 else
1616 fs->fsCsb[0] = FS_SYMBOL;
1618 else
1620 fs->fsCsb[0] = os2->ulCodePageRange1;
1621 fs->fsCsb[1] = os2->ulCodePageRange2;
1624 else
1626 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1628 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1629 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1630 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1631 *fs = csi.fs;
1635 if (fs->fsCsb[0] == 0)
1637 /* let's see if we can find any interesting cmaps */
1638 for (i = 0; i < ft_face->num_charmaps; i++)
1640 switch (ft_face->charmaps[i]->encoding)
1642 case FT_ENCODING_UNICODE:
1643 case FT_ENCODING_APPLE_ROMAN:
1644 fs->fsCsb[0] |= FS_LATIN1;
1645 break;
1646 case FT_ENCODING_MS_SYMBOL:
1647 fs->fsCsb[0] |= FS_SYMBOL;
1648 break;
1649 default:
1650 break;
1656 static inline void free_face( Face *face )
1658 HeapFree( GetProcessHeap(), 0, face->file );
1659 HeapFree( GetProcessHeap(), 0, face->StyleName );
1660 HeapFree( GetProcessHeap(), 0, face->FullName );
1661 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1662 HeapFree( GetProcessHeap(), 0, face );
1665 #define ADDFONT_EXTERNAL_FONT 0x01
1666 #define ADDFONT_FORCE_BITMAP 0x02
1667 #define ADDFONT_ADD_TO_CACHE 0x04
1669 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1670 DWORD flags, BOOL vertical )
1672 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1673 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1675 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1676 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1677 if (file)
1679 face->file = strdupA( file );
1680 face->font_data_ptr = NULL;
1681 face->font_data_size = 0;
1683 else
1685 face->file = NULL;
1686 face->font_data_ptr = font_data_ptr;
1687 face->font_data_size = font_data_size;
1690 face->face_index = face_index;
1691 get_fontsig( ft_face, &face->fs );
1692 face->ntmFlags = get_ntm_flags( ft_face );
1693 face->font_version = get_font_version( ft_face );
1695 if (FT_IS_SCALABLE( ft_face ))
1697 memset( &face->size, 0, sizeof(face->size) );
1698 face->scalable = TRUE;
1700 else
1702 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1703 size->height, size->width, size->size >> 6,
1704 size->x_ppem >> 6, size->y_ppem >> 6);
1705 face->size.height = size->height;
1706 face->size.width = size->width;
1707 face->size.size = size->size;
1708 face->size.x_ppem = size->x_ppem;
1709 face->size.y_ppem = size->y_ppem;
1710 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1711 face->scalable = FALSE;
1714 face->vertical = vertical;
1715 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1716 face->family = NULL;
1717 face->cached_enum_data = NULL;
1719 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1720 face->fs.fsCsb[0], face->fs.fsCsb[1],
1721 face->fs.fsUsb[0], face->fs.fsUsb[1],
1722 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1724 return face;
1727 static inline BOOL faces_equal( Face *f1, Face *f2 )
1729 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1730 if (f1->scalable) return TRUE;
1731 if (f2->size.y_ppem != f2->size.y_ppem) return FALSE;
1732 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1735 static BOOL insert_face_in_family_list( Face *face, Family *family )
1737 Face *cursor;
1739 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1741 if (faces_equal( face, cursor ))
1743 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1744 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1745 cursor->font_version, face->font_version);
1747 if (face->font_version <= cursor->font_version)
1749 TRACE("Original font is newer so skipping this one\n");
1750 return FALSE;
1752 else
1754 TRACE("Replacing original with this one\n");
1755 list_add_before( &cursor->entry, &face->entry );
1756 face->family = family;
1757 list_remove( &cursor->entry);
1758 free_face( cursor );
1759 return TRUE;
1763 if (style_order( face ) < style_order( cursor )) break;
1766 list_add_before( &cursor->entry, &face->entry );
1767 face->family = family;
1768 return TRUE;
1771 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1772 FT_Long face_index, DWORD flags, BOOL vertical)
1774 Face *face;
1775 Family *family;
1777 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical );
1778 family = get_family( ft_face, vertical );
1779 if (!insert_face_in_family_list( face, family ))
1781 free_face( face );
1782 return;
1785 if (flags & ADDFONT_ADD_TO_CACHE)
1786 add_face_to_cache( face );
1788 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1789 debugstr_w(face->StyleName));
1792 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1793 FT_Long face_index, BOOL allow_bitmap )
1795 FT_Error err;
1796 TT_OS2 *pOS2;
1797 FT_Face ft_face;
1799 if (file)
1801 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1802 err = pFT_New_Face(library, file, face_index, &ft_face);
1804 else
1806 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1807 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1810 if (err != 0)
1812 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1813 return NULL;
1816 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1817 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1819 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1820 goto fail;
1823 if (!FT_IS_SFNT( ft_face ))
1825 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1827 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1828 goto fail;
1831 else
1833 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1834 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1835 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1837 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1838 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1839 goto fail;
1842 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1843 we don't want to load these. */
1844 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1846 FT_ULong len = 0;
1848 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1850 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1851 goto fail;
1856 if (!ft_face->family_name || !ft_face->style_name)
1858 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1859 goto fail;
1862 return ft_face;
1863 fail:
1864 pFT_Done_Face( ft_face );
1865 return NULL;
1868 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1870 FT_Face ft_face;
1871 FT_Long face_index = 0, num_faces;
1872 INT ret = 0;
1874 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1875 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1877 #ifdef HAVE_CARBON_CARBON_H
1878 if(file)
1880 char **mac_list = expand_mac_font(file);
1881 if(mac_list)
1883 BOOL had_one = FALSE;
1884 char **cursor;
1885 for(cursor = mac_list; *cursor; cursor++)
1887 had_one = TRUE;
1888 AddFontToList(*cursor, NULL, 0, flags);
1889 HeapFree(GetProcessHeap(), 0, *cursor);
1891 HeapFree(GetProcessHeap(), 0, mac_list);
1892 if(had_one)
1893 return 1;
1896 #endif /* HAVE_CARBON_CARBON_H */
1898 do {
1899 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1900 if (!ft_face) return 0;
1902 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1904 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1905 pFT_Done_Face(ft_face);
1906 return 0;
1909 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1910 ++ret;
1912 if (FT_HAS_VERTICAL(ft_face))
1914 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1915 ++ret;
1918 num_faces = ft_face->num_faces;
1919 pFT_Done_Face(ft_face);
1920 } while(num_faces > ++face_index);
1921 return ret;
1924 static void DumpFontList(void)
1926 Family *family;
1927 Face *face;
1928 struct list *family_elem_ptr, *face_elem_ptr;
1930 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1931 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1932 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1933 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1934 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1935 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1936 if(!face->scalable)
1937 TRACE(" %d", face->size.height);
1938 TRACE("\n");
1941 return;
1944 /***********************************************************
1945 * The replacement list is a way to map an entire font
1946 * family onto another family. For example adding
1948 * [HKCU\Software\Wine\Fonts\Replacements]
1949 * "Wingdings"="Winedings"
1951 * would enumerate the Winedings font both as Winedings and
1952 * Wingdings. However if a real Wingdings font is present the
1953 * replacement does not take place.
1956 static void LoadReplaceList(void)
1958 HKEY hkey;
1959 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1960 LPWSTR value;
1961 LPVOID data;
1962 CHAR familyA[400];
1964 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1965 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1967 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1968 &valuelen, &datalen, NULL, NULL);
1970 valuelen++; /* returned value doesn't include room for '\0' */
1971 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1972 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1974 dlen = datalen;
1975 vlen = valuelen;
1976 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1977 &dlen) == ERROR_SUCCESS) {
1978 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1979 /* "NewName"="Oldname" */
1980 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1982 if(!find_family_from_any_name(value))
1984 Family * const family = find_family_from_any_name(data);
1985 if (family != NULL)
1987 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1988 if (new_family != NULL)
1990 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1991 new_family->FamilyName = strdupW(value);
1992 new_family->EnglishName = NULL;
1993 list_init(&new_family->faces);
1994 new_family->replacement = &family->faces;
1995 list_add_tail(&font_list, &new_family->entry);
1998 else
2000 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2003 else
2005 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2007 /* reset dlen and vlen */
2008 dlen = datalen;
2009 vlen = valuelen;
2011 HeapFree(GetProcessHeap(), 0, data);
2012 HeapFree(GetProcessHeap(), 0, value);
2013 RegCloseKey(hkey);
2017 static const WCHAR *font_links_list[] =
2019 Lucida_Sans_Unicode,
2020 Microsoft_Sans_Serif,
2021 Tahoma
2024 static const struct font_links_defaults_list
2026 /* Keyed off substitution for "MS Shell Dlg" */
2027 const WCHAR *shelldlg;
2028 /* Maximum of four substitutes, plus terminating NULL pointer */
2029 const WCHAR *substitutes[5];
2030 } font_links_defaults_list[] =
2032 /* Non East-Asian */
2033 { Tahoma, /* FIXME unverified ordering */
2034 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2036 /* Below lists are courtesy of
2037 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2039 /* Japanese */
2040 { MS_UI_Gothic,
2041 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2043 /* Chinese Simplified */
2044 { SimSun,
2045 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2047 /* Korean */
2048 { Gulim,
2049 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2051 /* Chinese Traditional */
2052 { PMingLiU,
2053 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2058 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2060 SYSTEM_LINKS *font_link;
2062 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2064 if(!strcmpiW(font_link->font_name, name))
2065 return font_link;
2068 return NULL;
2071 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2073 const WCHAR *value;
2074 int i;
2075 FontSubst *psub;
2076 Family *family;
2077 Face *face;
2078 const char *file;
2079 WCHAR *fileW;
2081 if (values)
2083 SYSTEM_LINKS *font_link;
2085 psub = get_font_subst(&font_subst_list, name, -1);
2086 /* Don't store fonts that are only substitutes for other fonts */
2087 if(psub)
2089 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2090 return;
2093 font_link = find_font_link(name);
2094 if (font_link == NULL)
2096 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2097 font_link->font_name = strdupW(name);
2098 list_init(&font_link->links);
2099 list_add_tail(&system_links, &font_link->entry);
2102 memset(&font_link->fs, 0, sizeof font_link->fs);
2103 for (i = 0; values[i] != NULL; i++)
2105 const struct list *face_list;
2106 CHILD_FONT *child_font;
2108 value = values[i];
2109 if (!strcmpiW(name,value))
2110 continue;
2111 psub = get_font_subst(&font_subst_list, value, -1);
2112 if(psub)
2113 value = psub->to.name;
2114 family = find_family_from_name(value);
2115 if (!family)
2116 continue;
2117 file = NULL;
2118 /* Use first extant filename for this Family */
2119 face_list = get_face_list_from_family(family);
2120 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2122 if (!face->file)
2123 continue;
2124 file = strrchr(face->file, '/');
2125 if (!file)
2126 file = face->file;
2127 else
2128 file++;
2129 break;
2131 if (!file)
2132 continue;
2133 fileW = towstr(CP_UNIXCP, file);
2135 face = find_face_from_filename(fileW, value);
2136 if(!face)
2138 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2139 continue;
2142 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2143 child_font->face = face;
2144 child_font->font = NULL;
2145 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2146 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2147 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2148 list_add_tail(&font_link->links, &child_font->entry);
2150 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2151 HeapFree(GetProcessHeap(), 0, fileW);
2157 /*************************************************************
2158 * init_system_links
2160 static BOOL init_system_links(void)
2162 HKEY hkey;
2163 BOOL ret = FALSE;
2164 DWORD type, max_val, max_data, val_len, data_len, index;
2165 WCHAR *value, *data;
2166 WCHAR *entry, *next;
2167 SYSTEM_LINKS *font_link, *system_font_link;
2168 CHILD_FONT *child_font;
2169 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2170 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2171 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2172 Face *face;
2173 FontSubst *psub;
2174 UINT i, j;
2176 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2178 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2179 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2180 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2181 val_len = max_val + 1;
2182 data_len = max_data;
2183 index = 0;
2184 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2186 psub = get_font_subst(&font_subst_list, value, -1);
2187 /* Don't store fonts that are only substitutes for other fonts */
2188 if(psub)
2190 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2191 goto next;
2193 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2194 font_link->font_name = strdupW(value);
2195 memset(&font_link->fs, 0, sizeof font_link->fs);
2196 list_init(&font_link->links);
2197 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2199 WCHAR *face_name;
2200 CHILD_FONT *child_font;
2202 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2204 next = entry + strlenW(entry) + 1;
2206 face_name = strchrW(entry, ',');
2207 if(face_name)
2209 *face_name++ = 0;
2210 while(isspaceW(*face_name))
2211 face_name++;
2213 psub = get_font_subst(&font_subst_list, face_name, -1);
2214 if(psub)
2215 face_name = psub->to.name;
2217 face = find_face_from_filename(entry, face_name);
2218 if(!face)
2220 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2221 continue;
2224 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2225 child_font->face = face;
2226 child_font->font = NULL;
2227 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2228 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2229 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2230 list_add_tail(&font_link->links, &child_font->entry);
2232 list_add_tail(&system_links, &font_link->entry);
2233 next:
2234 val_len = max_val + 1;
2235 data_len = max_data;
2238 HeapFree(GetProcessHeap(), 0, value);
2239 HeapFree(GetProcessHeap(), 0, data);
2240 RegCloseKey(hkey);
2244 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2245 if (!psub) {
2246 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2247 goto skip_internal;
2250 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2252 const FontSubst *psub2;
2253 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2255 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2257 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2258 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2260 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2261 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2263 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2265 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2269 skip_internal:
2271 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2272 that Tahoma has */
2274 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2275 system_font_link->font_name = strdupW(System);
2276 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2277 list_init(&system_font_link->links);
2279 face = find_face_from_filename(tahoma_ttf, Tahoma);
2280 if(face)
2282 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2283 child_font->face = face;
2284 child_font->font = NULL;
2285 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2286 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2287 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2288 list_add_tail(&system_font_link->links, &child_font->entry);
2290 font_link = find_font_link(Tahoma);
2291 if (font_link != NULL)
2293 CHILD_FONT *font_link_entry;
2294 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2296 CHILD_FONT *new_child;
2297 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2298 new_child->face = font_link_entry->face;
2299 new_child->font = NULL;
2300 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2301 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2302 list_add_tail(&system_font_link->links, &new_child->entry);
2305 list_add_tail(&system_links, &system_font_link->entry);
2306 return ret;
2309 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2311 DIR *dir;
2312 struct dirent *dent;
2313 char path[MAX_PATH];
2315 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2317 dir = opendir(dirname);
2318 if(!dir) {
2319 WARN("Can't open directory %s\n", debugstr_a(dirname));
2320 return FALSE;
2322 while((dent = readdir(dir)) != NULL) {
2323 struct stat statbuf;
2325 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2326 continue;
2328 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2330 sprintf(path, "%s/%s", dirname, dent->d_name);
2332 if(stat(path, &statbuf) == -1)
2334 WARN("Can't stat %s\n", debugstr_a(path));
2335 continue;
2337 if(S_ISDIR(statbuf.st_mode))
2338 ReadFontDir(path, external_fonts);
2339 else
2341 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2342 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2343 AddFontToList(path, NULL, 0, addfont_flags);
2346 closedir(dir);
2347 return TRUE;
2350 static void load_fontconfig_fonts(void)
2352 #ifdef SONAME_LIBFONTCONFIG
2353 void *fc_handle = NULL;
2354 FcConfig *config;
2355 FcPattern *pat;
2356 FcObjectSet *os;
2357 FcFontSet *fontset;
2358 int i, len;
2359 char *file;
2360 const char *ext;
2362 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2363 if(!fc_handle) {
2364 TRACE("Wine cannot find the fontconfig library (%s).\n",
2365 SONAME_LIBFONTCONFIG);
2366 return;
2368 #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;}
2369 LOAD_FUNCPTR(FcConfigGetCurrent);
2370 LOAD_FUNCPTR(FcFontList);
2371 LOAD_FUNCPTR(FcFontSetDestroy);
2372 LOAD_FUNCPTR(FcInit);
2373 LOAD_FUNCPTR(FcObjectSetAdd);
2374 LOAD_FUNCPTR(FcObjectSetCreate);
2375 LOAD_FUNCPTR(FcObjectSetDestroy);
2376 LOAD_FUNCPTR(FcPatternCreate);
2377 LOAD_FUNCPTR(FcPatternDestroy);
2378 LOAD_FUNCPTR(FcPatternGetBool);
2379 LOAD_FUNCPTR(FcPatternGetString);
2380 #undef LOAD_FUNCPTR
2382 if(!pFcInit()) return;
2384 config = pFcConfigGetCurrent();
2385 pat = pFcPatternCreate();
2386 os = pFcObjectSetCreate();
2387 pFcObjectSetAdd(os, FC_FILE);
2388 pFcObjectSetAdd(os, FC_SCALABLE);
2389 fontset = pFcFontList(config, pat, os);
2390 if(!fontset) return;
2391 for(i = 0; i < fontset->nfont; i++) {
2392 FcBool scalable;
2394 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2395 continue;
2396 TRACE("fontconfig: %s\n", file);
2398 /* We're just interested in OT/TT fonts for now, so this hack just
2399 picks up the scalable fonts without extensions .pf[ab] to save time
2400 loading every other font */
2402 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2404 TRACE("not scalable\n");
2405 continue;
2408 len = strlen( file );
2409 if(len < 4) continue;
2410 ext = &file[ len - 3 ];
2411 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2412 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2414 pFcFontSetDestroy(fontset);
2415 pFcObjectSetDestroy(os);
2416 pFcPatternDestroy(pat);
2417 sym_not_found:
2418 #endif
2419 return;
2422 static BOOL load_font_from_data_dir(LPCWSTR file)
2424 BOOL ret = FALSE;
2425 const char *data_dir = wine_get_data_dir();
2427 if (!data_dir) data_dir = wine_get_build_dir();
2429 if (data_dir)
2431 INT len;
2432 char *unix_name;
2434 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2436 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2438 strcpy(unix_name, data_dir);
2439 strcat(unix_name, "/fonts/");
2441 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2443 EnterCriticalSection( &freetype_cs );
2444 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2445 LeaveCriticalSection( &freetype_cs );
2446 HeapFree(GetProcessHeap(), 0, unix_name);
2448 return ret;
2451 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2453 static const WCHAR slashW[] = {'\\','\0'};
2454 BOOL ret = FALSE;
2455 WCHAR windowsdir[MAX_PATH];
2456 char *unixname;
2458 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2459 strcatW(windowsdir, fontsW);
2460 strcatW(windowsdir, slashW);
2461 strcatW(windowsdir, file);
2462 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2463 EnterCriticalSection( &freetype_cs );
2464 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2465 LeaveCriticalSection( &freetype_cs );
2466 HeapFree(GetProcessHeap(), 0, unixname);
2468 return ret;
2471 static void load_system_fonts(void)
2473 HKEY hkey;
2474 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2475 const WCHAR * const *value;
2476 DWORD dlen, type;
2477 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2478 char *unixname;
2480 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2481 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2482 strcatW(windowsdir, fontsW);
2483 for(value = SystemFontValues; *value; value++) {
2484 dlen = sizeof(data);
2485 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2486 type == REG_SZ) {
2487 BOOL added = FALSE;
2489 sprintfW(pathW, fmtW, windowsdir, data);
2490 if((unixname = wine_get_unix_file_name(pathW))) {
2491 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2492 HeapFree(GetProcessHeap(), 0, unixname);
2494 if (!added)
2495 load_font_from_data_dir(data);
2498 RegCloseKey(hkey);
2502 /*************************************************************
2504 * This adds registry entries for any externally loaded fonts
2505 * (fonts from fontconfig or FontDirs). It also deletes entries
2506 * of no longer existing fonts.
2509 static void update_reg_entries(void)
2511 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2512 LPWSTR valueW;
2513 DWORD len, len_fam;
2514 Family *family;
2515 Face *face;
2516 struct list *family_elem_ptr, *face_elem_ptr;
2517 WCHAR *file;
2518 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2519 static const WCHAR spaceW[] = {' ', '\0'};
2520 char *path;
2522 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2523 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2524 ERR("Can't create Windows font reg key\n");
2525 goto end;
2528 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2529 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2530 ERR("Can't create Windows font reg key\n");
2531 goto end;
2534 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2535 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2536 ERR("Can't create external font reg key\n");
2537 goto end;
2540 /* enumerate the fonts and add external ones to the two keys */
2542 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2543 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2544 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2545 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2546 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2547 if(!face->external) continue;
2548 len = len_fam;
2549 if (!(face->ntmFlags & NTM_REGULAR))
2550 len = len_fam + strlenW(face->StyleName) + 1;
2551 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2552 strcpyW(valueW, family->FamilyName);
2553 if(len != len_fam) {
2554 strcatW(valueW, spaceW);
2555 strcatW(valueW, face->StyleName);
2557 strcatW(valueW, TrueType);
2559 file = wine_get_dos_file_name(face->file);
2560 if(file)
2561 len = strlenW(file) + 1;
2562 else
2564 if((path = strrchr(face->file, '/')) == NULL)
2565 path = face->file;
2566 else
2567 path++;
2568 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2570 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2571 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2573 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2574 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2575 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2577 HeapFree(GetProcessHeap(), 0, file);
2578 HeapFree(GetProcessHeap(), 0, valueW);
2581 end:
2582 if(external_key) RegCloseKey(external_key);
2583 if(win9x_key) RegCloseKey(win9x_key);
2584 if(winnt_key) RegCloseKey(winnt_key);
2585 return;
2588 static void delete_external_font_keys(void)
2590 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2591 DWORD dlen, vlen, datalen, valuelen, i, type;
2592 LPWSTR valueW;
2593 LPVOID data;
2595 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2596 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2597 ERR("Can't create Windows font reg key\n");
2598 goto end;
2601 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2602 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2603 ERR("Can't create Windows font reg key\n");
2604 goto end;
2607 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2608 ERR("Can't create external font reg key\n");
2609 goto end;
2612 /* Delete all external fonts added last time */
2614 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2615 &valuelen, &datalen, NULL, NULL);
2616 valuelen++; /* returned value doesn't include room for '\0' */
2617 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2618 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2620 dlen = datalen * sizeof(WCHAR);
2621 vlen = valuelen;
2622 i = 0;
2623 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2624 &dlen) == ERROR_SUCCESS) {
2626 RegDeleteValueW(winnt_key, valueW);
2627 RegDeleteValueW(win9x_key, valueW);
2628 /* reset dlen and vlen */
2629 dlen = datalen;
2630 vlen = valuelen;
2632 HeapFree(GetProcessHeap(), 0, data);
2633 HeapFree(GetProcessHeap(), 0, valueW);
2635 /* Delete the old external fonts key */
2636 RegCloseKey(external_key);
2637 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2639 end:
2640 if(win9x_key) RegCloseKey(win9x_key);
2641 if(winnt_key) RegCloseKey(winnt_key);
2644 /*************************************************************
2645 * WineEngAddFontResourceEx
2648 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2650 INT ret = 0;
2652 GDI_CheckNotLock();
2654 if (ft_handle) /* do it only if we have freetype up and running */
2656 char *unixname;
2658 if(flags)
2659 FIXME("Ignoring flags %x\n", flags);
2661 if((unixname = wine_get_unix_file_name(file)))
2663 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2665 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2666 EnterCriticalSection( &freetype_cs );
2667 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2668 LeaveCriticalSection( &freetype_cs );
2669 HeapFree(GetProcessHeap(), 0, unixname);
2671 if (!ret && !strchrW(file, '\\')) {
2672 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2673 ret = load_font_from_winfonts_dir(file);
2674 if (!ret) {
2675 /* Try in datadir/fonts (or builddir/fonts),
2676 * needed for Magic the Gathering Online
2678 ret = load_font_from_data_dir(file);
2682 return ret;
2685 /*************************************************************
2686 * WineEngAddFontMemResourceEx
2689 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2691 GDI_CheckNotLock();
2693 if (ft_handle) /* do it only if we have freetype up and running */
2695 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2697 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2698 memcpy(pFontCopy, pbFont, cbFont);
2700 EnterCriticalSection( &freetype_cs );
2701 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2702 LeaveCriticalSection( &freetype_cs );
2704 if (*pcFonts == 0)
2706 TRACE("AddFontToList failed\n");
2707 HeapFree(GetProcessHeap(), 0, pFontCopy);
2708 return 0;
2710 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2711 * For now return something unique but quite random
2713 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2714 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2717 *pcFonts = 0;
2718 return 0;
2721 /*************************************************************
2722 * WineEngRemoveFontResourceEx
2725 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2727 GDI_CheckNotLock();
2728 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2729 return TRUE;
2732 static const struct nls_update_font_list
2734 UINT ansi_cp, oem_cp;
2735 const char *oem, *fixed, *system;
2736 const char *courier, *serif, *small, *sserif;
2737 /* these are for font substitutes */
2738 const char *shelldlg, *tmsrmn;
2739 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2740 *helv_0, *tmsrmn_0;
2741 const struct subst
2743 const char *from, *to;
2744 } arial_0, courier_new_0, times_new_roman_0;
2745 } nls_update_font_list[] =
2747 /* Latin 1 (United States) */
2748 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2749 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2750 "Tahoma","Times New Roman",
2751 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2752 { 0 }, { 0 }, { 0 }
2754 /* Latin 1 (Multilingual) */
2755 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2756 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2757 "Tahoma","Times New Roman", /* FIXME unverified */
2758 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2759 { 0 }, { 0 }, { 0 }
2761 /* Eastern Europe */
2762 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2763 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2764 "Tahoma","Times New Roman", /* FIXME unverified */
2765 "Fixedsys,238", "System,238",
2766 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2767 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2768 { "Arial CE,0", "Arial,238" },
2769 { "Courier New CE,0", "Courier New,238" },
2770 { "Times New Roman CE,0", "Times New Roman,238" }
2772 /* Cyrillic */
2773 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2774 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2775 "Tahoma","Times New Roman", /* FIXME unverified */
2776 "Fixedsys,204", "System,204",
2777 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2778 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2779 { "Arial Cyr,0", "Arial,204" },
2780 { "Courier New Cyr,0", "Courier New,204" },
2781 { "Times New Roman Cyr,0", "Times New Roman,204" }
2783 /* Greek */
2784 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2785 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2786 "Tahoma","Times New Roman", /* FIXME unverified */
2787 "Fixedsys,161", "System,161",
2788 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2789 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2790 { "Arial Greek,0", "Arial,161" },
2791 { "Courier New Greek,0", "Courier New,161" },
2792 { "Times New Roman Greek,0", "Times New Roman,161" }
2794 /* Turkish */
2795 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2796 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2797 "Tahoma","Times New Roman", /* FIXME unverified */
2798 "Fixedsys,162", "System,162",
2799 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2800 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2801 { "Arial Tur,0", "Arial,162" },
2802 { "Courier New Tur,0", "Courier New,162" },
2803 { "Times New Roman Tur,0", "Times New Roman,162" }
2805 /* Hebrew */
2806 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2807 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2808 "Tahoma","Times New Roman", /* FIXME unverified */
2809 "Fixedsys,177", "System,177",
2810 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2811 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2812 { 0 }, { 0 }, { 0 }
2814 /* Arabic */
2815 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2816 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2817 "Tahoma","Times New Roman", /* FIXME unverified */
2818 "Fixedsys,178", "System,178",
2819 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2820 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2821 { 0 }, { 0 }, { 0 }
2823 /* Baltic */
2824 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2825 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2826 "Tahoma","Times New Roman", /* FIXME unverified */
2827 "Fixedsys,186", "System,186",
2828 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2829 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2830 { "Arial Baltic,0", "Arial,186" },
2831 { "Courier New Baltic,0", "Courier New,186" },
2832 { "Times New Roman Baltic,0", "Times New Roman,186" }
2834 /* Vietnamese */
2835 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2836 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2837 "Tahoma","Times New Roman", /* FIXME unverified */
2838 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2839 { 0 }, { 0 }, { 0 }
2841 /* Thai */
2842 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2843 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2844 "Tahoma","Times New Roman", /* FIXME unverified */
2845 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2846 { 0 }, { 0 }, { 0 }
2848 /* Japanese */
2849 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2850 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2851 "MS UI Gothic","MS Serif",
2852 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2853 { 0 }, { 0 }, { 0 }
2855 /* Chinese Simplified */
2856 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2857 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2858 "SimSun", "NSimSun",
2859 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2860 { 0 }, { 0 }, { 0 }
2862 /* Korean */
2863 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2864 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2865 "Gulim", "Batang",
2866 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2867 { 0 }, { 0 }, { 0 }
2869 /* Chinese Traditional */
2870 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2871 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2872 "PMingLiU", "MingLiU",
2873 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2874 { 0 }, { 0 }, { 0 }
2878 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2880 return ( ansi_cp == 932 /* CP932 for Japanese */
2881 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2882 || ansi_cp == 949 /* CP949 for Korean */
2883 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2886 static inline HKEY create_fonts_NT_registry_key(void)
2888 HKEY hkey = 0;
2890 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2891 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2892 return hkey;
2895 static inline HKEY create_fonts_9x_registry_key(void)
2897 HKEY hkey = 0;
2899 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2900 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2901 return hkey;
2904 static inline HKEY create_config_fonts_registry_key(void)
2906 HKEY hkey = 0;
2908 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2909 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2910 return hkey;
2913 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2915 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2916 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2917 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2918 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2921 static void set_value_key(HKEY hkey, const char *name, const char *value)
2923 if (value)
2924 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2925 else if (name)
2926 RegDeleteValueA(hkey, name);
2929 static void update_font_info(void)
2931 char buf[40], cpbuf[40];
2932 DWORD len, type;
2933 HKEY hkey = 0;
2934 UINT i, ansi_cp = 0, oem_cp = 0;
2935 BOOL done = FALSE;
2937 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2938 return;
2940 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2941 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2942 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2943 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2944 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2946 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2947 if (is_dbcs_ansi_cp(ansi_cp))
2948 use_default_fallback = TRUE;
2950 len = sizeof(buf);
2951 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2953 if (!strcmp( buf, cpbuf )) /* already set correctly */
2955 RegCloseKey(hkey);
2956 return;
2958 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2960 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2962 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2963 RegCloseKey(hkey);
2965 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2967 HKEY hkey;
2969 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2970 nls_update_font_list[i].oem_cp == oem_cp)
2972 hkey = create_config_fonts_registry_key();
2973 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2974 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2975 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2976 RegCloseKey(hkey);
2978 hkey = create_fonts_NT_registry_key();
2979 add_font_list(hkey, &nls_update_font_list[i]);
2980 RegCloseKey(hkey);
2982 hkey = create_fonts_9x_registry_key();
2983 add_font_list(hkey, &nls_update_font_list[i]);
2984 RegCloseKey(hkey);
2986 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2988 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2989 strlen(nls_update_font_list[i].shelldlg)+1);
2990 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2991 strlen(nls_update_font_list[i].tmsrmn)+1);
2993 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2994 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2995 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2996 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2997 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2998 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2999 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3000 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3002 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3003 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3004 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3006 RegCloseKey(hkey);
3008 done = TRUE;
3010 else
3012 /* Delete the FontSubstitutes from other locales */
3013 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3015 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3016 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3017 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3018 RegCloseKey(hkey);
3022 if (!done)
3023 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3026 static BOOL init_freetype(void)
3028 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3029 if(!ft_handle) {
3030 WINE_MESSAGE(
3031 "Wine cannot find the FreeType font library. To enable Wine to\n"
3032 "use TrueType fonts please install a version of FreeType greater than\n"
3033 "or equal to 2.0.5.\n"
3034 "http://www.freetype.org\n");
3035 return FALSE;
3038 #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;}
3040 LOAD_FUNCPTR(FT_Done_Face)
3041 LOAD_FUNCPTR(FT_Get_Char_Index)
3042 LOAD_FUNCPTR(FT_Get_First_Char)
3043 LOAD_FUNCPTR(FT_Get_Module)
3044 LOAD_FUNCPTR(FT_Get_Next_Char)
3045 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3046 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3047 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3048 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3049 LOAD_FUNCPTR(FT_Init_FreeType)
3050 LOAD_FUNCPTR(FT_Library_Version)
3051 LOAD_FUNCPTR(FT_Load_Glyph)
3052 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3053 LOAD_FUNCPTR(FT_Matrix_Multiply)
3054 #ifndef FT_MULFIX_INLINED
3055 LOAD_FUNCPTR(FT_MulFix)
3056 #endif
3057 LOAD_FUNCPTR(FT_New_Face)
3058 LOAD_FUNCPTR(FT_New_Memory_Face)
3059 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3060 LOAD_FUNCPTR(FT_Outline_Transform)
3061 LOAD_FUNCPTR(FT_Outline_Translate)
3062 LOAD_FUNCPTR(FT_Render_Glyph)
3063 LOAD_FUNCPTR(FT_Select_Charmap)
3064 LOAD_FUNCPTR(FT_Set_Charmap)
3065 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3066 LOAD_FUNCPTR(FT_Vector_Transform)
3067 LOAD_FUNCPTR(FT_Vector_Unit)
3068 #undef LOAD_FUNCPTR
3069 /* Don't warn if these ones are missing */
3070 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3071 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3072 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3073 #endif
3075 if(pFT_Init_FreeType(&library) != 0) {
3076 ERR("Can't init FreeType library\n");
3077 wine_dlclose(ft_handle, NULL, 0);
3078 ft_handle = NULL;
3079 return FALSE;
3081 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3083 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3084 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3085 ((FT_Version.minor << 8) & 0x00ff00) |
3086 ((FT_Version.patch ) & 0x0000ff);
3088 font_driver = &freetype_funcs;
3089 return TRUE;
3091 sym_not_found:
3092 WINE_MESSAGE(
3093 "Wine cannot find certain functions that it needs inside the FreeType\n"
3094 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3095 "FreeType to at least version 2.1.4.\n"
3096 "http://www.freetype.org\n");
3097 wine_dlclose(ft_handle, NULL, 0);
3098 ft_handle = NULL;
3099 return FALSE;
3102 static void init_font_list(void)
3104 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3105 static const WCHAR pathW[] = {'P','a','t','h',0};
3106 HKEY hkey;
3107 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3108 WCHAR windowsdir[MAX_PATH];
3109 char *unixname;
3110 const char *home;
3111 const char *data_dir;
3113 delete_external_font_keys();
3115 /* load the system bitmap fonts */
3116 load_system_fonts();
3118 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3119 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3120 strcatW(windowsdir, fontsW);
3121 if((unixname = wine_get_unix_file_name(windowsdir)))
3123 ReadFontDir(unixname, FALSE);
3124 HeapFree(GetProcessHeap(), 0, unixname);
3127 /* load the system truetype fonts */
3128 data_dir = wine_get_data_dir();
3129 if (!data_dir) data_dir = wine_get_build_dir();
3130 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3132 strcpy(unixname, data_dir);
3133 strcat(unixname, "/fonts/");
3134 ReadFontDir(unixname, TRUE);
3135 HeapFree(GetProcessHeap(), 0, unixname);
3138 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3139 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3140 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3141 will skip these. */
3142 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3143 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3144 &hkey) == ERROR_SUCCESS)
3146 LPWSTR data, valueW;
3147 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3148 &valuelen, &datalen, NULL, NULL);
3150 valuelen++; /* returned value doesn't include room for '\0' */
3151 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3152 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3153 if (valueW && data)
3155 dlen = datalen * sizeof(WCHAR);
3156 vlen = valuelen;
3157 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3158 &dlen) == ERROR_SUCCESS)
3160 if(data[0] && (data[1] == ':'))
3162 if((unixname = wine_get_unix_file_name(data)))
3164 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3165 HeapFree(GetProcessHeap(), 0, unixname);
3168 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3170 WCHAR pathW[MAX_PATH];
3171 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3172 BOOL added = FALSE;
3174 sprintfW(pathW, fmtW, windowsdir, data);
3175 if((unixname = wine_get_unix_file_name(pathW)))
3177 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3178 HeapFree(GetProcessHeap(), 0, unixname);
3180 if (!added)
3181 load_font_from_data_dir(data);
3183 /* reset dlen and vlen */
3184 dlen = datalen;
3185 vlen = valuelen;
3188 HeapFree(GetProcessHeap(), 0, data);
3189 HeapFree(GetProcessHeap(), 0, valueW);
3190 RegCloseKey(hkey);
3193 load_fontconfig_fonts();
3195 /* then look in any directories that we've specified in the config file */
3196 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3197 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3199 DWORD len;
3200 LPWSTR valueW;
3201 LPSTR valueA, ptr;
3203 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3205 len += sizeof(WCHAR);
3206 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3207 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3209 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3210 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3211 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3212 TRACE( "got font path %s\n", debugstr_a(valueA) );
3213 ptr = valueA;
3214 while (ptr)
3216 LPSTR next = strchr( ptr, ':' );
3217 if (next) *next++ = 0;
3218 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3219 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3221 strcpy( unixname, home );
3222 strcat( unixname, ptr + 1 );
3223 ReadFontDir( unixname, TRUE );
3224 HeapFree( GetProcessHeap(), 0, unixname );
3226 else
3227 ReadFontDir( ptr, TRUE );
3228 ptr = next;
3230 HeapFree( GetProcessHeap(), 0, valueA );
3232 HeapFree( GetProcessHeap(), 0, valueW );
3234 RegCloseKey(hkey);
3237 #ifdef __APPLE__
3238 /* Mac default font locations. */
3239 ReadFontDir( "/Library/Fonts", TRUE );
3240 ReadFontDir( "/Network/Library/Fonts", TRUE );
3241 ReadFontDir( "/System/Library/Fonts", TRUE );
3242 if ((home = getenv( "HOME" )))
3244 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3245 strcpy( unixname, home );
3246 strcat( unixname, "/Library/Fonts" );
3247 ReadFontDir( unixname, TRUE);
3248 HeapFree( GetProcessHeap(), 0, unixname );
3250 #endif
3253 static BOOL move_to_front(const WCHAR *name)
3255 Family *family, *cursor2;
3256 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3258 if(!strcmpiW(family->FamilyName, name))
3260 list_remove(&family->entry);
3261 list_add_head(&font_list, &family->entry);
3262 return TRUE;
3265 return FALSE;
3268 static BOOL set_default(const WCHAR **name_list)
3270 while (*name_list)
3272 if (move_to_front(*name_list)) return TRUE;
3273 name_list++;
3276 return FALSE;
3279 static void reorder_font_list(void)
3281 set_default( default_serif_list );
3282 set_default( default_fixed_list );
3283 set_default( default_sans_list );
3286 /*************************************************************
3287 * WineEngInit
3289 * Initialize FreeType library and create a list of available faces
3291 BOOL WineEngInit(void)
3293 HKEY hkey_font_cache;
3294 DWORD disposition;
3295 HANDLE font_mutex;
3297 /* update locale dependent font info in registry */
3298 update_font_info();
3300 if(!init_freetype()) return FALSE;
3302 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3304 ERR("Failed to create font mutex\n");
3305 return FALSE;
3307 WaitForSingleObject(font_mutex, INFINITE);
3309 create_font_cache_key(&hkey_font_cache, &disposition);
3311 if(disposition == REG_CREATED_NEW_KEY)
3312 init_font_list();
3313 else
3314 load_font_list_from_cache(hkey_font_cache);
3316 RegCloseKey(hkey_font_cache);
3318 reorder_font_list();
3320 DumpFontList();
3321 LoadSubstList();
3322 DumpSubstList();
3323 LoadReplaceList();
3325 if(disposition == REG_CREATED_NEW_KEY)
3326 update_reg_entries();
3328 init_system_links();
3330 ReleaseMutex(font_mutex);
3331 return TRUE;
3335 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3337 TT_OS2 *pOS2;
3338 TT_HoriHeader *pHori;
3340 LONG ppem;
3342 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3343 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3345 if(height == 0) height = 16;
3347 /* Calc. height of EM square:
3349 * For +ve lfHeight we have
3350 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3351 * Re-arranging gives:
3352 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3354 * For -ve lfHeight we have
3355 * |lfHeight| = ppem
3356 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3357 * with il = winAscent + winDescent - units_per_em]
3361 if(height > 0) {
3362 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3363 ppem = MulDiv(ft_face->units_per_EM, height,
3364 pHori->Ascender - pHori->Descender);
3365 else
3366 ppem = MulDiv(ft_face->units_per_EM, height,
3367 pOS2->usWinAscent + pOS2->usWinDescent);
3369 else
3370 ppem = -height;
3372 return ppem;
3375 static struct font_mapping *map_font_file( const char *name )
3377 struct font_mapping *mapping;
3378 struct stat st;
3379 int fd;
3381 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3382 if (fstat( fd, &st ) == -1) goto error;
3384 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3386 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3388 mapping->refcount++;
3389 close( fd );
3390 return mapping;
3393 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3394 goto error;
3396 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3397 close( fd );
3399 if (mapping->data == MAP_FAILED)
3401 HeapFree( GetProcessHeap(), 0, mapping );
3402 return NULL;
3404 mapping->refcount = 1;
3405 mapping->dev = st.st_dev;
3406 mapping->ino = st.st_ino;
3407 mapping->size = st.st_size;
3408 list_add_tail( &mappings_list, &mapping->entry );
3409 return mapping;
3411 error:
3412 close( fd );
3413 return NULL;
3416 static void unmap_font_file( struct font_mapping *mapping )
3418 if (!--mapping->refcount)
3420 list_remove( &mapping->entry );
3421 munmap( mapping->data, mapping->size );
3422 HeapFree( GetProcessHeap(), 0, mapping );
3426 static LONG load_VDMX(GdiFont*, LONG);
3428 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3430 FT_Error err;
3431 FT_Face ft_face;
3432 void *data_ptr;
3433 DWORD data_size;
3435 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3437 if (face->file)
3439 if (!(font->mapping = map_font_file( face->file )))
3441 WARN("failed to map %s\n", debugstr_a(face->file));
3442 return 0;
3444 data_ptr = font->mapping->data;
3445 data_size = font->mapping->size;
3447 else
3449 data_ptr = face->font_data_ptr;
3450 data_size = face->font_data_size;
3453 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3454 if(err) {
3455 ERR("FT_New_Face rets %d\n", err);
3456 return 0;
3459 /* set it here, as load_VDMX needs it */
3460 font->ft_face = ft_face;
3462 if(FT_IS_SCALABLE(ft_face)) {
3463 /* load the VDMX table if we have one */
3464 font->ppem = load_VDMX(font, height);
3465 if(font->ppem == 0)
3466 font->ppem = calc_ppem_for_height(ft_face, height);
3467 TRACE("height %d => ppem %d\n", height, font->ppem);
3469 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3470 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3471 } else {
3472 font->ppem = height;
3473 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3474 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3476 return ft_face;
3480 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3482 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3483 a single face with the requested charset. The idea is to check if
3484 the selected font supports the current ANSI codepage, if it does
3485 return the corresponding charset, else return the first charset */
3487 CHARSETINFO csi;
3488 int acp = GetACP(), i;
3489 DWORD fs0;
3491 *cp = acp;
3492 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3494 const SYSTEM_LINKS *font_link;
3496 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3497 return csi.ciCharset;
3499 font_link = find_font_link(family_name);
3500 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3501 return csi.ciCharset;
3504 for(i = 0; i < 32; i++) {
3505 fs0 = 1L << i;
3506 if(face->fs.fsCsb[0] & fs0) {
3507 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3508 *cp = csi.ciACP;
3509 return csi.ciCharset;
3511 else
3512 FIXME("TCI failing on %x\n", fs0);
3516 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3517 face->fs.fsCsb[0], face->file);
3518 *cp = acp;
3519 return DEFAULT_CHARSET;
3522 static GdiFont *alloc_font(void)
3524 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3525 ret->gmsize = 1;
3526 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3527 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3528 ret->potm = NULL;
3529 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3530 ret->total_kern_pairs = (DWORD)-1;
3531 ret->kern_pairs = NULL;
3532 list_init(&ret->hfontlist);
3533 list_init(&ret->child_fonts);
3534 return ret;
3537 static void free_font(GdiFont *font)
3539 struct list *cursor, *cursor2;
3540 DWORD i;
3542 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3544 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3545 list_remove(cursor);
3546 if(child->font)
3547 free_font(child->font);
3548 HeapFree(GetProcessHeap(), 0, child);
3551 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3553 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3554 DeleteObject(hfontlist->hfont);
3555 list_remove(&hfontlist->entry);
3556 HeapFree(GetProcessHeap(), 0, hfontlist);
3559 if (font->ft_face) pFT_Done_Face(font->ft_face);
3560 if (font->mapping) unmap_font_file( font->mapping );
3561 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3562 HeapFree(GetProcessHeap(), 0, font->potm);
3563 HeapFree(GetProcessHeap(), 0, font->name);
3564 for (i = 0; i < font->gmsize; i++)
3565 HeapFree(GetProcessHeap(),0,font->gm[i]);
3566 HeapFree(GetProcessHeap(), 0, font->gm);
3567 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3568 HeapFree(GetProcessHeap(), 0, font);
3572 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3574 FT_Face ft_face = font->ft_face;
3575 FT_ULong len;
3576 FT_Error err;
3578 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3580 if(!buf)
3581 len = 0;
3582 else
3583 len = cbData;
3585 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3587 /* make sure value of len is the value freetype says it needs */
3588 if (buf && len)
3590 FT_ULong needed = 0;
3591 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3592 if( !err && needed < len) len = needed;
3594 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3595 if (err)
3597 TRACE("Can't find table %c%c%c%c\n",
3598 /* bytes were reversed */
3599 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3600 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3601 return GDI_ERROR;
3603 return len;
3606 /*************************************************************
3607 * load_VDMX
3609 * load the vdmx entry for the specified height
3612 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3613 ( ( (FT_ULong)_x4 << 24 ) | \
3614 ( (FT_ULong)_x3 << 16 ) | \
3615 ( (FT_ULong)_x2 << 8 ) | \
3616 (FT_ULong)_x1 )
3618 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3620 typedef struct {
3621 BYTE bCharSet;
3622 BYTE xRatio;
3623 BYTE yStartRatio;
3624 BYTE yEndRatio;
3625 } Ratios;
3627 typedef struct {
3628 WORD recs;
3629 BYTE startsz;
3630 BYTE endsz;
3631 } VDMX_group;
3633 static LONG load_VDMX(GdiFont *font, LONG height)
3635 WORD hdr[3], tmp;
3636 VDMX_group group;
3637 BYTE devXRatio, devYRatio;
3638 USHORT numRecs, numRatios;
3639 DWORD result, offset = -1;
3640 LONG ppem = 0;
3641 int i;
3643 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3645 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3646 return ppem;
3648 /* FIXME: need the real device aspect ratio */
3649 devXRatio = 1;
3650 devYRatio = 1;
3652 numRecs = GET_BE_WORD(hdr[1]);
3653 numRatios = GET_BE_WORD(hdr[2]);
3655 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3656 for(i = 0; i < numRatios; i++) {
3657 Ratios ratio;
3659 offset = (3 * 2) + (i * sizeof(Ratios));
3660 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3661 offset = -1;
3663 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3665 if((ratio.xRatio == 0 &&
3666 ratio.yStartRatio == 0 &&
3667 ratio.yEndRatio == 0) ||
3668 (devXRatio == ratio.xRatio &&
3669 devYRatio >= ratio.yStartRatio &&
3670 devYRatio <= ratio.yEndRatio))
3672 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3673 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3674 offset = GET_BE_WORD(tmp);
3675 break;
3679 if(offset == -1) {
3680 FIXME("No suitable ratio found\n");
3681 return ppem;
3684 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3685 USHORT recs;
3686 BYTE startsz, endsz;
3687 WORD *vTable;
3689 recs = GET_BE_WORD(group.recs);
3690 startsz = group.startsz;
3691 endsz = group.endsz;
3693 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3695 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3696 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3697 if(result == GDI_ERROR) {
3698 FIXME("Failed to retrieve vTable\n");
3699 goto end;
3702 if(height > 0) {
3703 for(i = 0; i < recs; i++) {
3704 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3705 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3706 ppem = GET_BE_WORD(vTable[i * 3]);
3708 if(yMax + -yMin == height) {
3709 font->yMax = yMax;
3710 font->yMin = yMin;
3711 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3712 break;
3714 if(yMax + -yMin > height) {
3715 if(--i < 0) {
3716 ppem = 0;
3717 goto end; /* failed */
3719 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3720 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3721 ppem = GET_BE_WORD(vTable[i * 3]);
3722 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3723 break;
3726 if(!font->yMax) {
3727 ppem = 0;
3728 TRACE("ppem not found for height %d\n", height);
3731 end:
3732 HeapFree(GetProcessHeap(), 0, vTable);
3735 return ppem;
3738 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3740 if(font->font_desc.hash != fd->hash) return TRUE;
3741 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3742 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3743 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3744 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3747 static void calc_hash(FONT_DESC *pfd)
3749 DWORD hash = 0, *ptr, two_chars;
3750 WORD *pwc;
3751 unsigned int i;
3753 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3754 hash ^= *ptr;
3755 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3756 hash ^= *ptr;
3757 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3758 two_chars = *ptr;
3759 pwc = (WCHAR *)&two_chars;
3760 if(!*pwc) break;
3761 *pwc = toupperW(*pwc);
3762 pwc++;
3763 *pwc = toupperW(*pwc);
3764 hash ^= two_chars;
3765 if(!*pwc) break;
3767 hash ^= !pfd->can_use_bitmap;
3768 pfd->hash = hash;
3769 return;
3772 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3774 GdiFont *ret;
3775 FONT_DESC fd;
3776 HFONTLIST *hflist;
3777 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3779 fd.lf = *plf;
3780 fd.matrix = *pmat;
3781 fd.can_use_bitmap = can_use_bitmap;
3782 calc_hash(&fd);
3784 /* try the child list */
3785 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3786 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3787 if(!fontcmp(ret, &fd)) {
3788 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3789 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3790 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3791 if(hflist->hfont == hfont)
3792 return ret;
3797 /* try the in-use list */
3798 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3799 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3800 if(!fontcmp(ret, &fd)) {
3801 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3802 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3803 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3804 if(hflist->hfont == hfont)
3805 return ret;
3807 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3808 hflist->hfont = hfont;
3809 list_add_head(&ret->hfontlist, &hflist->entry);
3810 return ret;
3814 /* then the unused list */
3815 font_elem_ptr = list_head(&unused_gdi_font_list);
3816 while(font_elem_ptr) {
3817 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3818 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3819 if(!fontcmp(ret, &fd)) {
3820 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3821 assert(list_empty(&ret->hfontlist));
3822 TRACE("Found %p in unused list\n", ret);
3823 list_remove(&ret->entry);
3824 list_add_head(&gdi_font_list, &ret->entry);
3825 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3826 hflist->hfont = hfont;
3827 list_add_head(&ret->hfontlist, &hflist->entry);
3828 return ret;
3831 return NULL;
3834 static void add_to_cache(GdiFont *font)
3836 static DWORD cache_num = 1;
3838 font->cache_num = cache_num++;
3839 list_add_head(&gdi_font_list, &font->entry);
3842 /*************************************************************
3843 * create_child_font_list
3845 static BOOL create_child_font_list(GdiFont *font)
3847 BOOL ret = FALSE;
3848 SYSTEM_LINKS *font_link;
3849 CHILD_FONT *font_link_entry, *new_child;
3850 FontSubst *psub;
3851 WCHAR* font_name;
3853 psub = get_font_subst(&font_subst_list, font->name, -1);
3854 font_name = psub ? psub->to.name : font->name;
3855 font_link = find_font_link(font_name);
3856 if (font_link != NULL)
3858 TRACE("found entry in system list\n");
3859 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3861 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3862 new_child->face = font_link_entry->face;
3863 new_child->font = NULL;
3864 list_add_tail(&font->child_fonts, &new_child->entry);
3865 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3867 ret = TRUE;
3870 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3871 * Sans Serif. This is how asian windows get default fallbacks for fonts
3873 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3874 font->charset != OEM_CHARSET &&
3875 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3877 font_link = find_font_link(szDefaultFallbackLink);
3878 if (font_link != NULL)
3880 TRACE("found entry in default fallback list\n");
3881 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3883 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3884 new_child->face = font_link_entry->face;
3885 new_child->font = NULL;
3886 list_add_tail(&font->child_fonts, &new_child->entry);
3887 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3889 ret = TRUE;
3893 return ret;
3896 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3898 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3900 if (pFT_Set_Charmap)
3902 FT_Int i;
3903 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3905 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3907 for (i = 0; i < ft_face->num_charmaps; i++)
3909 if (ft_face->charmaps[i]->encoding == encoding)
3911 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3912 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3914 switch (ft_face->charmaps[i]->platform_id)
3916 default:
3917 cmap_def = ft_face->charmaps[i];
3918 break;
3919 case 0: /* Apple Unicode */
3920 cmap0 = ft_face->charmaps[i];
3921 break;
3922 case 1: /* Macintosh */
3923 cmap1 = ft_face->charmaps[i];
3924 break;
3925 case 2: /* ISO */
3926 cmap2 = ft_face->charmaps[i];
3927 break;
3928 case 3: /* Microsoft */
3929 cmap3 = ft_face->charmaps[i];
3930 break;
3934 if (cmap3) /* prefer Microsoft cmap table */
3935 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3936 else if (cmap1)
3937 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3938 else if (cmap2)
3939 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3940 else if (cmap0)
3941 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3942 else if (cmap_def)
3943 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3945 return ft_err == FT_Err_Ok;
3948 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3952 /*************************************************************
3953 * freetype_CreateDC
3955 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3956 LPCWSTR output, const DEVMODEW *devmode )
3958 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3960 if (!physdev) return FALSE;
3961 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3962 return TRUE;
3966 /*************************************************************
3967 * freetype_DeleteDC
3969 static BOOL freetype_DeleteDC( PHYSDEV dev )
3971 struct freetype_physdev *physdev = get_freetype_dev( dev );
3972 HeapFree( GetProcessHeap(), 0, physdev );
3973 return TRUE;
3977 /*************************************************************
3978 * freetype_SelectFont
3980 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3982 struct freetype_physdev *physdev = get_freetype_dev( dev );
3983 GdiFont *ret;
3984 Face *face, *best, *best_bitmap;
3985 Family *family, *last_resort_family;
3986 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
3987 INT height, width = 0;
3988 unsigned int score = 0, new_score;
3989 signed int diff = 0, newdiff;
3990 BOOL bd, it, can_use_bitmap, want_vertical;
3991 LOGFONTW lf;
3992 CHARSETINFO csi;
3993 HFONTLIST *hflist;
3994 FMAT2 dcmat;
3995 FontSubst *psub = NULL;
3996 DC *dc = get_dc_ptr( dev->hdc );
3997 const SYSTEM_LINKS *font_link;
3999 if (!hfont) /* notification that the font has been changed by another driver */
4001 dc->gdiFont = NULL;
4002 physdev->font = NULL;
4003 release_dc_ptr( dc );
4004 return 0;
4007 GetObjectW( hfont, sizeof(lf), &lf );
4008 lf.lfWidth = abs(lf.lfWidth);
4010 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4012 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4013 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4014 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4015 lf.lfEscapement);
4017 if(dc->GraphicsMode == GM_ADVANCED)
4019 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4020 /* Try to avoid not necessary glyph transformations */
4021 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4023 lf.lfHeight *= fabs(dcmat.eM11);
4024 lf.lfWidth *= fabs(dcmat.eM11);
4025 dcmat.eM11 = dcmat.eM22 = 1.0;
4028 else
4030 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4031 font scaling abilities. */
4032 dcmat.eM11 = dcmat.eM22 = 1.0;
4033 dcmat.eM21 = dcmat.eM12 = 0;
4034 if (dc->vport2WorldValid)
4036 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4037 lf.lfOrientation = -lf.lfOrientation;
4038 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4039 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4043 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4044 dcmat.eM21, dcmat.eM22);
4046 GDI_CheckNotLock();
4047 EnterCriticalSection( &freetype_cs );
4049 /* check the cache first */
4050 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4051 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4052 goto done;
4055 if(list_empty(&font_list)) /* No fonts installed */
4057 TRACE("No fonts installed\n");
4058 goto done;
4061 TRACE("not in cache\n");
4062 ret = alloc_font();
4064 ret->font_desc.matrix = dcmat;
4065 ret->font_desc.lf = lf;
4066 ret->font_desc.can_use_bitmap = can_use_bitmap;
4067 calc_hash(&ret->font_desc);
4068 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4069 hflist->hfont = hfont;
4070 list_add_head(&ret->hfontlist, &hflist->entry);
4072 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4073 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4074 original value lfCharSet. Note this is a special case for
4075 Symbol and doesn't happen at least for "Wingdings*" */
4077 if(!strcmpiW(lf.lfFaceName, SymbolW))
4078 lf.lfCharSet = SYMBOL_CHARSET;
4080 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4081 switch(lf.lfCharSet) {
4082 case DEFAULT_CHARSET:
4083 csi.fs.fsCsb[0] = 0;
4084 break;
4085 default:
4086 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4087 csi.fs.fsCsb[0] = 0;
4088 break;
4092 family = NULL;
4093 if(lf.lfFaceName[0] != '\0') {
4094 CHILD_FONT *font_link_entry;
4095 LPWSTR FaceName = lf.lfFaceName;
4097 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4099 if(psub) {
4100 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4101 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4102 if (psub->to.charset != -1)
4103 lf.lfCharSet = psub->to.charset;
4106 /* We want a match on name and charset or just name if
4107 charset was DEFAULT_CHARSET. If the latter then
4108 we fixup the returned charset later in get_nearest_charset
4109 where we'll either use the charset of the current ansi codepage
4110 or if that's unavailable the first charset that the font supports.
4112 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4113 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4114 if (!strcmpiW(family->FamilyName, FaceName) ||
4115 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4117 font_link = find_font_link(family->FamilyName);
4118 face_list = get_face_list_from_family(family);
4119 LIST_FOR_EACH(face_elem_ptr, face_list) {
4120 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4121 if (!(face->scalable || can_use_bitmap))
4122 continue;
4123 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4124 goto found;
4125 if (font_link != NULL &&
4126 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4127 goto found;
4128 if (!csi.fs.fsCsb[0])
4129 goto found;
4134 /* Search by full face name. */
4135 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4136 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4137 face_list = get_face_list_from_family(family);
4138 LIST_FOR_EACH(face_elem_ptr, face_list) {
4139 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4140 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4141 (face->scalable || can_use_bitmap))
4143 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4144 goto found_face;
4145 font_link = find_font_link(family->FamilyName);
4146 if (font_link != NULL &&
4147 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4148 goto found_face;
4154 * Try check the SystemLink list first for a replacement font.
4155 * We may find good replacements there.
4157 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4159 if(!strcmpiW(font_link->font_name, FaceName) ||
4160 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4162 TRACE("found entry in system list\n");
4163 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4165 const SYSTEM_LINKS *links;
4167 face = font_link_entry->face;
4168 if (!(face->scalable || can_use_bitmap))
4169 continue;
4170 family = face->family;
4171 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4172 goto found;
4173 links = find_font_link(family->FamilyName);
4174 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4175 goto found;
4181 psub = NULL; /* substitution is no more relevant */
4183 /* If requested charset was DEFAULT_CHARSET then try using charset
4184 corresponding to the current ansi codepage */
4185 if (!csi.fs.fsCsb[0])
4187 INT acp = GetACP();
4188 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4189 FIXME("TCI failed on codepage %d\n", acp);
4190 csi.fs.fsCsb[0] = 0;
4191 } else
4192 lf.lfCharSet = csi.ciCharset;
4195 want_vertical = (lf.lfFaceName[0] == '@');
4197 /* Face families are in the top 4 bits of lfPitchAndFamily,
4198 so mask with 0xF0 before testing */
4200 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4201 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4202 strcpyW(lf.lfFaceName, defFixed);
4203 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4204 strcpyW(lf.lfFaceName, defSerif);
4205 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4206 strcpyW(lf.lfFaceName, defSans);
4207 else
4208 strcpyW(lf.lfFaceName, defSans);
4209 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4210 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4211 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4212 font_link = find_font_link(family->FamilyName);
4213 face_list = get_face_list_from_family(family);
4214 LIST_FOR_EACH(face_elem_ptr, face_list) {
4215 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4216 if (!(face->scalable || can_use_bitmap))
4217 continue;
4218 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4219 goto found;
4220 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4221 goto found;
4226 last_resort_family = NULL;
4227 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4228 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4229 font_link = find_font_link(family->FamilyName);
4230 face_list = get_face_list_from_family(family);
4231 LIST_FOR_EACH(face_elem_ptr, face_list) {
4232 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4233 if(face->vertical == want_vertical &&
4234 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4235 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4236 if(face->scalable)
4237 goto found;
4238 if(can_use_bitmap && !last_resort_family)
4239 last_resort_family = family;
4244 if(last_resort_family) {
4245 family = last_resort_family;
4246 csi.fs.fsCsb[0] = 0;
4247 goto found;
4250 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4251 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4252 face_list = get_face_list_from_family(family);
4253 LIST_FOR_EACH(face_elem_ptr, face_list) {
4254 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4255 if(face->scalable && face->vertical == want_vertical) {
4256 csi.fs.fsCsb[0] = 0;
4257 WARN("just using first face for now\n");
4258 goto found;
4260 if(can_use_bitmap && !last_resort_family)
4261 last_resort_family = family;
4264 if(!last_resort_family) {
4265 FIXME("can't find a single appropriate font - bailing\n");
4266 free_font(ret);
4267 ret = NULL;
4268 goto done;
4271 WARN("could only find a bitmap font - this will probably look awful!\n");
4272 family = last_resort_family;
4273 csi.fs.fsCsb[0] = 0;
4275 found:
4276 it = lf.lfItalic ? 1 : 0;
4277 bd = lf.lfWeight > 550 ? 1 : 0;
4279 height = lf.lfHeight;
4281 face = best = best_bitmap = NULL;
4282 font_link = find_font_link(family->FamilyName);
4283 face_list = get_face_list_from_family(family);
4284 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4286 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4287 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4288 !csi.fs.fsCsb[0])
4290 BOOL italic, bold;
4292 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4293 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4294 new_score = (italic ^ it) + (bold ^ bd);
4295 if(!best || new_score <= score)
4297 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4298 italic, bold, it, bd);
4299 score = new_score;
4300 best = face;
4301 if(best->scalable && score == 0) break;
4302 if(!best->scalable)
4304 if(height > 0)
4305 newdiff = height - (signed int)(best->size.height);
4306 else
4307 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4308 if(!best_bitmap || new_score < score ||
4309 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4311 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4312 diff = newdiff;
4313 best_bitmap = best;
4314 if(score == 0 && diff == 0) break;
4320 if(best)
4321 face = best->scalable ? best : best_bitmap;
4322 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4323 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4325 found_face:
4326 height = lf.lfHeight;
4328 ret->fs = face->fs;
4330 if(csi.fs.fsCsb[0]) {
4331 ret->charset = lf.lfCharSet;
4332 ret->codepage = csi.ciACP;
4334 else
4335 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4337 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4338 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4340 ret->aveWidth = height ? lf.lfWidth : 0;
4342 if(!face->scalable) {
4343 /* Windows uses integer scaling factors for bitmap fonts */
4344 INT scale, scaled_height;
4345 GdiFont *cachedfont;
4347 /* FIXME: rotation of bitmap fonts is ignored */
4348 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4349 if (ret->aveWidth)
4350 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4351 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4352 dcmat.eM11 = dcmat.eM22 = 1.0;
4353 /* As we changed the matrix, we need to search the cache for the font again,
4354 * otherwise we might explode the cache. */
4355 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4356 TRACE("Found cached font after non-scalable matrix rescale!\n");
4357 free_font( ret );
4358 ret = cachedfont;
4359 goto done;
4361 calc_hash(&ret->font_desc);
4363 if (height != 0) height = diff;
4364 height += face->size.height;
4366 scale = (height + face->size.height - 1) / face->size.height;
4367 scaled_height = scale * face->size.height;
4368 /* Only jump to the next height if the difference <= 25% original height */
4369 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4370 /* The jump between unscaled and doubled is delayed by 1 */
4371 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4372 ret->scale_y = scale;
4374 width = face->size.x_ppem >> 6;
4375 height = face->size.y_ppem >> 6;
4377 else
4378 ret->scale_y = 1.0;
4379 TRACE("font scale y: %f\n", ret->scale_y);
4381 ret->ft_face = OpenFontFace(ret, face, width, height);
4383 if (!ret->ft_face)
4385 free_font( ret );
4386 ret = NULL;
4387 goto done;
4390 ret->ntmFlags = face->ntmFlags;
4392 if (ret->charset == SYMBOL_CHARSET &&
4393 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4394 /* No ops */
4396 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4397 /* No ops */
4399 else {
4400 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4403 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4404 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4405 ret->underline = lf.lfUnderline ? 0xff : 0;
4406 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4407 create_child_font_list(ret);
4409 if (face->vertical) /* We need to try to load the GSUB table */
4411 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4412 if (length != GDI_ERROR)
4414 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4415 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4416 TRACE("Loaded GSUB table of %i bytes\n",length);
4420 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4422 add_to_cache(ret);
4423 done:
4424 if (ret)
4426 dc->gdiFont = ret;
4427 physdev->font = ret;
4429 LeaveCriticalSection( &freetype_cs );
4430 release_dc_ptr( dc );
4431 return ret ? hfont : 0;
4434 static void dump_gdi_font_list(void)
4436 GdiFont *gdiFont;
4437 struct list *elem_ptr;
4439 TRACE("---------- gdiFont Cache ----------\n");
4440 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4441 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4442 TRACE("gdiFont=%p %s %d\n",
4443 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4446 TRACE("---------- Unused gdiFont Cache ----------\n");
4447 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4448 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4449 TRACE("gdiFont=%p %s %d\n",
4450 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4453 TRACE("---------- Child gdiFont Cache ----------\n");
4454 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4455 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4456 TRACE("gdiFont=%p %s %d\n",
4457 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4461 /*************************************************************
4462 * WineEngDestroyFontInstance
4464 * free the gdiFont associated with this handle
4467 BOOL WineEngDestroyFontInstance(HFONT handle)
4469 GdiFont *gdiFont;
4470 HFONTLIST *hflist;
4471 BOOL ret = FALSE;
4472 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4473 int i = 0;
4475 GDI_CheckNotLock();
4476 EnterCriticalSection( &freetype_cs );
4478 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4480 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4481 while(hfontlist_elem_ptr) {
4482 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4483 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4484 if(hflist->hfont == handle) {
4485 TRACE("removing child font %p from child list\n", gdiFont);
4486 list_remove(&gdiFont->entry);
4487 LeaveCriticalSection( &freetype_cs );
4488 return TRUE;
4493 TRACE("destroying hfont=%p\n", handle);
4494 if(TRACE_ON(font))
4495 dump_gdi_font_list();
4497 font_elem_ptr = list_head(&gdi_font_list);
4498 while(font_elem_ptr) {
4499 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4500 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4502 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4503 while(hfontlist_elem_ptr) {
4504 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4505 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4506 if(hflist->hfont == handle) {
4507 list_remove(&hflist->entry);
4508 HeapFree(GetProcessHeap(), 0, hflist);
4509 ret = TRUE;
4512 if(list_empty(&gdiFont->hfontlist)) {
4513 TRACE("Moving to Unused list\n");
4514 list_remove(&gdiFont->entry);
4515 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4520 font_elem_ptr = list_head(&unused_gdi_font_list);
4521 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4522 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4523 while(font_elem_ptr) {
4524 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4525 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4526 TRACE("freeing %p\n", gdiFont);
4527 list_remove(&gdiFont->entry);
4528 free_font(gdiFont);
4530 LeaveCriticalSection( &freetype_cs );
4531 return ret;
4534 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4536 HRSRC rsrc;
4537 HGLOBAL hMem;
4538 WCHAR *p;
4539 int i;
4541 id += IDS_FIRST_SCRIPT;
4542 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4543 if (!rsrc) return 0;
4544 hMem = LoadResource( gdi32_module, rsrc );
4545 if (!hMem) return 0;
4547 p = LockResource( hMem );
4548 id &= 0x000f;
4549 while (id--) p += *p + 1;
4551 i = min(LF_FACESIZE - 1, *p);
4552 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4553 buffer[i] = 0;
4554 return i;
4558 /***************************************************
4559 * create_enum_charset_list
4561 * This function creates charset enumeration list because in DEFAULT_CHARSET
4562 * case, the ANSI codepage's charset takes precedence over other charsets.
4563 * This function works as a filter other than DEFAULT_CHARSET case.
4565 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4567 CHARSETINFO csi;
4568 DWORD n = 0;
4570 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4571 csi.fs.fsCsb[0] != 0) {
4572 list->element[n].mask = csi.fs.fsCsb[0];
4573 list->element[n].charset = csi.ciCharset;
4574 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4575 n++;
4577 else { /* charset is DEFAULT_CHARSET or invalid. */
4578 INT acp, i;
4580 /* Set the current codepage's charset as the first element. */
4581 acp = GetACP();
4582 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4583 csi.fs.fsCsb[0] != 0) {
4584 list->element[n].mask = csi.fs.fsCsb[0];
4585 list->element[n].charset = csi.ciCharset;
4586 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4587 n++;
4590 /* Fill out left elements. */
4591 for (i = 0; i < 32; i++) {
4592 FONTSIGNATURE fs;
4593 fs.fsCsb[0] = 1L << i;
4594 fs.fsCsb[1] = 0;
4595 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4596 continue; /* skip, already added. */
4597 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4598 continue; /* skip, this is an invalid fsCsb bit. */
4600 list->element[n].mask = fs.fsCsb[0];
4601 list->element[n].charset = csi.ciCharset;
4602 load_script_name( i, list->element[n].name );
4603 n++;
4606 list->total = n;
4608 return n;
4611 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4612 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4614 GdiFont *font;
4615 LONG width, height;
4617 if (face->cached_enum_data)
4619 TRACE("Cached\n");
4620 *pelf = face->cached_enum_data->elf;
4621 *pntm = face->cached_enum_data->ntm;
4622 *ptype = face->cached_enum_data->type;
4623 return;
4626 font = alloc_font();
4628 if(face->scalable) {
4629 height = -2048; /* 2048 is the most common em size */
4630 width = 0;
4631 } else {
4632 height = face->size.y_ppem >> 6;
4633 width = face->size.x_ppem >> 6;
4635 font->scale_y = 1.0;
4637 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4639 free_font(font);
4640 return;
4643 font->name = strdupW(face->family->FamilyName);
4644 font->ntmFlags = face->ntmFlags;
4646 if (get_outline_text_metrics(font))
4648 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4650 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4652 lstrcpynW(pelf->elfLogFont.lfFaceName,
4653 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4654 LF_FACESIZE);
4655 lstrcpynW(pelf->elfFullName,
4656 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4657 LF_FULLFACESIZE);
4658 lstrcpynW(pelf->elfStyle,
4659 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4660 LF_FACESIZE);
4662 else
4664 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4666 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4668 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4669 if (face->FullName)
4670 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4671 else
4672 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4673 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4676 pntm->ntmTm.ntmFlags = face->ntmFlags;
4677 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4678 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4679 pntm->ntmFontSig = face->fs;
4681 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4683 pelf->elfLogFont.lfEscapement = 0;
4684 pelf->elfLogFont.lfOrientation = 0;
4685 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4686 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4687 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4688 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4689 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4690 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4691 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4692 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4693 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4694 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4695 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4697 *ptype = 0;
4698 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4699 *ptype |= TRUETYPE_FONTTYPE;
4700 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4701 *ptype |= DEVICE_FONTTYPE;
4702 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4703 *ptype |= RASTER_FONTTYPE;
4705 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4706 if (face->cached_enum_data)
4708 face->cached_enum_data->elf = *pelf;
4709 face->cached_enum_data->ntm = *pntm;
4710 face->cached_enum_data->type = *ptype;
4713 free_font(font);
4716 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
4718 static const WCHAR spaceW[] = { ' ', 0 };
4720 strcpyW(full_name, family_name);
4721 strcatW(full_name, spaceW);
4722 strcatW(full_name, style_name);
4725 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4727 const struct list *face_list, *face_elem_ptr;
4729 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4731 face_list = get_face_list_from_family(family);
4732 LIST_FOR_EACH(face_elem_ptr, face_list)
4734 WCHAR full_family_name[LF_FULLFACESIZE];
4735 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4737 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4739 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4740 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4741 continue;
4744 create_full_name(full_family_name, family->FamilyName, face->StyleName);
4745 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4748 return FALSE;
4751 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
4753 WCHAR full_family_name[LF_FULLFACESIZE];
4755 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
4757 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4759 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4760 debugstr_w(family_name), debugstr_w(face->StyleName));
4761 return FALSE;
4764 create_full_name(full_family_name, family_name, face->StyleName);
4765 return !strcmpiW(lf->lfFaceName, full_family_name);
4768 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
4769 FONTENUMPROCW proc, LPARAM lparam)
4771 ENUMLOGFONTEXW elf;
4772 NEWTEXTMETRICEXW ntm;
4773 DWORD type = 0;
4774 int i;
4776 GetEnumStructs(face, &elf, &ntm, &type);
4777 for(i = 0; i < list->total; i++) {
4778 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4779 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4780 load_script_name( IDS_OEM_DOS, elf.elfScript );
4781 i = list->total; /* break out of loop after enumeration */
4782 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4783 continue;
4784 else {
4785 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4786 strcpyW(elf.elfScript, list->element[i].name);
4787 if (!elf.elfScript[0])
4788 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4790 /* Font Replacement */
4791 if (family != face->family)
4793 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
4794 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
4796 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4797 debugstr_w(elf.elfLogFont.lfFaceName),
4798 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4799 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4800 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4801 ntm.ntmTm.ntmFlags);
4802 /* release section before callback (FIXME) */
4803 LeaveCriticalSection( &freetype_cs );
4804 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4805 EnterCriticalSection( &freetype_cs );
4807 return TRUE;
4810 /*************************************************************
4811 * freetype_EnumFonts
4813 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4815 Family *family;
4816 Face *face;
4817 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4818 LOGFONTW lf;
4819 struct enum_charset_list enum_charsets;
4821 if (!plf)
4823 lf.lfCharSet = DEFAULT_CHARSET;
4824 lf.lfPitchAndFamily = 0;
4825 lf.lfFaceName[0] = 0;
4826 plf = &lf;
4829 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4831 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4833 GDI_CheckNotLock();
4834 EnterCriticalSection( &freetype_cs );
4835 if(plf->lfFaceName[0]) {
4836 FontSubst *psub;
4837 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4839 if(psub) {
4840 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4841 debugstr_w(psub->to.name));
4842 lf = *plf;
4843 strcpyW(lf.lfFaceName, psub->to.name);
4844 plf = &lf;
4847 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4848 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4849 if(family_matches(family, plf)) {
4850 face_list = get_face_list_from_family(family);
4851 LIST_FOR_EACH(face_elem_ptr, face_list) {
4852 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4853 if (!face_matches(family->FamilyName, face, plf)) continue;
4854 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4858 } else {
4859 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4860 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4861 face_list = get_face_list_from_family(family);
4862 face_elem_ptr = list_head(face_list);
4863 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4864 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4867 LeaveCriticalSection( &freetype_cs );
4868 return TRUE;
4871 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4873 pt->x.value = vec->x >> 6;
4874 pt->x.fract = (vec->x & 0x3f) << 10;
4875 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4876 pt->y.value = vec->y >> 6;
4877 pt->y.fract = (vec->y & 0x3f) << 10;
4878 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4879 return;
4882 /***************************************************
4883 * According to the MSDN documentation on WideCharToMultiByte,
4884 * certain codepages cannot set the default_used parameter.
4885 * This returns TRUE if the codepage can set that parameter, false else
4886 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4888 static BOOL codepage_sets_default_used(UINT codepage)
4890 switch (codepage)
4892 case CP_UTF7:
4893 case CP_UTF8:
4894 case CP_SYMBOL:
4895 return FALSE;
4896 default:
4897 return TRUE;
4902 * GSUB Table handling functions
4905 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4907 const GSUB_CoverageFormat1* cf1;
4909 cf1 = table;
4911 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4913 int count = GET_BE_WORD(cf1->GlyphCount);
4914 int i;
4915 TRACE("Coverage Format 1, %i glyphs\n",count);
4916 for (i = 0; i < count; i++)
4917 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4918 return i;
4919 return -1;
4921 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4923 const GSUB_CoverageFormat2* cf2;
4924 int i;
4925 int count;
4926 cf2 = (const GSUB_CoverageFormat2*)cf1;
4928 count = GET_BE_WORD(cf2->RangeCount);
4929 TRACE("Coverage Format 2, %i ranges\n",count);
4930 for (i = 0; i < count; i++)
4932 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4933 return -1;
4934 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4935 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4937 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4938 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4941 return -1;
4943 else
4944 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4946 return -1;
4949 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4951 const GSUB_ScriptList *script;
4952 const GSUB_Script *deflt = NULL;
4953 int i;
4954 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4956 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4957 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4959 const GSUB_Script *scr;
4960 int offset;
4962 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4963 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4965 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4966 return scr;
4967 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4968 deflt = scr;
4970 return deflt;
4973 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4975 int i;
4976 int offset;
4977 const GSUB_LangSys *Lang;
4979 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4981 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4983 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4984 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4986 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4987 return Lang;
4989 offset = GET_BE_WORD(script->DefaultLangSys);
4990 if (offset)
4992 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4993 return Lang;
4995 return NULL;
4998 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5000 int i;
5001 const GSUB_FeatureList *feature;
5002 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5004 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5005 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5007 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5008 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5010 const GSUB_Feature *feat;
5011 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5012 return feat;
5015 return NULL;
5018 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5020 int i;
5021 int offset;
5022 const GSUB_LookupList *lookup;
5023 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5025 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5026 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5028 const GSUB_LookupTable *look;
5029 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5030 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5031 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5032 if (GET_BE_WORD(look->LookupType) != 1)
5033 FIXME("We only handle SubType 1\n");
5034 else
5036 int j;
5038 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5040 const GSUB_SingleSubstFormat1 *ssf1;
5041 offset = GET_BE_WORD(look->SubTable[j]);
5042 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5043 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5045 int offset = GET_BE_WORD(ssf1->Coverage);
5046 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5047 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5049 TRACE(" Glyph 0x%x ->",glyph);
5050 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5051 TRACE(" 0x%x\n",glyph);
5054 else
5056 const GSUB_SingleSubstFormat2 *ssf2;
5057 INT index;
5058 INT offset;
5060 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5061 offset = GET_BE_WORD(ssf1->Coverage);
5062 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5063 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5064 TRACE(" Coverage index %i\n",index);
5065 if (index != -1)
5067 TRACE(" Glyph is 0x%x ->",glyph);
5068 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5069 TRACE("0x%x\n",glyph);
5075 return glyph;
5078 static const char* get_opentype_script(const GdiFont *font)
5081 * I am not sure if this is the correct way to generate our script tag
5084 switch (font->charset)
5086 case ANSI_CHARSET: return "latn";
5087 case BALTIC_CHARSET: return "latn"; /* ?? */
5088 case CHINESEBIG5_CHARSET: return "hani";
5089 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5090 case GB2312_CHARSET: return "hani";
5091 case GREEK_CHARSET: return "grek";
5092 case HANGUL_CHARSET: return "hang";
5093 case RUSSIAN_CHARSET: return "cyrl";
5094 case SHIFTJIS_CHARSET: return "kana";
5095 case TURKISH_CHARSET: return "latn"; /* ?? */
5096 case VIETNAMESE_CHARSET: return "latn";
5097 case JOHAB_CHARSET: return "latn"; /* ?? */
5098 case ARABIC_CHARSET: return "arab";
5099 case HEBREW_CHARSET: return "hebr";
5100 case THAI_CHARSET: return "thai";
5101 default: return "latn";
5105 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5107 const GSUB_Header *header;
5108 const GSUB_Script *script;
5109 const GSUB_LangSys *language;
5110 const GSUB_Feature *feature;
5112 if (!font->GSUB_Table)
5113 return glyph;
5115 header = font->GSUB_Table;
5117 script = GSUB_get_script_table(header, get_opentype_script(font));
5118 if (!script)
5120 TRACE("Script not found\n");
5121 return glyph;
5123 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5124 if (!language)
5126 TRACE("Language not found\n");
5127 return glyph;
5129 feature = GSUB_get_feature(header, language, "vrt2");
5130 if (!feature)
5131 feature = GSUB_get_feature(header, language, "vert");
5132 if (!feature)
5134 TRACE("vrt2/vert feature not found\n");
5135 return glyph;
5137 return GSUB_apply_feature(header, feature, glyph);
5140 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5142 FT_UInt glyphId;
5144 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5145 WCHAR wc = (WCHAR)glyph;
5146 BOOL default_used;
5147 BOOL *default_used_pointer;
5148 FT_UInt ret;
5149 char buf;
5150 default_used_pointer = NULL;
5151 default_used = FALSE;
5152 if (codepage_sets_default_used(font->codepage))
5153 default_used_pointer = &default_used;
5154 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5155 ret = 0;
5156 else
5157 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5158 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5159 return ret;
5162 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5164 if (glyph < 0x100) glyph += 0xf000;
5165 /* there is a number of old pre-Unicode "broken" TTFs, which
5166 do have symbols at U+00XX instead of U+f0XX */
5167 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5168 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5170 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5172 return glyphId;
5175 /*************************************************************
5176 * freetype_GetGlyphIndices
5178 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5180 struct freetype_physdev *physdev = get_freetype_dev( dev );
5181 int i;
5182 WORD default_char;
5183 BOOL got_default = FALSE;
5185 if (!physdev->font)
5187 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5188 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5191 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5193 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5194 got_default = TRUE;
5197 GDI_CheckNotLock();
5198 EnterCriticalSection( &freetype_cs );
5200 for(i = 0; i < count; i++)
5202 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5203 if (pgi[i] == 0)
5205 if (!got_default)
5207 if (FT_IS_SFNT(physdev->font->ft_face))
5209 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5210 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5212 else
5214 TEXTMETRICW textm;
5215 get_text_metrics(physdev->font, &textm);
5216 default_char = textm.tmDefaultChar;
5218 got_default = TRUE;
5220 pgi[i] = default_char;
5223 LeaveCriticalSection( &freetype_cs );
5224 return count;
5227 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5229 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5230 return !memcmp(matrix, &identity, sizeof(FMAT2));
5233 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5235 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5236 return !memcmp(matrix, &identity, sizeof(MAT2));
5239 static inline BYTE get_max_level( UINT format )
5241 switch( format )
5243 case GGO_GRAY2_BITMAP: return 4;
5244 case GGO_GRAY4_BITMAP: return 16;
5245 case GGO_GRAY8_BITMAP: return 64;
5247 return 255;
5250 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5252 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5253 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5254 const MAT2* lpmat)
5256 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5257 FT_Face ft_face = incoming_font->ft_face;
5258 GdiFont *font = incoming_font;
5259 FT_UInt glyph_index;
5260 DWORD width, height, pitch, needed = 0;
5261 FT_Bitmap ft_bitmap;
5262 FT_Error err;
5263 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5264 FT_Angle angle = 0;
5265 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5266 double widthRatio = 1.0;
5267 FT_Matrix transMat = identityMat;
5268 FT_Matrix transMatUnrotated;
5269 BOOL needsTransform = FALSE;
5270 BOOL tategaki = (font->GSUB_Table != NULL);
5271 UINT original_index;
5273 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5274 buflen, buf, lpmat);
5276 TRACE("font transform %f %f %f %f\n",
5277 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5278 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5280 if(format & GGO_GLYPH_INDEX) {
5281 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5282 original_index = glyph;
5283 format &= ~GGO_GLYPH_INDEX;
5284 } else {
5285 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5286 ft_face = font->ft_face;
5287 original_index = glyph_index;
5290 if(format & GGO_UNHINTED) {
5291 load_flags |= FT_LOAD_NO_HINTING;
5292 format &= ~GGO_UNHINTED;
5295 /* tategaki never appears to happen to lower glyph index */
5296 if (glyph_index < TATEGAKI_LOWER_BOUND )
5297 tategaki = FALSE;
5299 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5300 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5301 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5302 font->gmsize * sizeof(GM*));
5303 } else {
5304 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5305 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5307 *lpgm = FONT_GM(font,original_index)->gm;
5308 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5309 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5310 lpgm->gmCellIncX, lpgm->gmCellIncY);
5311 return 1; /* FIXME */
5315 if (!font->gm[original_index / GM_BLOCK_SIZE])
5316 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5318 /* Scaling factor */
5319 if (font->aveWidth)
5321 TEXTMETRICW tm;
5323 get_text_metrics(font, &tm);
5325 widthRatio = (double)font->aveWidth;
5326 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5328 else
5329 widthRatio = font->scale_y;
5331 /* Scaling transform */
5332 if (widthRatio != 1.0 || font->scale_y != 1.0)
5334 FT_Matrix scaleMat;
5335 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5336 scaleMat.xy = 0;
5337 scaleMat.yx = 0;
5338 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5340 pFT_Matrix_Multiply(&scaleMat, &transMat);
5341 needsTransform = TRUE;
5344 /* Slant transform */
5345 if (font->fake_italic) {
5346 FT_Matrix slantMat;
5348 slantMat.xx = (1 << 16);
5349 slantMat.xy = ((1 << 16) >> 2);
5350 slantMat.yx = 0;
5351 slantMat.yy = (1 << 16);
5352 pFT_Matrix_Multiply(&slantMat, &transMat);
5353 needsTransform = TRUE;
5356 /* Rotation transform */
5357 transMatUnrotated = transMat;
5358 if(font->orientation && !tategaki) {
5359 FT_Matrix rotationMat;
5360 FT_Vector vecAngle;
5361 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5362 pFT_Vector_Unit(&vecAngle, angle);
5363 rotationMat.xx = vecAngle.x;
5364 rotationMat.xy = -vecAngle.y;
5365 rotationMat.yx = -rotationMat.xy;
5366 rotationMat.yy = rotationMat.xx;
5368 pFT_Matrix_Multiply(&rotationMat, &transMat);
5369 needsTransform = TRUE;
5372 /* World transform */
5373 if (!is_identity_FMAT2(&font->font_desc.matrix))
5375 FT_Matrix worldMat;
5376 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5377 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5378 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5379 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5380 pFT_Matrix_Multiply(&worldMat, &transMat);
5381 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5382 needsTransform = TRUE;
5385 /* Extra transformation specified by caller */
5386 if (!is_identity_MAT2(lpmat))
5388 FT_Matrix extraMat;
5389 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5390 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5391 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5392 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5393 pFT_Matrix_Multiply(&extraMat, &transMat);
5394 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5395 needsTransform = TRUE;
5398 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5399 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5400 format == GGO_GRAY8_BITMAP))
5402 load_flags |= FT_LOAD_NO_BITMAP;
5405 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5407 if(err) {
5408 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5409 return GDI_ERROR;
5412 if(!needsTransform) {
5413 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5414 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5415 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5417 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5418 bottom = (ft_face->glyph->metrics.horiBearingY -
5419 ft_face->glyph->metrics.height) & -64;
5420 lpgm->gmCellIncX = adv;
5421 lpgm->gmCellIncY = 0;
5422 } else {
5423 INT xc, yc;
5424 FT_Vector vec;
5426 left = right = 0;
5428 for(xc = 0; xc < 2; xc++) {
5429 for(yc = 0; yc < 2; yc++) {
5430 vec.x = (ft_face->glyph->metrics.horiBearingX +
5431 xc * ft_face->glyph->metrics.width);
5432 vec.y = ft_face->glyph->metrics.horiBearingY -
5433 yc * ft_face->glyph->metrics.height;
5434 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5435 pFT_Vector_Transform(&vec, &transMat);
5436 if(xc == 0 && yc == 0) {
5437 left = right = vec.x;
5438 top = bottom = vec.y;
5439 } else {
5440 if(vec.x < left) left = vec.x;
5441 else if(vec.x > right) right = vec.x;
5442 if(vec.y < bottom) bottom = vec.y;
5443 else if(vec.y > top) top = vec.y;
5447 left = left & -64;
5448 right = (right + 63) & -64;
5449 bottom = bottom & -64;
5450 top = (top + 63) & -64;
5452 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5453 vec.x = ft_face->glyph->metrics.horiAdvance;
5454 vec.y = 0;
5455 pFT_Vector_Transform(&vec, &transMat);
5456 lpgm->gmCellIncX = (vec.x+63) >> 6;
5457 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5459 vec.x = ft_face->glyph->metrics.horiAdvance;
5460 vec.y = 0;
5461 pFT_Vector_Transform(&vec, &transMatUnrotated);
5462 adv = (vec.x+63) >> 6;
5465 lsb = left >> 6;
5466 bbx = (right - left) >> 6;
5467 lpgm->gmBlackBoxX = (right - left) >> 6;
5468 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5469 lpgm->gmptGlyphOrigin.x = left >> 6;
5470 lpgm->gmptGlyphOrigin.y = top >> 6;
5472 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5473 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5474 lpgm->gmCellIncX, lpgm->gmCellIncY);
5476 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5477 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5479 FONT_GM(font,original_index)->gm = *lpgm;
5480 FONT_GM(font,original_index)->adv = adv;
5481 FONT_GM(font,original_index)->lsb = lsb;
5482 FONT_GM(font,original_index)->bbx = bbx;
5483 FONT_GM(font,original_index)->init = TRUE;
5486 if(format == GGO_METRICS)
5488 return 1; /* FIXME */
5491 if(ft_face->glyph->format != ft_glyph_format_outline &&
5492 (format == GGO_NATIVE || format == GGO_BEZIER))
5494 TRACE("loaded a bitmap\n");
5495 return GDI_ERROR;
5498 switch(format) {
5499 case GGO_BITMAP:
5500 width = lpgm->gmBlackBoxX;
5501 height = lpgm->gmBlackBoxY;
5502 pitch = ((width + 31) >> 5) << 2;
5503 needed = pitch * height;
5505 if(!buf || !buflen) break;
5507 switch(ft_face->glyph->format) {
5508 case ft_glyph_format_bitmap:
5510 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5511 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5512 INT h = ft_face->glyph->bitmap.rows;
5513 while(h--) {
5514 memcpy(dst, src, w);
5515 src += ft_face->glyph->bitmap.pitch;
5516 dst += pitch;
5518 break;
5521 case ft_glyph_format_outline:
5522 ft_bitmap.width = width;
5523 ft_bitmap.rows = height;
5524 ft_bitmap.pitch = pitch;
5525 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5526 ft_bitmap.buffer = buf;
5528 if(needsTransform)
5529 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5531 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5533 /* Note: FreeType will only set 'black' bits for us. */
5534 memset(buf, 0, needed);
5535 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5536 break;
5538 default:
5539 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5540 return GDI_ERROR;
5542 break;
5544 case GGO_GRAY2_BITMAP:
5545 case GGO_GRAY4_BITMAP:
5546 case GGO_GRAY8_BITMAP:
5547 case WINE_GGO_GRAY16_BITMAP:
5549 unsigned int max_level, row, col;
5550 BYTE *start, *ptr;
5552 width = lpgm->gmBlackBoxX;
5553 height = lpgm->gmBlackBoxY;
5554 pitch = (width + 3) / 4 * 4;
5555 needed = pitch * height;
5557 if(!buf || !buflen) break;
5559 max_level = get_max_level( format );
5561 switch(ft_face->glyph->format) {
5562 case ft_glyph_format_bitmap:
5564 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5565 INT h = ft_face->glyph->bitmap.rows;
5566 INT x;
5567 memset( buf, 0, needed );
5568 while(h--) {
5569 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5570 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5571 src += ft_face->glyph->bitmap.pitch;
5572 dst += pitch;
5574 return needed;
5576 case ft_glyph_format_outline:
5578 ft_bitmap.width = width;
5579 ft_bitmap.rows = height;
5580 ft_bitmap.pitch = pitch;
5581 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5582 ft_bitmap.buffer = buf;
5584 if(needsTransform)
5585 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5587 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5589 memset(ft_bitmap.buffer, 0, buflen);
5591 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5593 if (max_level != 255)
5595 for (row = 0, start = buf; row < height; row++)
5597 for (col = 0, ptr = start; col < width; col++, ptr++)
5598 *ptr = (((int)*ptr) * max_level + 128) / 256;
5599 start += pitch;
5602 return needed;
5605 default:
5606 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5607 return GDI_ERROR;
5609 break;
5612 case WINE_GGO_HRGB_BITMAP:
5613 case WINE_GGO_HBGR_BITMAP:
5614 case WINE_GGO_VRGB_BITMAP:
5615 case WINE_GGO_VBGR_BITMAP:
5616 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5618 switch (ft_face->glyph->format)
5620 case FT_GLYPH_FORMAT_BITMAP:
5622 BYTE *src, *dst;
5623 INT src_pitch, x;
5625 width = lpgm->gmBlackBoxX;
5626 height = lpgm->gmBlackBoxY;
5627 pitch = width * 4;
5628 needed = pitch * height;
5630 if (!buf || !buflen) break;
5632 memset(buf, 0, buflen);
5633 dst = buf;
5634 src = ft_face->glyph->bitmap.buffer;
5635 src_pitch = ft_face->glyph->bitmap.pitch;
5637 height = min( height, ft_face->glyph->bitmap.rows );
5638 while ( height-- )
5640 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5642 if ( src[x / 8] & masks[x % 8] )
5643 ((unsigned int *)dst)[x] = ~0u;
5645 src += src_pitch;
5646 dst += pitch;
5649 break;
5652 case FT_GLYPH_FORMAT_OUTLINE:
5654 unsigned int *dst;
5655 BYTE *src;
5656 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5657 INT x_shift, y_shift;
5658 BOOL rgb;
5659 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5660 FT_Render_Mode render_mode =
5661 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5662 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5664 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5666 if ( render_mode == FT_RENDER_MODE_LCD)
5668 lpgm->gmBlackBoxX += 2;
5669 lpgm->gmptGlyphOrigin.x -= 1;
5671 else
5673 lpgm->gmBlackBoxY += 2;
5674 lpgm->gmptGlyphOrigin.y += 1;
5678 width = lpgm->gmBlackBoxX;
5679 height = lpgm->gmBlackBoxY;
5680 pitch = width * 4;
5681 needed = pitch * height;
5683 if (!buf || !buflen) break;
5685 memset(buf, 0, buflen);
5686 dst = buf;
5687 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5689 if ( needsTransform )
5690 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5692 if ( pFT_Library_SetLcdFilter )
5693 pFT_Library_SetLcdFilter( library, lcdfilter );
5694 pFT_Render_Glyph (ft_face->glyph, render_mode);
5696 src = ft_face->glyph->bitmap.buffer;
5697 src_pitch = ft_face->glyph->bitmap.pitch;
5698 src_width = ft_face->glyph->bitmap.width;
5699 src_height = ft_face->glyph->bitmap.rows;
5701 if ( render_mode == FT_RENDER_MODE_LCD)
5703 rgb_interval = 1;
5704 hmul = 3;
5705 vmul = 1;
5707 else
5709 rgb_interval = src_pitch;
5710 hmul = 1;
5711 vmul = 3;
5714 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5715 if ( x_shift < 0 ) x_shift = 0;
5716 if ( x_shift + (src_width / hmul) > width )
5717 x_shift = width - (src_width / hmul);
5719 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5720 if ( y_shift < 0 ) y_shift = 0;
5721 if ( y_shift + (src_height / vmul) > height )
5722 y_shift = height - (src_height / vmul);
5724 dst += x_shift + y_shift * ( pitch / 4 );
5725 while ( src_height )
5727 for ( x = 0; x < src_width / hmul; x++ )
5729 if ( rgb )
5731 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5732 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5733 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5734 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5736 else
5738 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5739 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5740 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5741 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5744 src += src_pitch * vmul;
5745 dst += pitch / 4;
5746 src_height -= vmul;
5749 break;
5752 default:
5753 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5754 return GDI_ERROR;
5757 break;
5759 #else
5760 return GDI_ERROR;
5761 #endif
5763 case GGO_NATIVE:
5765 int contour, point = 0, first_pt;
5766 FT_Outline *outline = &ft_face->glyph->outline;
5767 TTPOLYGONHEADER *pph;
5768 TTPOLYCURVE *ppc;
5769 DWORD pph_start, cpfx, type;
5771 if(buflen == 0) buf = NULL;
5773 if (needsTransform && buf) {
5774 pFT_Outline_Transform(outline, &transMat);
5777 for(contour = 0; contour < outline->n_contours; contour++) {
5778 pph_start = needed;
5779 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5780 first_pt = point;
5781 if(buf) {
5782 pph->dwType = TT_POLYGON_TYPE;
5783 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5785 needed += sizeof(*pph);
5786 point++;
5787 while(point <= outline->contours[contour]) {
5788 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5789 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5790 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5791 cpfx = 0;
5792 do {
5793 if(buf)
5794 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5795 cpfx++;
5796 point++;
5797 } while(point <= outline->contours[contour] &&
5798 (outline->tags[point] & FT_Curve_Tag_On) ==
5799 (outline->tags[point-1] & FT_Curve_Tag_On));
5800 /* At the end of a contour Windows adds the start point, but
5801 only for Beziers */
5802 if(point > outline->contours[contour] &&
5803 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5804 if(buf)
5805 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5806 cpfx++;
5807 } else if(point <= outline->contours[contour] &&
5808 outline->tags[point] & FT_Curve_Tag_On) {
5809 /* add closing pt for bezier */
5810 if(buf)
5811 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5812 cpfx++;
5813 point++;
5815 if(buf) {
5816 ppc->wType = type;
5817 ppc->cpfx = cpfx;
5819 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5821 if(buf)
5822 pph->cb = needed - pph_start;
5824 break;
5826 case GGO_BEZIER:
5828 /* Convert the quadratic Beziers to cubic Beziers.
5829 The parametric eqn for a cubic Bezier is, from PLRM:
5830 r(t) = at^3 + bt^2 + ct + r0
5831 with the control points:
5832 r1 = r0 + c/3
5833 r2 = r1 + (c + b)/3
5834 r3 = r0 + c + b + a
5836 A quadratic Bezier has the form:
5837 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5839 So equating powers of t leads to:
5840 r1 = 2/3 p1 + 1/3 p0
5841 r2 = 2/3 p1 + 1/3 p2
5842 and of course r0 = p0, r3 = p2
5845 int contour, point = 0, first_pt;
5846 FT_Outline *outline = &ft_face->glyph->outline;
5847 TTPOLYGONHEADER *pph;
5848 TTPOLYCURVE *ppc;
5849 DWORD pph_start, cpfx, type;
5850 FT_Vector cubic_control[4];
5851 if(buflen == 0) buf = NULL;
5853 if (needsTransform && buf) {
5854 pFT_Outline_Transform(outline, &transMat);
5857 for(contour = 0; contour < outline->n_contours; contour++) {
5858 pph_start = needed;
5859 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5860 first_pt = point;
5861 if(buf) {
5862 pph->dwType = TT_POLYGON_TYPE;
5863 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5865 needed += sizeof(*pph);
5866 point++;
5867 while(point <= outline->contours[contour]) {
5868 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5869 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5870 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5871 cpfx = 0;
5872 do {
5873 if(type == TT_PRIM_LINE) {
5874 if(buf)
5875 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5876 cpfx++;
5877 point++;
5878 } else {
5879 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5880 so cpfx = 3n */
5882 /* FIXME: Possible optimization in endpoint calculation
5883 if there are two consecutive curves */
5884 cubic_control[0] = outline->points[point-1];
5885 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5886 cubic_control[0].x += outline->points[point].x + 1;
5887 cubic_control[0].y += outline->points[point].y + 1;
5888 cubic_control[0].x >>= 1;
5889 cubic_control[0].y >>= 1;
5891 if(point+1 > outline->contours[contour])
5892 cubic_control[3] = outline->points[first_pt];
5893 else {
5894 cubic_control[3] = outline->points[point+1];
5895 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5896 cubic_control[3].x += outline->points[point].x + 1;
5897 cubic_control[3].y += outline->points[point].y + 1;
5898 cubic_control[3].x >>= 1;
5899 cubic_control[3].y >>= 1;
5902 /* r1 = 1/3 p0 + 2/3 p1
5903 r2 = 1/3 p2 + 2/3 p1 */
5904 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5905 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5906 cubic_control[2] = cubic_control[1];
5907 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5908 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5909 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5910 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5911 if(buf) {
5912 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5913 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5914 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5916 cpfx += 3;
5917 point++;
5919 } while(point <= outline->contours[contour] &&
5920 (outline->tags[point] & FT_Curve_Tag_On) ==
5921 (outline->tags[point-1] & FT_Curve_Tag_On));
5922 /* At the end of a contour Windows adds the start point,
5923 but only for Beziers and we've already done that.
5925 if(point <= outline->contours[contour] &&
5926 outline->tags[point] & FT_Curve_Tag_On) {
5927 /* This is the closing pt of a bezier, but we've already
5928 added it, so just inc point and carry on */
5929 point++;
5931 if(buf) {
5932 ppc->wType = type;
5933 ppc->cpfx = cpfx;
5935 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5937 if(buf)
5938 pph->cb = needed - pph_start;
5940 break;
5943 default:
5944 FIXME("Unsupported format %d\n", format);
5945 return GDI_ERROR;
5947 return needed;
5950 static BOOL get_bitmap_text_metrics(GdiFont *font)
5952 FT_Face ft_face = font->ft_face;
5953 FT_WinFNT_HeaderRec winfnt_header;
5954 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5955 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5956 font->potm->otmSize = size;
5958 #define TM font->potm->otmTextMetrics
5959 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5961 TM.tmHeight = winfnt_header.pixel_height;
5962 TM.tmAscent = winfnt_header.ascent;
5963 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5964 TM.tmInternalLeading = winfnt_header.internal_leading;
5965 TM.tmExternalLeading = winfnt_header.external_leading;
5966 TM.tmAveCharWidth = winfnt_header.avg_width;
5967 TM.tmMaxCharWidth = winfnt_header.max_width;
5968 TM.tmWeight = winfnt_header.weight;
5969 TM.tmOverhang = 0;
5970 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5971 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5972 TM.tmFirstChar = winfnt_header.first_char;
5973 TM.tmLastChar = winfnt_header.last_char;
5974 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5975 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5976 TM.tmItalic = winfnt_header.italic;
5977 TM.tmUnderlined = font->underline;
5978 TM.tmStruckOut = font->strikeout;
5979 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5980 TM.tmCharSet = winfnt_header.charset;
5982 else
5984 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5985 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5986 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5987 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5988 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5989 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5990 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5991 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5992 TM.tmOverhang = 0;
5993 TM.tmDigitizedAspectX = 96; /* FIXME */
5994 TM.tmDigitizedAspectY = 96; /* FIXME */
5995 TM.tmFirstChar = 1;
5996 TM.tmLastChar = 255;
5997 TM.tmDefaultChar = 32;
5998 TM.tmBreakChar = 32;
5999 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6000 TM.tmUnderlined = font->underline;
6001 TM.tmStruckOut = font->strikeout;
6002 /* NB inverted meaning of TMPF_FIXED_PITCH */
6003 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6004 TM.tmCharSet = font->charset;
6006 #undef TM
6008 return TRUE;
6012 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6014 double scale_x, scale_y;
6016 if (font->aveWidth)
6018 scale_x = (double)font->aveWidth;
6019 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6021 else
6022 scale_x = font->scale_y;
6024 scale_x *= fabs(font->font_desc.matrix.eM11);
6025 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6027 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6028 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6030 SCALE_Y(ptm->tmHeight);
6031 SCALE_Y(ptm->tmAscent);
6032 SCALE_Y(ptm->tmDescent);
6033 SCALE_Y(ptm->tmInternalLeading);
6034 SCALE_Y(ptm->tmExternalLeading);
6035 SCALE_Y(ptm->tmOverhang);
6037 SCALE_X(ptm->tmAveCharWidth);
6038 SCALE_X(ptm->tmMaxCharWidth);
6040 #undef SCALE_X
6041 #undef SCALE_Y
6044 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6046 double scale_x, scale_y;
6048 if (font->aveWidth)
6050 scale_x = (double)font->aveWidth;
6051 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6053 else
6054 scale_x = font->scale_y;
6056 scale_x *= fabs(font->font_desc.matrix.eM11);
6057 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6059 scale_font_metrics(font, &potm->otmTextMetrics);
6061 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6062 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6064 SCALE_Y(potm->otmAscent);
6065 SCALE_Y(potm->otmDescent);
6066 SCALE_Y(potm->otmLineGap);
6067 SCALE_Y(potm->otmsCapEmHeight);
6068 SCALE_Y(potm->otmsXHeight);
6069 SCALE_Y(potm->otmrcFontBox.top);
6070 SCALE_Y(potm->otmrcFontBox.bottom);
6071 SCALE_X(potm->otmrcFontBox.left);
6072 SCALE_X(potm->otmrcFontBox.right);
6073 SCALE_Y(potm->otmMacAscent);
6074 SCALE_Y(potm->otmMacDescent);
6075 SCALE_Y(potm->otmMacLineGap);
6076 SCALE_X(potm->otmptSubscriptSize.x);
6077 SCALE_Y(potm->otmptSubscriptSize.y);
6078 SCALE_X(potm->otmptSubscriptOffset.x);
6079 SCALE_Y(potm->otmptSubscriptOffset.y);
6080 SCALE_X(potm->otmptSuperscriptSize.x);
6081 SCALE_Y(potm->otmptSuperscriptSize.y);
6082 SCALE_X(potm->otmptSuperscriptOffset.x);
6083 SCALE_Y(potm->otmptSuperscriptOffset.y);
6084 SCALE_Y(potm->otmsStrikeoutSize);
6085 SCALE_Y(potm->otmsStrikeoutPosition);
6086 SCALE_Y(potm->otmsUnderscoreSize);
6087 SCALE_Y(potm->otmsUnderscorePosition);
6089 #undef SCALE_X
6090 #undef SCALE_Y
6093 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6095 if(!font->potm)
6097 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6099 /* Make sure that the font has sane width/height ratio */
6100 if (font->aveWidth)
6102 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6104 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6105 font->aveWidth = 0;
6109 *ptm = font->potm->otmTextMetrics;
6110 scale_font_metrics(font, ptm);
6111 return TRUE;
6114 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6116 int i;
6118 for(i = 0; i < ft_face->num_charmaps; i++)
6120 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6121 return TRUE;
6123 return FALSE;
6126 static BOOL get_outline_text_metrics(GdiFont *font)
6128 BOOL ret = FALSE;
6129 FT_Face ft_face = font->ft_face;
6130 UINT needed, lenfam, lensty;
6131 TT_OS2 *pOS2;
6132 TT_HoriHeader *pHori;
6133 TT_Postscript *pPost;
6134 FT_Fixed x_scale, y_scale;
6135 WCHAR *family_nameW, *style_nameW;
6136 static const WCHAR spaceW[] = {' ', '\0'};
6137 char *cp;
6138 INT ascent, descent;
6140 TRACE("font=%p\n", font);
6142 if(!FT_IS_SCALABLE(ft_face))
6143 return FALSE;
6145 needed = sizeof(*font->potm);
6147 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6148 family_nameW = strdupW(font->name);
6150 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6151 * sizeof(WCHAR);
6152 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6153 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6154 style_nameW, lensty/sizeof(WCHAR));
6156 /* These names should be read from the TT name table */
6158 /* length of otmpFamilyName */
6159 needed += lenfam;
6161 /* length of otmpFaceName */
6162 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6163 needed += lenfam; /* just the family name */
6164 } else {
6165 needed += lenfam + lensty; /* family + " " + style */
6168 /* length of otmpStyleName */
6169 needed += lensty;
6171 /* length of otmpFullName */
6172 needed += lenfam + lensty;
6175 x_scale = ft_face->size->metrics.x_scale;
6176 y_scale = ft_face->size->metrics.y_scale;
6178 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6179 if(!pOS2) {
6180 FIXME("Can't find OS/2 table - not TT font?\n");
6181 goto end;
6184 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6185 if(!pHori) {
6186 FIXME("Can't find HHEA table - not TT font?\n");
6187 goto end;
6190 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6192 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",
6193 pOS2->usWinAscent, pOS2->usWinDescent,
6194 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6195 ft_face->ascender, ft_face->descender, ft_face->height,
6196 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6197 ft_face->bbox.yMax, ft_face->bbox.yMin);
6199 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6200 font->potm->otmSize = needed;
6202 #define TM font->potm->otmTextMetrics
6204 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6205 ascent = pHori->Ascender;
6206 descent = -pHori->Descender;
6207 } else {
6208 ascent = pOS2->usWinAscent;
6209 descent = pOS2->usWinDescent;
6212 if(font->yMax) {
6213 TM.tmAscent = font->yMax;
6214 TM.tmDescent = -font->yMin;
6215 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6216 } else {
6217 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6218 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6219 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6220 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6223 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6225 /* MSDN says:
6226 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6228 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6229 ((ascent + descent) -
6230 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6232 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6233 if (TM.tmAveCharWidth == 0) {
6234 TM.tmAveCharWidth = 1;
6236 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6237 TM.tmWeight = FW_REGULAR;
6238 if (font->fake_bold)
6239 TM.tmWeight = FW_BOLD;
6240 else
6242 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6244 if (pOS2->usWeightClass > FW_MEDIUM)
6245 TM.tmWeight = pOS2->usWeightClass;
6247 else if (pOS2->usWeightClass <= FW_MEDIUM)
6248 TM.tmWeight = pOS2->usWeightClass;
6250 TM.tmOverhang = 0;
6251 TM.tmDigitizedAspectX = 300;
6252 TM.tmDigitizedAspectY = 300;
6253 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6254 * symbol range to 0 - f0ff
6257 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6259 TM.tmFirstChar = 0;
6260 switch(GetACP())
6262 case 1257: /* Baltic */
6263 TM.tmLastChar = 0xf8fd;
6264 break;
6265 default:
6266 TM.tmLastChar = 0xf0ff;
6268 TM.tmBreakChar = 0x20;
6269 TM.tmDefaultChar = 0x1f;
6271 else
6273 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6274 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6276 if(pOS2->usFirstCharIndex <= 1)
6277 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6278 else if (pOS2->usFirstCharIndex > 0xff)
6279 TM.tmBreakChar = 0x20;
6280 else
6281 TM.tmBreakChar = pOS2->usFirstCharIndex;
6282 TM.tmDefaultChar = TM.tmBreakChar - 1;
6284 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6285 TM.tmUnderlined = font->underline;
6286 TM.tmStruckOut = font->strikeout;
6288 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6289 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6290 (pOS2->version == 0xFFFFU ||
6291 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6292 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6293 else
6294 TM.tmPitchAndFamily = 0;
6296 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6298 case PAN_FAMILY_SCRIPT:
6299 TM.tmPitchAndFamily |= FF_SCRIPT;
6300 break;
6302 case PAN_FAMILY_DECORATIVE:
6303 TM.tmPitchAndFamily |= FF_DECORATIVE;
6304 break;
6306 case PAN_ANY:
6307 case PAN_NO_FIT:
6308 case PAN_FAMILY_TEXT_DISPLAY:
6309 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6310 /* which is clearly not what the panose spec says. */
6311 default:
6312 if(TM.tmPitchAndFamily == 0 || /* fixed */
6313 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6314 TM.tmPitchAndFamily = FF_MODERN;
6315 else
6317 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6319 case PAN_ANY:
6320 case PAN_NO_FIT:
6321 default:
6322 TM.tmPitchAndFamily |= FF_DONTCARE;
6323 break;
6325 case PAN_SERIF_COVE:
6326 case PAN_SERIF_OBTUSE_COVE:
6327 case PAN_SERIF_SQUARE_COVE:
6328 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6329 case PAN_SERIF_SQUARE:
6330 case PAN_SERIF_THIN:
6331 case PAN_SERIF_BONE:
6332 case PAN_SERIF_EXAGGERATED:
6333 case PAN_SERIF_TRIANGLE:
6334 TM.tmPitchAndFamily |= FF_ROMAN;
6335 break;
6337 case PAN_SERIF_NORMAL_SANS:
6338 case PAN_SERIF_OBTUSE_SANS:
6339 case PAN_SERIF_PERP_SANS:
6340 case PAN_SERIF_FLARED:
6341 case PAN_SERIF_ROUNDED:
6342 TM.tmPitchAndFamily |= FF_SWISS;
6343 break;
6346 break;
6349 if(FT_IS_SCALABLE(ft_face))
6350 TM.tmPitchAndFamily |= TMPF_VECTOR;
6352 if(FT_IS_SFNT(ft_face))
6354 if (font->ntmFlags & NTM_PS_OPENTYPE)
6355 TM.tmPitchAndFamily |= TMPF_DEVICE;
6356 else
6357 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6360 TM.tmCharSet = font->charset;
6362 font->potm->otmFiller = 0;
6363 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6364 font->potm->otmfsSelection = pOS2->fsSelection;
6365 font->potm->otmfsType = pOS2->fsType;
6366 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6367 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6368 font->potm->otmItalicAngle = 0; /* POST table */
6369 font->potm->otmEMSquare = ft_face->units_per_EM;
6370 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6371 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6372 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6373 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6374 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6375 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6376 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6377 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6378 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6379 font->potm->otmMacAscent = TM.tmAscent;
6380 font->potm->otmMacDescent = -TM.tmDescent;
6381 font->potm->otmMacLineGap = font->potm->otmLineGap;
6382 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6383 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6384 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6385 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6386 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6387 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6388 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6389 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6390 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6391 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6392 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6393 if(!pPost) {
6394 font->potm->otmsUnderscoreSize = 0;
6395 font->potm->otmsUnderscorePosition = 0;
6396 } else {
6397 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6398 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6400 #undef TM
6402 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6403 cp = (char*)font->potm + sizeof(*font->potm);
6404 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6405 strcpyW((WCHAR*)cp, family_nameW);
6406 cp += lenfam;
6407 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6408 strcpyW((WCHAR*)cp, style_nameW);
6409 cp += lensty;
6410 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6411 strcpyW((WCHAR*)cp, family_nameW);
6412 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6413 strcatW((WCHAR*)cp, spaceW);
6414 strcatW((WCHAR*)cp, style_nameW);
6415 cp += lenfam + lensty;
6416 } else
6417 cp += lenfam;
6418 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6419 strcpyW((WCHAR*)cp, family_nameW);
6420 strcatW((WCHAR*)cp, spaceW);
6421 strcatW((WCHAR*)cp, style_nameW);
6422 ret = TRUE;
6424 end:
6425 HeapFree(GetProcessHeap(), 0, style_nameW);
6426 HeapFree(GetProcessHeap(), 0, family_nameW);
6427 return ret;
6430 /*************************************************************
6431 * freetype_GetGlyphOutline
6433 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6434 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6436 struct freetype_physdev *physdev = get_freetype_dev( dev );
6437 DWORD ret;
6439 if (!physdev->font)
6441 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6442 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6445 GDI_CheckNotLock();
6446 EnterCriticalSection( &freetype_cs );
6447 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6448 LeaveCriticalSection( &freetype_cs );
6449 return ret;
6452 /*************************************************************
6453 * freetype_GetTextMetrics
6455 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6457 struct freetype_physdev *physdev = get_freetype_dev( dev );
6458 BOOL ret;
6460 if (!physdev->font)
6462 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6463 return dev->funcs->pGetTextMetrics( dev, metrics );
6466 GDI_CheckNotLock();
6467 EnterCriticalSection( &freetype_cs );
6468 ret = get_text_metrics( physdev->font, metrics );
6469 LeaveCriticalSection( &freetype_cs );
6470 return ret;
6473 /*************************************************************
6474 * freetype_GetOutlineTextMetrics
6476 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6478 struct freetype_physdev *physdev = get_freetype_dev( dev );
6479 UINT ret = 0;
6481 if (!physdev->font)
6483 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6484 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6487 TRACE("font=%p\n", physdev->font);
6489 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6491 GDI_CheckNotLock();
6492 EnterCriticalSection( &freetype_cs );
6494 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6496 if(cbSize >= physdev->font->potm->otmSize)
6498 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6499 scale_outline_font_metrics(physdev->font, potm);
6501 ret = physdev->font->potm->otmSize;
6503 LeaveCriticalSection( &freetype_cs );
6504 return ret;
6507 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6509 HFONTLIST *hfontlist;
6510 child->font = alloc_font();
6511 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6512 if(!child->font->ft_face)
6514 free_font(child->font);
6515 child->font = NULL;
6516 return FALSE;
6519 child->font->font_desc = font->font_desc;
6520 child->font->ntmFlags = child->face->ntmFlags;
6521 child->font->orientation = font->orientation;
6522 child->font->scale_y = font->scale_y;
6523 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6524 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6525 child->font->name = strdupW(child->face->family->FamilyName);
6526 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6527 child->font->base_font = font;
6528 list_add_head(&child_font_list, &child->font->entry);
6529 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6530 return TRUE;
6533 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6535 FT_UInt g;
6536 CHILD_FONT *child_font;
6538 if(font->base_font)
6539 font = font->base_font;
6541 *linked_font = font;
6543 if((*glyph = get_glyph_index(font, c)))
6545 *glyph = get_GSUB_vert_glyph(font, *glyph);
6546 return TRUE;
6549 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6551 if(!child_font->font)
6552 if(!load_child_font(font, child_font))
6553 continue;
6555 if(!child_font->font->ft_face)
6556 continue;
6557 g = get_glyph_index(child_font->font, c);
6558 g = get_GSUB_vert_glyph(child_font->font, g);
6559 if(g)
6561 *glyph = g;
6562 *linked_font = child_font->font;
6563 return TRUE;
6566 return FALSE;
6569 /*************************************************************
6570 * freetype_GetCharWidth
6572 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6574 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6575 UINT c;
6576 GLYPHMETRICS gm;
6577 FT_UInt glyph_index;
6578 GdiFont *linked_font;
6579 struct freetype_physdev *physdev = get_freetype_dev( dev );
6581 if (!physdev->font)
6583 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6584 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6587 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6589 GDI_CheckNotLock();
6590 EnterCriticalSection( &freetype_cs );
6591 for(c = firstChar; c <= lastChar; c++) {
6592 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6593 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6594 &gm, 0, NULL, &identity);
6595 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6597 LeaveCriticalSection( &freetype_cs );
6598 return TRUE;
6601 /*************************************************************
6602 * freetype_GetCharABCWidths
6604 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6606 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6607 UINT c;
6608 GLYPHMETRICS gm;
6609 FT_UInt glyph_index;
6610 GdiFont *linked_font;
6611 struct freetype_physdev *physdev = get_freetype_dev( dev );
6613 if (!physdev->font)
6615 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6616 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6619 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6621 GDI_CheckNotLock();
6622 EnterCriticalSection( &freetype_cs );
6624 for(c = firstChar; c <= lastChar; c++) {
6625 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6626 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6627 &gm, 0, NULL, &identity);
6628 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6629 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6630 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6631 FONT_GM(linked_font,glyph_index)->bbx;
6633 LeaveCriticalSection( &freetype_cs );
6634 return TRUE;
6637 /*************************************************************
6638 * freetype_GetCharABCWidthsI
6640 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6642 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6643 UINT c;
6644 GLYPHMETRICS gm;
6645 FT_UInt glyph_index;
6646 GdiFont *linked_font;
6647 struct freetype_physdev *physdev = get_freetype_dev( dev );
6649 if (!physdev->font)
6651 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6652 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6655 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6656 return FALSE;
6658 GDI_CheckNotLock();
6659 EnterCriticalSection( &freetype_cs );
6661 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6662 if (!pgi)
6663 for(c = firstChar; c < firstChar+count; c++) {
6664 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6665 &gm, 0, NULL, &identity);
6666 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6667 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6668 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6669 - FONT_GM(linked_font,c)->bbx;
6671 else
6672 for(c = 0; c < count; c++) {
6673 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6674 &gm, 0, NULL, &identity);
6675 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6676 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6677 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6678 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6681 LeaveCriticalSection( &freetype_cs );
6682 return TRUE;
6685 /*************************************************************
6686 * freetype_GetTextExtentExPoint
6688 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6689 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6691 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6692 INT idx;
6693 INT nfit = 0, ext;
6694 GLYPHMETRICS gm;
6695 TEXTMETRICW tm;
6696 FT_UInt glyph_index;
6697 GdiFont *linked_font;
6698 struct freetype_physdev *physdev = get_freetype_dev( dev );
6700 if (!physdev->font)
6702 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6703 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6706 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6708 GDI_CheckNotLock();
6709 EnterCriticalSection( &freetype_cs );
6711 size->cx = 0;
6712 get_text_metrics( physdev->font, &tm );
6713 size->cy = tm.tmHeight;
6715 for(idx = 0; idx < count; idx++) {
6716 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6717 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6718 &gm, 0, NULL, &identity);
6719 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6720 ext = size->cx;
6721 if (! pnfit || ext <= max_ext) {
6722 ++nfit;
6723 if (dxs)
6724 dxs[idx] = ext;
6728 if (pnfit)
6729 *pnfit = nfit;
6731 LeaveCriticalSection( &freetype_cs );
6732 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6733 return TRUE;
6736 /*************************************************************
6737 * freetype_GetTextExtentExPointI
6739 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6740 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6742 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6743 INT idx;
6744 INT nfit = 0, ext;
6745 GLYPHMETRICS gm;
6746 TEXTMETRICW tm;
6747 struct freetype_physdev *physdev = get_freetype_dev( dev );
6749 if (!physdev->font)
6751 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6752 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6755 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6757 GDI_CheckNotLock();
6758 EnterCriticalSection( &freetype_cs );
6760 size->cx = 0;
6761 get_text_metrics(physdev->font, &tm);
6762 size->cy = tm.tmHeight;
6764 for(idx = 0; idx < count; idx++) {
6765 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6766 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6767 ext = size->cx;
6768 if (! pnfit || ext <= max_ext) {
6769 ++nfit;
6770 if (dxs)
6771 dxs[idx] = ext;
6775 if (pnfit)
6776 *pnfit = nfit;
6778 LeaveCriticalSection( &freetype_cs );
6779 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6780 return TRUE;
6783 /*************************************************************
6784 * freetype_GetFontData
6786 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6788 struct freetype_physdev *physdev = get_freetype_dev( dev );
6790 if (!physdev->font)
6792 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6793 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6796 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6797 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6798 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6800 return get_font_data( physdev->font, table, offset, buf, cbData );
6803 /*************************************************************
6804 * freetype_GetTextFace
6806 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6808 INT n;
6809 struct freetype_physdev *physdev = get_freetype_dev( dev );
6811 if (!physdev->font)
6813 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6814 return dev->funcs->pGetTextFace( dev, count, str );
6817 n = strlenW(physdev->font->name) + 1;
6818 if (str)
6820 lstrcpynW(str, physdev->font->name, count);
6821 n = min(count, n);
6823 return n;
6826 /*************************************************************
6827 * freetype_GetTextCharsetInfo
6829 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6831 struct freetype_physdev *physdev = get_freetype_dev( dev );
6833 if (!physdev->font)
6835 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6836 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6838 if (fs) *fs = physdev->font->fs;
6839 return physdev->font->charset;
6842 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6844 GdiFont *font = dc->gdiFont, *linked_font;
6845 struct list *first_hfont;
6846 BOOL ret;
6848 GDI_CheckNotLock();
6849 EnterCriticalSection( &freetype_cs );
6850 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6851 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6852 if(font == linked_font)
6853 *new_hfont = dc->hFont;
6854 else
6856 first_hfont = list_head(&linked_font->hfontlist);
6857 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6859 LeaveCriticalSection( &freetype_cs );
6860 return ret;
6863 /* Retrieve a list of supported Unicode ranges for a given font.
6864 * Can be called with NULL gs to calculate the buffer size. Returns
6865 * the number of ranges found.
6867 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6869 DWORD num_ranges = 0;
6871 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6873 FT_UInt glyph_code;
6874 FT_ULong char_code, char_code_prev;
6876 glyph_code = 0;
6877 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6879 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6880 face->num_glyphs, glyph_code, char_code);
6882 if (!glyph_code) return 0;
6884 if (gs)
6886 gs->ranges[0].wcLow = (USHORT)char_code;
6887 gs->ranges[0].cGlyphs = 0;
6888 gs->cGlyphsSupported = 0;
6891 num_ranges = 1;
6892 while (glyph_code)
6894 if (char_code < char_code_prev)
6896 ERR("expected increasing char code from FT_Get_Next_Char\n");
6897 return 0;
6899 if (char_code - char_code_prev > 1)
6901 num_ranges++;
6902 if (gs)
6904 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6905 gs->ranges[num_ranges - 1].cGlyphs = 1;
6906 gs->cGlyphsSupported++;
6909 else if (gs)
6911 gs->ranges[num_ranges - 1].cGlyphs++;
6912 gs->cGlyphsSupported++;
6914 char_code_prev = char_code;
6915 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6918 else
6919 FIXME("encoding %u not supported\n", face->charmap->encoding);
6921 return num_ranges;
6924 /*************************************************************
6925 * freetype_GetFontUnicodeRanges
6927 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6929 struct freetype_physdev *physdev = get_freetype_dev( dev );
6930 DWORD size, num_ranges;
6932 if (!physdev->font)
6934 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6935 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6938 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6939 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6940 if (glyphset)
6942 glyphset->cbThis = size;
6943 glyphset->cRanges = num_ranges;
6944 glyphset->flAccel = 0;
6946 return size;
6949 /*************************************************************
6950 * freetype_FontIsLinked
6952 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6954 struct freetype_physdev *physdev = get_freetype_dev( dev );
6955 BOOL ret;
6957 if (!physdev->font)
6959 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6960 return dev->funcs->pFontIsLinked( dev );
6963 GDI_CheckNotLock();
6964 EnterCriticalSection( &freetype_cs );
6965 ret = !list_empty(&physdev->font->child_fonts);
6966 LeaveCriticalSection( &freetype_cs );
6967 return ret;
6970 static BOOL is_hinting_enabled(void)
6972 /* Use the >= 2.2.0 function if available */
6973 if(pFT_Get_TrueType_Engine_Type)
6975 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6976 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6978 #ifdef FT_DRIVER_HAS_HINTER
6979 else
6981 FT_Module mod;
6983 /* otherwise if we've been compiled with < 2.2.0 headers
6984 use the internal macro */
6985 mod = pFT_Get_Module(library, "truetype");
6986 if(mod && FT_DRIVER_HAS_HINTER(mod))
6987 return TRUE;
6989 #endif
6991 return FALSE;
6994 static BOOL is_subpixel_rendering_enabled( void )
6996 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6997 return pFT_Library_SetLcdFilter &&
6998 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6999 #else
7000 return FALSE;
7001 #endif
7004 /*************************************************************************
7005 * GetRasterizerCaps (GDI32.@)
7007 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7009 static int hinting = -1;
7010 static int subpixel = -1;
7012 if(hinting == -1)
7014 hinting = is_hinting_enabled();
7015 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7018 if ( subpixel == -1 )
7020 subpixel = is_subpixel_rendering_enabled();
7021 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7024 lprs->nSize = sizeof(RASTERIZER_STATUS);
7025 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7026 if ( subpixel )
7027 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7028 lprs->nLanguageID = 0;
7029 return TRUE;
7032 /*************************************************************
7033 * freetype_GdiRealizationInfo
7035 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7037 struct freetype_physdev *physdev = get_freetype_dev( dev );
7038 realization_info_t *info = ptr;
7040 if (!physdev->font)
7042 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7043 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7046 FIXME("(%p, %p): stub!\n", physdev->font, info);
7048 info->flags = 1;
7049 if(FT_IS_SCALABLE(physdev->font->ft_face))
7050 info->flags |= 2;
7052 info->cache_num = physdev->font->cache_num;
7053 info->unknown2 = -1;
7054 return TRUE;
7057 /*************************************************************************
7058 * Kerning support for TrueType fonts
7060 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7062 struct TT_kern_table
7064 USHORT version;
7065 USHORT nTables;
7068 struct TT_kern_subtable
7070 USHORT version;
7071 USHORT length;
7072 union
7074 USHORT word;
7075 struct
7077 USHORT horizontal : 1;
7078 USHORT minimum : 1;
7079 USHORT cross_stream: 1;
7080 USHORT override : 1;
7081 USHORT reserved1 : 4;
7082 USHORT format : 8;
7083 } bits;
7084 } coverage;
7087 struct TT_format0_kern_subtable
7089 USHORT nPairs;
7090 USHORT searchRange;
7091 USHORT entrySelector;
7092 USHORT rangeShift;
7095 struct TT_kern_pair
7097 USHORT left;
7098 USHORT right;
7099 short value;
7102 static DWORD parse_format0_kern_subtable(GdiFont *font,
7103 const struct TT_format0_kern_subtable *tt_f0_ks,
7104 const USHORT *glyph_to_char,
7105 KERNINGPAIR *kern_pair, DWORD cPairs)
7107 USHORT i, nPairs;
7108 const struct TT_kern_pair *tt_kern_pair;
7110 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7112 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7114 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7115 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7116 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7118 if (!kern_pair || !cPairs)
7119 return nPairs;
7121 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7123 nPairs = min(nPairs, cPairs);
7125 for (i = 0; i < nPairs; i++)
7127 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7128 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7129 /* this algorithm appears to better match what Windows does */
7130 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7131 if (kern_pair->iKernAmount < 0)
7133 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7134 kern_pair->iKernAmount -= font->ppem;
7136 else if (kern_pair->iKernAmount > 0)
7138 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7139 kern_pair->iKernAmount += font->ppem;
7141 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7143 TRACE("left %u right %u value %d\n",
7144 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7146 kern_pair++;
7148 TRACE("copied %u entries\n", nPairs);
7149 return nPairs;
7152 /*************************************************************
7153 * freetype_GetKerningPairs
7155 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7157 DWORD length;
7158 void *buf;
7159 const struct TT_kern_table *tt_kern_table;
7160 const struct TT_kern_subtable *tt_kern_subtable;
7161 USHORT i, nTables;
7162 USHORT *glyph_to_char;
7163 GdiFont *font;
7164 struct freetype_physdev *physdev = get_freetype_dev( dev );
7166 if (!(font = physdev->font))
7168 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7169 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7172 GDI_CheckNotLock();
7173 EnterCriticalSection( &freetype_cs );
7174 if (font->total_kern_pairs != (DWORD)-1)
7176 if (cPairs && kern_pair)
7178 cPairs = min(cPairs, font->total_kern_pairs);
7179 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7181 else cPairs = font->total_kern_pairs;
7183 LeaveCriticalSection( &freetype_cs );
7184 return cPairs;
7187 font->total_kern_pairs = 0;
7189 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7191 if (length == GDI_ERROR)
7193 TRACE("no kerning data in the font\n");
7194 LeaveCriticalSection( &freetype_cs );
7195 return 0;
7198 buf = HeapAlloc(GetProcessHeap(), 0, length);
7199 if (!buf)
7201 WARN("Out of memory\n");
7202 LeaveCriticalSection( &freetype_cs );
7203 return 0;
7206 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7208 /* build a glyph index to char code map */
7209 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7210 if (!glyph_to_char)
7212 WARN("Out of memory allocating a glyph index to char code map\n");
7213 HeapFree(GetProcessHeap(), 0, buf);
7214 LeaveCriticalSection( &freetype_cs );
7215 return 0;
7218 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7220 FT_UInt glyph_code;
7221 FT_ULong char_code;
7223 glyph_code = 0;
7224 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7226 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7227 font->ft_face->num_glyphs, glyph_code, char_code);
7229 while (glyph_code)
7231 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7233 /* FIXME: This doesn't match what Windows does: it does some fancy
7234 * things with duplicate glyph index to char code mappings, while
7235 * we just avoid overriding existing entries.
7237 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7238 glyph_to_char[glyph_code] = (USHORT)char_code;
7240 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7243 else
7245 ULONG n;
7247 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7248 for (n = 0; n <= 65535; n++)
7249 glyph_to_char[n] = (USHORT)n;
7252 tt_kern_table = buf;
7253 nTables = GET_BE_WORD(tt_kern_table->nTables);
7254 TRACE("version %u, nTables %u\n",
7255 GET_BE_WORD(tt_kern_table->version), nTables);
7257 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7259 for (i = 0; i < nTables; i++)
7261 struct TT_kern_subtable tt_kern_subtable_copy;
7263 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7264 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7265 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7267 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7268 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7269 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7271 /* According to the TrueType specification this is the only format
7272 * that will be properly interpreted by Windows and OS/2
7274 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7276 DWORD new_chunk, old_total = font->total_kern_pairs;
7278 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7279 glyph_to_char, NULL, 0);
7280 font->total_kern_pairs += new_chunk;
7282 if (!font->kern_pairs)
7283 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7284 font->total_kern_pairs * sizeof(*font->kern_pairs));
7285 else
7286 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7287 font->total_kern_pairs * sizeof(*font->kern_pairs));
7289 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7290 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7292 else
7293 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7295 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7298 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7299 HeapFree(GetProcessHeap(), 0, buf);
7301 if (cPairs && kern_pair)
7303 cPairs = min(cPairs, font->total_kern_pairs);
7304 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7306 else cPairs = font->total_kern_pairs;
7308 LeaveCriticalSection( &freetype_cs );
7309 return cPairs;
7312 static const struct gdi_dc_funcs freetype_funcs =
7314 NULL, /* pAbortDoc */
7315 NULL, /* pAbortPath */
7316 NULL, /* pAlphaBlend */
7317 NULL, /* pAngleArc */
7318 NULL, /* pArc */
7319 NULL, /* pArcTo */
7320 NULL, /* pBeginPath */
7321 NULL, /* pBlendImage */
7322 NULL, /* pChoosePixelFormat */
7323 NULL, /* pChord */
7324 NULL, /* pCloseFigure */
7325 NULL, /* pCopyBitmap */
7326 NULL, /* pCreateBitmap */
7327 NULL, /* pCreateCompatibleDC */
7328 freetype_CreateDC, /* pCreateDC */
7329 NULL, /* pDeleteBitmap */
7330 freetype_DeleteDC, /* pDeleteDC */
7331 NULL, /* pDeleteObject */
7332 NULL, /* pDescribePixelFormat */
7333 NULL, /* pDeviceCapabilities */
7334 NULL, /* pEllipse */
7335 NULL, /* pEndDoc */
7336 NULL, /* pEndPage */
7337 NULL, /* pEndPath */
7338 freetype_EnumFonts, /* pEnumFonts */
7339 NULL, /* pEnumICMProfiles */
7340 NULL, /* pExcludeClipRect */
7341 NULL, /* pExtDeviceMode */
7342 NULL, /* pExtEscape */
7343 NULL, /* pExtFloodFill */
7344 NULL, /* pExtSelectClipRgn */
7345 NULL, /* pExtTextOut */
7346 NULL, /* pFillPath */
7347 NULL, /* pFillRgn */
7348 NULL, /* pFlattenPath */
7349 freetype_FontIsLinked, /* pFontIsLinked */
7350 NULL, /* pFrameRgn */
7351 NULL, /* pGdiComment */
7352 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7353 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7354 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7355 freetype_GetCharWidth, /* pGetCharWidth */
7356 NULL, /* pGetDeviceCaps */
7357 NULL, /* pGetDeviceGammaRamp */
7358 freetype_GetFontData, /* pGetFontData */
7359 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7360 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7361 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7362 NULL, /* pGetICMProfile */
7363 NULL, /* pGetImage */
7364 freetype_GetKerningPairs, /* pGetKerningPairs */
7365 NULL, /* pGetNearestColor */
7366 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7367 NULL, /* pGetPixel */
7368 NULL, /* pGetPixelFormat */
7369 NULL, /* pGetSystemPaletteEntries */
7370 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7371 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7372 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7373 freetype_GetTextFace, /* pGetTextFace */
7374 freetype_GetTextMetrics, /* pGetTextMetrics */
7375 NULL, /* pGradientFill */
7376 NULL, /* pIntersectClipRect */
7377 NULL, /* pInvertRgn */
7378 NULL, /* pLineTo */
7379 NULL, /* pModifyWorldTransform */
7380 NULL, /* pMoveTo */
7381 NULL, /* pOffsetClipRgn */
7382 NULL, /* pOffsetViewportOrg */
7383 NULL, /* pOffsetWindowOrg */
7384 NULL, /* pPaintRgn */
7385 NULL, /* pPatBlt */
7386 NULL, /* pPie */
7387 NULL, /* pPolyBezier */
7388 NULL, /* pPolyBezierTo */
7389 NULL, /* pPolyDraw */
7390 NULL, /* pPolyPolygon */
7391 NULL, /* pPolyPolyline */
7392 NULL, /* pPolygon */
7393 NULL, /* pPolyline */
7394 NULL, /* pPolylineTo */
7395 NULL, /* pPutImage */
7396 NULL, /* pRealizeDefaultPalette */
7397 NULL, /* pRealizePalette */
7398 NULL, /* pRectangle */
7399 NULL, /* pResetDC */
7400 NULL, /* pRestoreDC */
7401 NULL, /* pRoundRect */
7402 NULL, /* pSaveDC */
7403 NULL, /* pScaleViewportExt */
7404 NULL, /* pScaleWindowExt */
7405 NULL, /* pSelectBitmap */
7406 NULL, /* pSelectBrush */
7407 NULL, /* pSelectClipPath */
7408 freetype_SelectFont, /* pSelectFont */
7409 NULL, /* pSelectPalette */
7410 NULL, /* pSelectPen */
7411 NULL, /* pSetArcDirection */
7412 NULL, /* pSetBkColor */
7413 NULL, /* pSetBkMode */
7414 NULL, /* pSetDCBrushColor */
7415 NULL, /* pSetDCPenColor */
7416 NULL, /* pSetDIBColorTable */
7417 NULL, /* pSetDIBitsToDevice */
7418 NULL, /* pSetDeviceClipping */
7419 NULL, /* pSetDeviceGammaRamp */
7420 NULL, /* pSetLayout */
7421 NULL, /* pSetMapMode */
7422 NULL, /* pSetMapperFlags */
7423 NULL, /* pSetPixel */
7424 NULL, /* pSetPixelFormat */
7425 NULL, /* pSetPolyFillMode */
7426 NULL, /* pSetROP2 */
7427 NULL, /* pSetRelAbs */
7428 NULL, /* pSetStretchBltMode */
7429 NULL, /* pSetTextAlign */
7430 NULL, /* pSetTextCharacterExtra */
7431 NULL, /* pSetTextColor */
7432 NULL, /* pSetTextJustification */
7433 NULL, /* pSetViewportExt */
7434 NULL, /* pSetViewportOrg */
7435 NULL, /* pSetWindowExt */
7436 NULL, /* pSetWindowOrg */
7437 NULL, /* pSetWorldTransform */
7438 NULL, /* pStartDoc */
7439 NULL, /* pStartPage */
7440 NULL, /* pStretchBlt */
7441 NULL, /* pStretchDIBits */
7442 NULL, /* pStrokeAndFillPath */
7443 NULL, /* pStrokePath */
7444 NULL, /* pSwapBuffers */
7445 NULL, /* pUnrealizePalette */
7446 NULL, /* pWidenPath */
7447 /* OpenGL not supported */
7450 #else /* HAVE_FREETYPE */
7452 /*************************************************************************/
7454 BOOL WineEngInit(void)
7456 return FALSE;
7458 BOOL WineEngDestroyFontInstance(HFONT hfont)
7460 return FALSE;
7463 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7465 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7466 return 1;
7469 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7471 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7472 return TRUE;
7475 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7477 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7478 return NULL;
7481 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7483 return FALSE;
7486 /*************************************************************************
7487 * GetRasterizerCaps (GDI32.@)
7489 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7491 lprs->nSize = sizeof(RASTERIZER_STATUS);
7492 lprs->wFlags = 0;
7493 lprs->nLanguageID = 0;
7494 return TRUE;
7497 #endif /* HAVE_FREETYPE */