gdi32: Add a helper to free a face object and fix a potential memory leak.
[wine/wine-gecko.git] / dlls / gdi32 / freetype.c
blobefa36bbc7a15597d87263ba1e2eb71622cc1c4c4
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 #include "resource.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FREETYPE
98 #ifdef HAVE_FT2BUILD_H
99 #include <ft2build.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
103 #endif
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
106 #endif
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
112 #endif
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
115 #endif
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
118 #endif
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
121 #endif
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
124 #endif
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
127 #endif
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
130 #endif
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
173 #else
174 MAKE_FUNCPTR(FT_MulFix);
175 #endif
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetString);
205 #endif
207 #undef MAKE_FUNCPTR
209 #ifndef FT_MAKE_TAG
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
213 #endif
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
217 #endif
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
220 #endif
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
223 #endif
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
226 #endif
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
230 #else
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
232 #endif
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
235 typedef struct {
236 FT_Short height;
237 FT_Short width;
238 FT_Pos size;
239 FT_Pos x_ppem;
240 FT_Pos y_ppem;
241 FT_Short internal_leading;
242 } Bitmap_Size;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
247 typedef struct {
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
250 } My_FT_Bitmap_Size;
252 struct enum_data
254 ENUMLOGFONTEXW elf;
255 NEWTEXTMETRICEXW ntm;
256 DWORD type;
259 typedef struct tagFace {
260 struct list entry;
261 WCHAR *StyleName;
262 WCHAR *FullName;
263 char *file;
264 void *font_data_ptr;
265 DWORD font_data_size;
266 FT_Long face_index;
267 FONTSIGNATURE fs;
268 DWORD ntmFlags;
269 FT_Fixed font_version;
270 BOOL scalable;
271 BOOL vertical;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
277 } Face;
279 typedef struct tagFamily {
280 struct list entry;
281 const WCHAR *FamilyName;
282 const WCHAR *EnglishName;
283 struct list faces;
284 struct list *replacement;
285 } Family;
287 typedef struct {
288 GLYPHMETRICS gm;
289 INT adv; /* These three hold to widths of the unrotated chars */
290 INT lsb;
291 INT bbx;
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct {
313 struct list entry;
314 Face *face;
315 GdiFont *font;
316 } CHILD_FONT;
318 struct tagGdiFont {
319 struct list entry;
320 GM **gm;
321 DWORD gmsize;
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
329 FT_Face ft_face;
330 struct font_mapping *mapping;
331 LPWSTR name;
332 int charset;
333 int codepage;
334 BOOL fake_italic;
335 BOOL fake_bold;
336 BYTE underline;
337 BYTE strikeout;
338 INT orientation;
339 FONT_DESC font_desc;
340 LONG aveWidth, ppem;
341 double scale_y;
342 SHORT yMax;
343 SHORT yMin;
344 DWORD ntmFlags;
345 FONTSIGNATURE fs;
346 GdiFont *base_font;
347 VOID *GSUB_Table;
348 DWORD cache_num;
351 typedef struct {
352 struct list entry;
353 const WCHAR *font_name;
354 FONTSIGNATURE fs;
355 struct list links;
356 } SYSTEM_LINKS;
358 struct enum_charset_element {
359 DWORD mask;
360 DWORD charset;
361 WCHAR name[LF_FACESIZE];
364 struct enum_charset_list {
365 DWORD total;
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 struct freetype_physdev
384 struct gdi_physdev dev;
385 GdiFont *font;
388 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
390 return (struct freetype_physdev *)dev;
393 static const struct gdi_dc_funcs freetype_funcs;
395 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR * const SystemFontValues[] = {
416 System_Value,
417 OEMFont_Value,
418 FixedSys_Value,
419 NULL
422 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
428 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
438 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
439 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR *default_serif_list[] =
448 times_new_roman,
449 liberation_serif,
450 bitstream_vera_serif,
451 NULL
454 static const WCHAR *default_fixed_list[] =
456 courier_new,
457 liberation_mono,
458 bitstream_vera_sans_mono,
459 NULL
462 static const WCHAR *default_sans_list[] =
464 arial,
465 liberation_sans,
466 bitstream_vera_sans,
467 NULL
470 typedef struct {
471 WCHAR *name;
472 INT charset;
473 } NameCs;
475 typedef struct tagFontSubst {
476 struct list entry;
477 NameCs from;
478 NameCs to;
479 } FontSubst;
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
487 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
488 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
489 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
491 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
501 struct font_mapping
503 struct list entry;
504 int refcount;
505 dev_t dev;
506 ino_t ino;
507 void *data;
508 size_t size;
511 static struct list mappings_list = LIST_INIT( mappings_list );
513 static CRITICAL_SECTION freetype_cs;
514 static CRITICAL_SECTION_DEBUG critsect_debug =
516 0, 0, &freetype_cs,
517 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
518 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback = FALSE;
527 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
528 static BOOL get_outline_text_metrics(GdiFont *font);
529 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
531 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
546 * Key Meaning
547 * FIXEDFON.FON FixedSys
548 * FONTS.FON System
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
562 * I have
563 * woafont=app850.fon
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
575 typedef struct {
576 DWORD version;
577 WORD ScriptList;
578 WORD FeatureList;
579 WORD LookupList;
580 } GSUB_Header;
582 typedef struct {
583 CHAR ScriptTag[4];
584 WORD Script;
585 } GSUB_ScriptRecord;
587 typedef struct {
588 WORD ScriptCount;
589 GSUB_ScriptRecord ScriptRecord[1];
590 } GSUB_ScriptList;
592 typedef struct {
593 CHAR LangSysTag[4];
594 WORD LangSys;
595 } GSUB_LangSysRecord;
597 typedef struct {
598 WORD DefaultLangSys;
599 WORD LangSysCount;
600 GSUB_LangSysRecord LangSysRecord[1];
601 } GSUB_Script;
603 typedef struct {
604 WORD LookupOrder; /* Reserved */
605 WORD ReqFeatureIndex;
606 WORD FeatureCount;
607 WORD FeatureIndex[1];
608 } GSUB_LangSys;
610 typedef struct {
611 CHAR FeatureTag[4];
612 WORD Feature;
613 } GSUB_FeatureRecord;
615 typedef struct {
616 WORD FeatureCount;
617 GSUB_FeatureRecord FeatureRecord[1];
618 } GSUB_FeatureList;
620 typedef struct {
621 WORD FeatureParams; /* Reserved */
622 WORD LookupCount;
623 WORD LookupListIndex[1];
624 } GSUB_Feature;
626 typedef struct {
627 WORD LookupCount;
628 WORD Lookup[1];
629 } GSUB_LookupList;
631 typedef struct {
632 WORD LookupType;
633 WORD LookupFlag;
634 WORD SubTableCount;
635 WORD SubTable[1];
636 } GSUB_LookupTable;
638 typedef struct {
639 WORD CoverageFormat;
640 WORD GlyphCount;
641 WORD GlyphArray[1];
642 } GSUB_CoverageFormat1;
644 typedef struct {
645 WORD Start;
646 WORD End;
647 WORD StartCoverageIndex;
648 } GSUB_RangeRecord;
650 typedef struct {
651 WORD CoverageFormat;
652 WORD RangeCount;
653 GSUB_RangeRecord RangeRecord[1];
654 } GSUB_CoverageFormat2;
656 typedef struct {
657 WORD SubstFormat; /* = 1 */
658 WORD Coverage;
659 WORD DeltaGlyphID;
660 } GSUB_SingleSubstFormat1;
662 typedef struct {
663 WORD SubstFormat; /* = 2 */
664 WORD Coverage;
665 WORD GlyphCount;
666 WORD Substitute[1];
667 }GSUB_SingleSubstFormat2;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
672 FSRef ref;
673 OSErr err;
674 static char cached_path[MAX_PATH];
675 static const char *wine = "/Wine", *fonts = "/Fonts";
677 if(*cached_path) return cached_path;
679 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
680 if(err != noErr)
682 WARN("can't create cached data folder\n");
683 return NULL;
685 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
686 if(err != noErr)
688 WARN("can't create cached data path\n");
689 *cached_path = '\0';
690 return NULL;
692 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
694 ERR("Could not create full path\n");
695 *cached_path = '\0';
696 return NULL;
698 strcat(cached_path, wine);
700 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
702 WARN("Couldn't mkdir %s\n", cached_path);
703 *cached_path = '\0';
704 return NULL;
706 strcat(cached_path, fonts);
707 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
709 WARN("Couldn't mkdir %s\n", cached_path);
710 *cached_path = '\0';
711 return NULL;
713 return cached_path;
716 /******************************************************************
717 * expand_mac_font
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
721 * find_cache_dir()).
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path)
729 FSRef ref;
730 SInt16 res_ref;
731 OSStatus s;
732 unsigned int idx;
733 const char *out_dir;
734 const char *filename;
735 int output_len;
736 struct {
737 char **array;
738 unsigned int size, max_size;
739 } ret;
741 TRACE("path %s\n", path);
743 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
744 if(s != noErr)
746 WARN("failed to get ref\n");
747 return NULL;
750 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
751 if(s != noErr)
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref = FSOpenResFile(&ref, fsRdPerm);
755 if(res_ref == -1)
757 TRACE("unable to open resource fork\n");
758 return NULL;
762 ret.size = 0;
763 ret.max_size = 10;
764 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
765 if(!ret.array)
767 CloseResFile(res_ref);
768 return NULL;
771 out_dir = find_cache_dir();
773 filename = strrchr(path, '/');
774 if(!filename) filename = path;
775 else filename++;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
780 UseResFile(res_ref);
781 idx = 1;
782 while(1)
784 FamRec *fam_rec;
785 unsigned short *num_faces_ptr, num_faces, face;
786 AsscEntry *assoc;
787 Handle fond;
788 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
790 fond = Get1IndResource(fond_res, idx);
791 if(!fond) break;
792 TRACE("got fond resource %d\n", idx);
793 HLock(fond);
795 fam_rec = *(FamRec**)fond;
796 num_faces_ptr = (unsigned short *)(fam_rec + 1);
797 num_faces = GET_BE_WORD(*num_faces_ptr);
798 num_faces++;
799 assoc = (AsscEntry*)(num_faces_ptr + 1);
800 TRACE("num faces %04x\n", num_faces);
801 for(face = 0; face < num_faces; face++, assoc++)
803 Handle sfnt;
804 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
805 unsigned short size, font_id;
806 char *output;
808 size = GET_BE_WORD(assoc->fontSize);
809 font_id = GET_BE_WORD(assoc->fontID);
810 if(size != 0)
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
813 continue;
816 TRACE("trying to load sfnt id %04x\n", font_id);
817 sfnt = GetResource(sfnt_res, font_id);
818 if(!sfnt)
820 TRACE("can't get sfnt resource %04x\n", font_id);
821 continue;
824 output = HeapAlloc(GetProcessHeap(), 0, output_len);
825 if(output)
827 int fd;
829 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
831 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
832 if(fd != -1 || errno == EEXIST)
834 if(fd != -1)
836 unsigned char *sfnt_data;
838 HLock(sfnt);
839 sfnt_data = *(unsigned char**)sfnt;
840 write(fd, sfnt_data, GetHandleSize(sfnt));
841 HUnlock(sfnt);
842 close(fd);
844 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
846 ret.max_size *= 2;
847 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
849 ret.array[ret.size++] = output;
851 else
853 WARN("unable to create %s\n", output);
854 HeapFree(GetProcessHeap(), 0, output);
857 ReleaseResource(sfnt);
859 HUnlock(fond);
860 ReleaseResource(fond);
861 idx++;
863 CloseResFile(res_ref);
865 return ret.array;
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed FT_FixedFromFloat(double f)
880 return f * 0x10000;
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
889 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
893 static const struct list *get_face_list_from_family(const Family *family)
895 if (!list_empty(&family->faces))
896 return &family->faces;
897 else
898 return family->replacement;
901 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
903 Family *family;
904 Face *face;
905 const char *file;
906 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
907 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
909 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
912 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
914 const struct list *face_list;
915 if(face_name && strcmpiW(face_name, family->FamilyName))
916 continue;
917 face_list = get_face_list_from_family(family);
918 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
920 if (!face->file)
921 continue;
922 file = strrchr(face->file, '/');
923 if(!file)
924 file = face->file;
925 else
926 file++;
927 if(!strcasecmp(file, file_nameA))
929 HeapFree(GetProcessHeap(), 0, file_nameA);
930 return face;
934 HeapFree(GetProcessHeap(), 0, file_nameA);
935 return NULL;
938 static Family *find_family_from_name(const WCHAR *name)
940 Family *family;
942 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
944 if(!strcmpiW(family->FamilyName, name))
945 return family;
948 return NULL;
951 static Family *find_family_from_any_name(const WCHAR *name)
953 Family *family;
955 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
957 if(!strcmpiW(family->FamilyName, name))
958 return family;
959 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
960 return family;
963 return NULL;
966 static void DumpSubstList(void)
968 FontSubst *psub;
970 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
972 if(psub->from.charset != -1 || psub->to.charset != -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
974 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
975 else
976 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
977 debugstr_w(psub->to.name));
979 return;
982 static LPWSTR strdupW(LPCWSTR p)
984 LPWSTR ret;
985 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
986 ret = HeapAlloc(GetProcessHeap(), 0, len);
987 memcpy(ret, p, len);
988 return ret;
991 static LPSTR strdupA(LPCSTR p)
993 LPSTR ret;
994 DWORD len = (strlen(p) + 1);
995 ret = HeapAlloc(GetProcessHeap(), 0, len);
996 memcpy(ret, p, len);
997 return ret;
1000 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1001 INT from_charset)
1003 FontSubst *element;
1005 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1007 if(!strcmpiW(element->from.name, from_name) &&
1008 (element->from.charset == from_charset ||
1009 element->from.charset == -1))
1010 return element;
1013 return NULL;
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1020 FontSubst *from_exist, *to_exist;
1022 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1024 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1026 list_remove(&from_exist->entry);
1027 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1028 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1029 HeapFree(GetProcessHeap(), 0, from_exist);
1030 from_exist = NULL;
1033 if(!from_exist)
1035 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1037 if(to_exist)
1039 HeapFree(GetProcessHeap(), 0, subst->to.name);
1040 subst->to.name = strdupW(to_exist->to.name);
1043 list_add_tail(subst_list, &subst->entry);
1045 return TRUE;
1048 HeapFree(GetProcessHeap(), 0, subst->from.name);
1049 HeapFree(GetProcessHeap(), 0, subst->to.name);
1050 HeapFree(GetProcessHeap(), 0, subst);
1051 return FALSE;
1054 static WCHAR *towstr(UINT cp, const char *str)
1056 int len;
1057 WCHAR *wstr;
1059 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1060 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1061 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1062 return wstr;
1065 static void split_subst_info(NameCs *nc, LPSTR str)
1067 CHAR *p = strrchr(str, ',');
1069 nc->charset = -1;
1070 if(p && *(p+1)) {
1071 nc->charset = strtol(p+1, NULL, 10);
1072 *p = '\0';
1074 nc->name = towstr(CP_ACP, str);
1077 static void LoadSubstList(void)
1079 FontSubst *psub;
1080 HKEY hkey;
1081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1082 LPSTR value;
1083 LPVOID data;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey) == ERROR_SUCCESS) {
1089 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1090 &valuelen, &datalen, NULL, NULL);
1092 valuelen++; /* returned value doesn't include room for '\0' */
1093 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1094 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1096 dlen = datalen;
1097 vlen = valuelen;
1098 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1099 &dlen) == ERROR_SUCCESS) {
1100 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1102 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1103 split_subst_info(&psub->from, value);
1104 split_subst_info(&psub->to, data);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1109 psub->to.charset == DEFAULT_CHARSET) {
1110 HeapFree(GetProcessHeap(), 0, psub->to.name);
1111 HeapFree(GetProcessHeap(), 0, psub->from.name);
1112 HeapFree(GetProcessHeap(), 0, psub);
1113 } else {
1114 add_font_subst(&font_subst_list, psub, 0);
1116 /* reset dlen and vlen */
1117 dlen = datalen;
1118 vlen = valuelen;
1120 HeapFree(GetProcessHeap(), 0, data);
1121 HeapFree(GetProcessHeap(), 0, value);
1122 RegCloseKey(hkey);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1137 FT_SfntName name;
1138 FT_UInt num_names, name_index;
1140 if(FT_IS_SFNT(ft_face))
1142 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1144 for(name_index = 0; name_index < num_names; name_index++)
1146 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1148 if((name.platform_id == req->platform_id) &&
1149 (name.encoding_id == req->encoding_id) &&
1150 (name.language_id == req->language_id) &&
1151 (name.name_id == req->name_id))
1153 req->string = name.string;
1154 req->string_len = name.string_len;
1155 return TRUE;
1160 req->string = NULL;
1161 req->string_len = 0;
1162 return FALSE;
1165 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1167 WCHAR *ret = NULL;
1168 FT_SfntName name;
1170 name.platform_id = TT_PLATFORM_MICROSOFT;
1171 name.encoding_id = TT_MS_ID_UNICODE_CS;
1172 name.language_id = language_id;
1173 name.name_id = name_id;
1175 if(get_name_table_entry(ft_face, &name))
1177 FT_UInt i;
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1181 for(i = 0; i < name.string_len / 2; i++)
1183 WORD *tmp = (WORD *)&name.string[i * 2];
1184 ret[i] = GET_BE_WORD(*tmp);
1186 ret[i] = 0;
1187 TRACE("Got localised name %s\n", debugstr_w(ret));
1190 return ret;
1193 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1195 DWORD type, needed;
1196 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1197 if(r != ERROR_SUCCESS) return r;
1198 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1199 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1202 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1204 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1207 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1209 DWORD needed;
1210 DWORD num_strikes, max_strike_key_len;
1212 /* If we have a File Name key then this is a real font, not just the parent
1213 key of a bunch of non-scalable strikes */
1214 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1216 DWORD italic, bold;
1217 Face *face;
1218 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1219 face->cached_enum_data = NULL;
1221 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1222 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1224 face->StyleName = strdupW(face_name);
1225 face->family = family;
1226 face->vertical = (family->FamilyName[0] == '@');
1228 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1230 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1231 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1232 face->FullName = fullName;
1234 else
1235 face->FullName = NULL;
1237 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1238 reg_load_dword(hkey_face, face_italic_value, &italic);
1239 reg_load_dword(hkey_face, face_bold_value, &bold);
1240 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1241 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1243 needed = sizeof(face->fs);
1244 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1246 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1248 face->scalable = TRUE;
1249 memset(&face->size, 0, sizeof(face->size));
1251 else
1253 face->scalable = FALSE;
1254 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1255 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1256 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1257 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1258 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1260 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1261 face->size.height, face->size.width, face->size.size >> 6,
1262 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1265 face->ntmFlags = 0;
1266 if (italic) face->ntmFlags |= NTM_ITALIC;
1267 if (bold) face->ntmFlags |= NTM_BOLD;
1268 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1270 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1271 face->fs.fsCsb[0], face->fs.fsCsb[1],
1272 face->fs.fsUsb[0], face->fs.fsUsb[1],
1273 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1275 if(!italic && !bold)
1276 list_add_head(&family->faces, &face->entry);
1277 else
1278 list_add_tail(&family->faces, &face->entry);
1280 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1283 /* do we have any bitmap strikes? */
1284 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1285 NULL, NULL, NULL, NULL);
1286 if(num_strikes != 0)
1288 WCHAR strike_name[10];
1289 DWORD strike_index = 0;
1291 needed = sizeof(strike_name) / sizeof(WCHAR);
1292 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1293 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1295 HKEY hkey_strike;
1296 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1297 load_face(hkey_strike, face_name, family);
1298 RegCloseKey(hkey_strike);
1299 needed = sizeof(strike_name) / sizeof(WCHAR);
1304 static void load_font_list_from_cache(HKEY hkey_font_cache)
1306 DWORD max_family_key_len, size;
1307 WCHAR *family_name;
1308 DWORD family_index = 0;
1309 Family *family;
1310 HKEY hkey_family;
1312 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1313 NULL, NULL, NULL, NULL);
1314 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1316 size = max_family_key_len + 1;
1317 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1318 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1320 WCHAR *english_family = NULL;
1321 DWORD face_index = 0;
1322 WCHAR *face_name;
1323 DWORD max_face_key_len;
1325 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1326 TRACE("opened family key %s\n", debugstr_w(family_name));
1327 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1329 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1330 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1333 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1334 family->FamilyName = strdupW(family_name);
1335 family->EnglishName = english_family;
1336 list_init(&family->faces);
1337 family->replacement = &family->faces;
1338 list_add_tail(&font_list, &family->entry);
1340 if(english_family)
1342 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1343 subst->from.name = strdupW(english_family);
1344 subst->from.charset = -1;
1345 subst->to.name = strdupW(family_name);
1346 subst->to.charset = -1;
1347 add_font_subst(&font_subst_list, subst, 0);
1350 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1351 NULL, NULL, NULL, NULL);
1353 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1354 size = max_face_key_len + 1;
1355 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1356 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1358 HKEY hkey_face;
1360 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1361 load_face(hkey_face, face_name, family);
1362 RegCloseKey(hkey_face);
1363 size = max_face_key_len + 1;
1365 HeapFree(GetProcessHeap(), 0, face_name);
1366 RegCloseKey(hkey_family);
1367 size = max_family_key_len + 1;
1370 HeapFree(GetProcessHeap(), 0, family_name);
1373 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1375 LONG ret;
1376 HKEY hkey_wine_fonts;
1378 /* We don't want to create the fonts key as volatile, so open this first */
1379 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1380 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1381 if(ret != ERROR_SUCCESS)
1383 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1384 return ret;
1387 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1388 KEY_ALL_ACCESS, NULL, hkey, disposition);
1389 RegCloseKey(hkey_wine_fonts);
1390 return ret;
1393 static void add_face_to_cache(Face *face)
1395 HKEY hkey_font_cache, hkey_family, hkey_face;
1396 WCHAR *face_key_name;
1398 create_font_cache_key(&hkey_font_cache, NULL);
1400 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1401 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1402 if(face->family->EnglishName)
1403 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1404 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1406 if(face->scalable)
1407 face_key_name = face->StyleName;
1408 else
1410 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1411 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1412 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1414 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1415 &hkey_face, NULL);
1416 if(!face->scalable)
1417 HeapFree(GetProcessHeap(), 0, face_key_name);
1419 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1420 if (face->FullName)
1421 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1422 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1424 reg_save_dword(hkey_face, face_index_value, face->face_index);
1425 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1426 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1427 reg_save_dword(hkey_face, face_version_value, face->font_version);
1428 reg_save_dword(hkey_face, face_external_value, face->external);
1430 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1432 if(!face->scalable)
1434 reg_save_dword(hkey_face, face_height_value, face->size.height);
1435 reg_save_dword(hkey_face, face_width_value, face->size.width);
1436 reg_save_dword(hkey_face, face_size_value, face->size.size);
1437 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1438 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1439 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1441 RegCloseKey(hkey_face);
1442 RegCloseKey(hkey_family);
1443 RegCloseKey(hkey_font_cache);
1446 static inline int TestStyles(DWORD flags, DWORD styles)
1448 return (flags & styles) == styles;
1451 static int StyleOrdering(Face *face)
1453 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1454 return 3;
1455 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1456 return 2;
1457 if (TestStyles(face->ntmFlags, NTM_BOLD))
1458 return 1;
1459 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1460 return 0;
1462 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1463 debugstr_w(face->family->FamilyName),
1464 debugstr_w(face->StyleName),
1465 face->ntmFlags);
1467 return 9999;
1470 /* Add a style of face to a font family using an ordering of the list such
1471 that regular fonts come before bold and italic, and single styles come
1472 before compound styles. */
1473 static void AddFaceToFamily(Face *face, Family *family)
1475 struct list *entry;
1477 LIST_FOR_EACH( entry, &family->faces )
1479 Face *ent = LIST_ENTRY(entry, Face, entry);
1480 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1482 list_add_before( entry, &face->entry );
1485 static WCHAR *prepend_at(WCHAR *family)
1487 WCHAR *str;
1489 if (!family)
1490 return NULL;
1492 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1493 str[0] = '@';
1494 strcpyW(str + 1, family);
1495 HeapFree(GetProcessHeap(), 0, family);
1496 return str;
1499 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1501 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1502 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1504 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1505 if (!*name)
1507 *name = *english;
1508 *english = NULL;
1510 else if (!strcmpiW( *name, *english ))
1512 HeapFree( GetProcessHeap(), 0, *english );
1513 *english = NULL;
1516 if (vertical)
1518 *name = prepend_at( *name );
1519 *english = prepend_at( *english );
1523 /****************************************************************
1524 * NB This function stores the ptrs to the strings to save copying.
1525 * Don't free them after calling.
1527 static Family *create_family( WCHAR *name, WCHAR *english_name )
1529 Family *family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1530 family->FamilyName = name;
1531 family->EnglishName = english_name;
1532 list_init( &family->faces );
1533 family->replacement = &family->faces;
1535 return family;
1538 static Family *get_family( FT_Face ft_face, BOOL vertical )
1540 Family *family;
1541 WCHAR *name, *english_name;
1543 get_family_names( ft_face, &name, &english_name, vertical );
1545 family = find_family_from_name( name );
1547 if (!family)
1549 family = create_family( name, english_name );
1550 list_add_tail( &font_list, &family->entry );
1552 if (english_name)
1554 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1555 subst->from.name = strdupW( english_name );
1556 subst->from.charset = -1;
1557 subst->to.name = strdupW( name );
1558 subst->to.charset = -1;
1559 add_font_subst( &font_subst_list, subst, 0 );
1562 else
1564 HeapFree( GetProcessHeap(), 0, name );
1565 HeapFree( GetProcessHeap(), 0, english_name );
1568 return family;
1571 static inline FT_Fixed get_font_version( FT_Face ft_face )
1573 FT_Fixed version = 0;
1574 TT_Header *header;
1576 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1577 if (header) version = header->Font_Revision;
1579 return version;
1582 static inline DWORD get_ntm_flags( FT_Face ft_face )
1584 DWORD flags = 0;
1585 FT_ULong table_size = 0;
1587 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1588 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1589 if (flags == 0) flags = NTM_REGULAR;
1591 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1592 flags |= NTM_PS_OPENTYPE;
1594 return flags;
1597 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1599 int internal_leading = 0;
1600 FT_WinFNT_HeaderRec winfnt_header;
1602 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1603 internal_leading = winfnt_header.internal_leading;
1605 return internal_leading;
1608 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1610 TT_OS2 *os2;
1611 FT_UInt dummy;
1612 CHARSETINFO csi;
1613 FT_WinFNT_HeaderRec winfnt_header;
1614 int i;
1616 memset( fs, 0, sizeof(*fs) );
1618 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1619 if (os2)
1621 fs->fsUsb[0] = os2->ulUnicodeRange1;
1622 fs->fsUsb[1] = os2->ulUnicodeRange2;
1623 fs->fsUsb[2] = os2->ulUnicodeRange3;
1624 fs->fsUsb[3] = os2->ulUnicodeRange4;
1626 if (os2->version == 0)
1628 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1629 fs->fsCsb[0] = FS_LATIN1;
1630 else
1631 fs->fsCsb[0] = FS_SYMBOL;
1633 else
1635 fs->fsCsb[0] = os2->ulCodePageRange1;
1636 fs->fsCsb[1] = os2->ulCodePageRange2;
1639 else
1641 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1643 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1644 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1645 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1646 *fs = csi.fs;
1650 if (fs->fsCsb[0] == 0)
1652 /* let's see if we can find any interesting cmaps */
1653 for (i = 0; i < ft_face->num_charmaps; i++)
1655 switch (ft_face->charmaps[i]->encoding)
1657 case FT_ENCODING_UNICODE:
1658 case FT_ENCODING_APPLE_ROMAN:
1659 fs->fsCsb[0] |= FS_LATIN1;
1660 break;
1661 case FT_ENCODING_MS_SYMBOL:
1662 fs->fsCsb[0] |= FS_SYMBOL;
1663 break;
1664 default:
1665 break;
1671 static inline void free_face( Face *face )
1673 HeapFree( GetProcessHeap(), 0, face->file );
1674 HeapFree( GetProcessHeap(), 0, face->StyleName );
1675 HeapFree( GetProcessHeap(), 0, face->FullName );
1676 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1677 HeapFree( GetProcessHeap(), 0, face );
1680 #define ADDFONT_EXTERNAL_FONT 0x01
1681 #define ADDFONT_FORCE_BITMAP 0x02
1682 #define ADDFONT_ADD_TO_CACHE 0x04
1684 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size, FT_Long face_index, DWORD flags, BOOL vertical)
1686 int bitmap_num = 0;
1687 Family *family;
1688 WCHAR *StyleW;
1690 do {
1691 Face *face;
1692 struct list *face_elem_ptr;
1693 FONTSIGNATURE fs;
1694 My_FT_Bitmap_Size *size = NULL;
1695 FT_Fixed version;
1697 if(!FT_IS_SCALABLE(ft_face))
1698 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1700 family = get_family( ft_face, vertical );
1702 StyleW = towstr(CP_ACP, ft_face->style_name);
1704 get_fontsig( ft_face, &fs );
1706 version = get_font_version( ft_face );
1707 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1708 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1709 if(!strcmpiW(face->StyleName, StyleW) &&
1710 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1711 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1712 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1713 face->font_version, version);
1714 if(version <= face->font_version) {
1715 TRACE("Original font is newer so skipping this one\n");
1716 HeapFree(GetProcessHeap(), 0, StyleW);
1717 return;
1718 } else {
1719 TRACE("Replacing original with this one\n");
1720 list_remove(&face->entry);
1721 free_face( face );
1722 break;
1726 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1727 face->cached_enum_data = NULL;
1728 face->StyleName = StyleW;
1729 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1730 if (file)
1732 face->file = strdupA(file);
1733 face->font_data_ptr = NULL;
1734 face->font_data_size = 0;
1736 else
1738 face->file = NULL;
1739 face->font_data_ptr = font_data_ptr;
1740 face->font_data_size = font_data_size;
1742 face->face_index = face_index;
1743 face->ntmFlags = get_ntm_flags( ft_face );
1744 face->font_version = version;
1745 face->family = family;
1746 face->vertical = vertical;
1747 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1748 face->fs = fs;
1750 if(FT_IS_SCALABLE(ft_face)) {
1751 memset(&face->size, 0, sizeof(face->size));
1752 face->scalable = TRUE;
1753 } else {
1754 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1755 size->height, size->width, size->size >> 6,
1756 size->x_ppem >> 6, size->y_ppem >> 6);
1757 face->size.height = size->height;
1758 face->size.width = size->width;
1759 face->size.size = size->size;
1760 face->size.x_ppem = size->x_ppem;
1761 face->size.y_ppem = size->y_ppem;
1762 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1763 face->scalable = FALSE;
1766 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1767 face->fs.fsCsb[0], face->fs.fsCsb[1],
1768 face->fs.fsUsb[0], face->fs.fsUsb[1],
1769 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1771 if(flags & ADDFONT_ADD_TO_CACHE)
1772 add_face_to_cache(face);
1774 AddFaceToFamily(face, family);
1776 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1778 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1779 debugstr_w(StyleW));
1782 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1784 FT_Face ft_face;
1785 TT_OS2 *pOS2;
1786 FT_Error err;
1787 FT_Long face_index = 0, num_faces;
1788 INT ret = 0;
1790 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1791 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1793 #ifdef HAVE_CARBON_CARBON_H
1794 if(file)
1796 char **mac_list = expand_mac_font(file);
1797 if(mac_list)
1799 BOOL had_one = FALSE;
1800 char **cursor;
1801 for(cursor = mac_list; *cursor; cursor++)
1803 had_one = TRUE;
1804 AddFontToList(*cursor, NULL, 0, flags);
1805 HeapFree(GetProcessHeap(), 0, *cursor);
1807 HeapFree(GetProcessHeap(), 0, mac_list);
1808 if(had_one)
1809 return 1;
1812 #endif /* HAVE_CARBON_CARBON_H */
1814 do {
1815 if (file)
1817 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1818 err = pFT_New_Face(library, file, face_index, &ft_face);
1819 } else
1821 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1822 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1825 if(err != 0) {
1826 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1827 return 0;
1830 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1831 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1832 pFT_Done_Face(ft_face);
1833 return 0;
1836 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1837 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1838 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1839 pFT_Done_Face(ft_face);
1840 return 0;
1843 if(FT_IS_SFNT(ft_face))
1845 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1846 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1847 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))
1849 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1850 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1851 pFT_Done_Face(ft_face);
1852 return 0;
1855 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1856 we don't want to load these. */
1857 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1859 FT_ULong len = 0;
1861 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1863 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1864 pFT_Done_Face(ft_face);
1865 return 0;
1870 if(!ft_face->family_name || !ft_face->style_name) {
1871 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1872 pFT_Done_Face(ft_face);
1873 return 0;
1876 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1878 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1879 pFT_Done_Face(ft_face);
1880 return 0;
1883 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1884 ++ret;
1886 if (FT_HAS_VERTICAL(ft_face))
1888 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1889 ++ret;
1892 num_faces = ft_face->num_faces;
1893 pFT_Done_Face(ft_face);
1894 } while(num_faces > ++face_index);
1895 return ret;
1898 static void DumpFontList(void)
1900 Family *family;
1901 Face *face;
1902 struct list *family_elem_ptr, *face_elem_ptr;
1904 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1905 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1906 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1907 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1908 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1909 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1910 if(!face->scalable)
1911 TRACE(" %d", face->size.height);
1912 TRACE("\n");
1915 return;
1918 /***********************************************************
1919 * The replacement list is a way to map an entire font
1920 * family onto another family. For example adding
1922 * [HKCU\Software\Wine\Fonts\Replacements]
1923 * "Wingdings"="Winedings"
1925 * would enumerate the Winedings font both as Winedings and
1926 * Wingdings. However if a real Wingdings font is present the
1927 * replacement does not take place.
1930 static void LoadReplaceList(void)
1932 HKEY hkey;
1933 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1934 LPWSTR value;
1935 LPVOID data;
1936 CHAR familyA[400];
1938 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1939 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1941 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1942 &valuelen, &datalen, NULL, NULL);
1944 valuelen++; /* returned value doesn't include room for '\0' */
1945 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1946 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1948 dlen = datalen;
1949 vlen = valuelen;
1950 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1951 &dlen) == ERROR_SUCCESS) {
1952 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1953 /* "NewName"="Oldname" */
1954 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1956 if(!find_family_from_any_name(value))
1958 Family * const family = find_family_from_any_name(data);
1959 if (family != NULL)
1961 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1962 if (new_family != NULL)
1964 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1965 new_family->FamilyName = strdupW(value);
1966 new_family->EnglishName = NULL;
1967 list_init(&new_family->faces);
1968 new_family->replacement = &family->faces;
1969 list_add_tail(&font_list, &new_family->entry);
1972 else
1974 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1977 else
1979 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1981 /* reset dlen and vlen */
1982 dlen = datalen;
1983 vlen = valuelen;
1985 HeapFree(GetProcessHeap(), 0, data);
1986 HeapFree(GetProcessHeap(), 0, value);
1987 RegCloseKey(hkey);
1991 static const WCHAR *font_links_list[] =
1993 Lucida_Sans_Unicode,
1994 Microsoft_Sans_Serif,
1995 Tahoma
1998 static const struct font_links_defaults_list
2000 /* Keyed off substitution for "MS Shell Dlg" */
2001 const WCHAR *shelldlg;
2002 /* Maximum of four substitutes, plus terminating NULL pointer */
2003 const WCHAR *substitutes[5];
2004 } font_links_defaults_list[] =
2006 /* Non East-Asian */
2007 { Tahoma, /* FIXME unverified ordering */
2008 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2010 /* Below lists are courtesy of
2011 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2013 /* Japanese */
2014 { MS_UI_Gothic,
2015 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2017 /* Chinese Simplified */
2018 { SimSun,
2019 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2021 /* Korean */
2022 { Gulim,
2023 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2025 /* Chinese Traditional */
2026 { PMingLiU,
2027 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2032 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2034 SYSTEM_LINKS *font_link;
2036 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2038 if(!strcmpiW(font_link->font_name, name))
2039 return font_link;
2042 return NULL;
2045 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2047 const WCHAR *value;
2048 int i;
2049 FontSubst *psub;
2050 Family *family;
2051 Face *face;
2052 const char *file;
2053 WCHAR *fileW;
2055 if (values)
2057 SYSTEM_LINKS *font_link;
2059 psub = get_font_subst(&font_subst_list, name, -1);
2060 /* Don't store fonts that are only substitutes for other fonts */
2061 if(psub)
2063 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2064 return;
2067 font_link = find_font_link(name);
2068 if (font_link == NULL)
2070 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2071 font_link->font_name = strdupW(name);
2072 list_init(&font_link->links);
2073 list_add_tail(&system_links, &font_link->entry);
2076 memset(&font_link->fs, 0, sizeof font_link->fs);
2077 for (i = 0; values[i] != NULL; i++)
2079 const struct list *face_list;
2080 CHILD_FONT *child_font;
2082 value = values[i];
2083 if (!strcmpiW(name,value))
2084 continue;
2085 psub = get_font_subst(&font_subst_list, value, -1);
2086 if(psub)
2087 value = psub->to.name;
2088 family = find_family_from_name(value);
2089 if (!family)
2090 continue;
2091 file = NULL;
2092 /* Use first extant filename for this Family */
2093 face_list = get_face_list_from_family(family);
2094 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2096 if (!face->file)
2097 continue;
2098 file = strrchr(face->file, '/');
2099 if (!file)
2100 file = face->file;
2101 else
2102 file++;
2103 break;
2105 if (!file)
2106 continue;
2107 fileW = towstr(CP_UNIXCP, file);
2109 face = find_face_from_filename(fileW, value);
2110 if(!face)
2112 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2113 continue;
2116 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2117 child_font->face = face;
2118 child_font->font = NULL;
2119 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2120 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2121 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2122 list_add_tail(&font_link->links, &child_font->entry);
2124 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2125 HeapFree(GetProcessHeap(), 0, fileW);
2131 /*************************************************************
2132 * init_system_links
2134 static BOOL init_system_links(void)
2136 HKEY hkey;
2137 BOOL ret = FALSE;
2138 DWORD type, max_val, max_data, val_len, data_len, index;
2139 WCHAR *value, *data;
2140 WCHAR *entry, *next;
2141 SYSTEM_LINKS *font_link, *system_font_link;
2142 CHILD_FONT *child_font;
2143 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2144 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2145 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2146 Face *face;
2147 FontSubst *psub;
2148 UINT i, j;
2150 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2152 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2153 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2154 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2155 val_len = max_val + 1;
2156 data_len = max_data;
2157 index = 0;
2158 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2160 psub = get_font_subst(&font_subst_list, value, -1);
2161 /* Don't store fonts that are only substitutes for other fonts */
2162 if(psub)
2164 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2165 goto next;
2167 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2168 font_link->font_name = strdupW(value);
2169 memset(&font_link->fs, 0, sizeof font_link->fs);
2170 list_init(&font_link->links);
2171 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2173 WCHAR *face_name;
2174 CHILD_FONT *child_font;
2176 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2178 next = entry + strlenW(entry) + 1;
2180 face_name = strchrW(entry, ',');
2181 if(face_name)
2183 *face_name++ = 0;
2184 while(isspaceW(*face_name))
2185 face_name++;
2187 psub = get_font_subst(&font_subst_list, face_name, -1);
2188 if(psub)
2189 face_name = psub->to.name;
2191 face = find_face_from_filename(entry, face_name);
2192 if(!face)
2194 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2195 continue;
2198 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2199 child_font->face = face;
2200 child_font->font = NULL;
2201 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2202 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2203 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2204 list_add_tail(&font_link->links, &child_font->entry);
2206 list_add_tail(&system_links, &font_link->entry);
2207 next:
2208 val_len = max_val + 1;
2209 data_len = max_data;
2212 HeapFree(GetProcessHeap(), 0, value);
2213 HeapFree(GetProcessHeap(), 0, data);
2214 RegCloseKey(hkey);
2218 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2219 if (!psub) {
2220 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2221 goto skip_internal;
2224 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2226 const FontSubst *psub2;
2227 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2229 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2231 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2232 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2234 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2235 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2237 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2239 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2243 skip_internal:
2245 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2246 that Tahoma has */
2248 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2249 system_font_link->font_name = strdupW(System);
2250 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2251 list_init(&system_font_link->links);
2253 face = find_face_from_filename(tahoma_ttf, Tahoma);
2254 if(face)
2256 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2257 child_font->face = face;
2258 child_font->font = NULL;
2259 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2260 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2261 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2262 list_add_tail(&system_font_link->links, &child_font->entry);
2264 font_link = find_font_link(Tahoma);
2265 if (font_link != NULL)
2267 CHILD_FONT *font_link_entry;
2268 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2270 CHILD_FONT *new_child;
2271 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2272 new_child->face = font_link_entry->face;
2273 new_child->font = NULL;
2274 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2275 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2276 list_add_tail(&system_font_link->links, &new_child->entry);
2279 list_add_tail(&system_links, &system_font_link->entry);
2280 return ret;
2283 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2285 DIR *dir;
2286 struct dirent *dent;
2287 char path[MAX_PATH];
2289 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2291 dir = opendir(dirname);
2292 if(!dir) {
2293 WARN("Can't open directory %s\n", debugstr_a(dirname));
2294 return FALSE;
2296 while((dent = readdir(dir)) != NULL) {
2297 struct stat statbuf;
2299 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2300 continue;
2302 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2304 sprintf(path, "%s/%s", dirname, dent->d_name);
2306 if(stat(path, &statbuf) == -1)
2308 WARN("Can't stat %s\n", debugstr_a(path));
2309 continue;
2311 if(S_ISDIR(statbuf.st_mode))
2312 ReadFontDir(path, external_fonts);
2313 else
2315 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2316 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2317 AddFontToList(path, NULL, 0, addfont_flags);
2320 closedir(dir);
2321 return TRUE;
2324 static void load_fontconfig_fonts(void)
2326 #ifdef SONAME_LIBFONTCONFIG
2327 void *fc_handle = NULL;
2328 FcConfig *config;
2329 FcPattern *pat;
2330 FcObjectSet *os;
2331 FcFontSet *fontset;
2332 int i, len;
2333 char *file;
2334 const char *ext;
2336 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2337 if(!fc_handle) {
2338 TRACE("Wine cannot find the fontconfig library (%s).\n",
2339 SONAME_LIBFONTCONFIG);
2340 return;
2342 #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;}
2343 LOAD_FUNCPTR(FcConfigGetCurrent);
2344 LOAD_FUNCPTR(FcFontList);
2345 LOAD_FUNCPTR(FcFontSetDestroy);
2346 LOAD_FUNCPTR(FcInit);
2347 LOAD_FUNCPTR(FcObjectSetAdd);
2348 LOAD_FUNCPTR(FcObjectSetCreate);
2349 LOAD_FUNCPTR(FcObjectSetDestroy);
2350 LOAD_FUNCPTR(FcPatternCreate);
2351 LOAD_FUNCPTR(FcPatternDestroy);
2352 LOAD_FUNCPTR(FcPatternGetBool);
2353 LOAD_FUNCPTR(FcPatternGetString);
2354 #undef LOAD_FUNCPTR
2356 if(!pFcInit()) return;
2358 config = pFcConfigGetCurrent();
2359 pat = pFcPatternCreate();
2360 os = pFcObjectSetCreate();
2361 pFcObjectSetAdd(os, FC_FILE);
2362 pFcObjectSetAdd(os, FC_SCALABLE);
2363 fontset = pFcFontList(config, pat, os);
2364 if(!fontset) return;
2365 for(i = 0; i < fontset->nfont; i++) {
2366 FcBool scalable;
2368 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2369 continue;
2370 TRACE("fontconfig: %s\n", file);
2372 /* We're just interested in OT/TT fonts for now, so this hack just
2373 picks up the scalable fonts without extensions .pf[ab] to save time
2374 loading every other font */
2376 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2378 TRACE("not scalable\n");
2379 continue;
2382 len = strlen( file );
2383 if(len < 4) continue;
2384 ext = &file[ len - 3 ];
2385 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2386 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2388 pFcFontSetDestroy(fontset);
2389 pFcObjectSetDestroy(os);
2390 pFcPatternDestroy(pat);
2391 sym_not_found:
2392 #endif
2393 return;
2396 static BOOL load_font_from_data_dir(LPCWSTR file)
2398 BOOL ret = FALSE;
2399 const char *data_dir = wine_get_data_dir();
2401 if (!data_dir) data_dir = wine_get_build_dir();
2403 if (data_dir)
2405 INT len;
2406 char *unix_name;
2408 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2410 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2412 strcpy(unix_name, data_dir);
2413 strcat(unix_name, "/fonts/");
2415 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2417 EnterCriticalSection( &freetype_cs );
2418 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2419 LeaveCriticalSection( &freetype_cs );
2420 HeapFree(GetProcessHeap(), 0, unix_name);
2422 return ret;
2425 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2427 static const WCHAR slashW[] = {'\\','\0'};
2428 BOOL ret = FALSE;
2429 WCHAR windowsdir[MAX_PATH];
2430 char *unixname;
2432 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2433 strcatW(windowsdir, fontsW);
2434 strcatW(windowsdir, slashW);
2435 strcatW(windowsdir, file);
2436 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2437 EnterCriticalSection( &freetype_cs );
2438 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2439 LeaveCriticalSection( &freetype_cs );
2440 HeapFree(GetProcessHeap(), 0, unixname);
2442 return ret;
2445 static void load_system_fonts(void)
2447 HKEY hkey;
2448 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2449 const WCHAR * const *value;
2450 DWORD dlen, type;
2451 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2452 char *unixname;
2454 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2455 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2456 strcatW(windowsdir, fontsW);
2457 for(value = SystemFontValues; *value; value++) {
2458 dlen = sizeof(data);
2459 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2460 type == REG_SZ) {
2461 BOOL added = FALSE;
2463 sprintfW(pathW, fmtW, windowsdir, data);
2464 if((unixname = wine_get_unix_file_name(pathW))) {
2465 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2466 HeapFree(GetProcessHeap(), 0, unixname);
2468 if (!added)
2469 load_font_from_data_dir(data);
2472 RegCloseKey(hkey);
2476 /*************************************************************
2478 * This adds registry entries for any externally loaded fonts
2479 * (fonts from fontconfig or FontDirs). It also deletes entries
2480 * of no longer existing fonts.
2483 static void update_reg_entries(void)
2485 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2486 LPWSTR valueW;
2487 DWORD len, len_fam;
2488 Family *family;
2489 Face *face;
2490 struct list *family_elem_ptr, *face_elem_ptr;
2491 WCHAR *file;
2492 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2493 static const WCHAR spaceW[] = {' ', '\0'};
2494 char *path;
2496 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2497 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2498 ERR("Can't create Windows font reg key\n");
2499 goto end;
2502 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2503 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2504 ERR("Can't create Windows font reg key\n");
2505 goto end;
2508 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2509 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2510 ERR("Can't create external font reg key\n");
2511 goto end;
2514 /* enumerate the fonts and add external ones to the two keys */
2516 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2517 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2518 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2519 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2520 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2521 if(!face->external) continue;
2522 len = len_fam;
2523 if (!(face->ntmFlags & NTM_REGULAR))
2524 len = len_fam + strlenW(face->StyleName) + 1;
2525 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2526 strcpyW(valueW, family->FamilyName);
2527 if(len != len_fam) {
2528 strcatW(valueW, spaceW);
2529 strcatW(valueW, face->StyleName);
2531 strcatW(valueW, TrueType);
2533 file = wine_get_dos_file_name(face->file);
2534 if(file)
2535 len = strlenW(file) + 1;
2536 else
2538 if((path = strrchr(face->file, '/')) == NULL)
2539 path = face->file;
2540 else
2541 path++;
2542 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2544 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2545 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2547 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2548 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2549 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2551 HeapFree(GetProcessHeap(), 0, file);
2552 HeapFree(GetProcessHeap(), 0, valueW);
2555 end:
2556 if(external_key) RegCloseKey(external_key);
2557 if(win9x_key) RegCloseKey(win9x_key);
2558 if(winnt_key) RegCloseKey(winnt_key);
2559 return;
2562 static void delete_external_font_keys(void)
2564 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2565 DWORD dlen, vlen, datalen, valuelen, i, type;
2566 LPWSTR valueW;
2567 LPVOID data;
2569 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2570 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2571 ERR("Can't create Windows font reg key\n");
2572 goto end;
2575 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2576 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2577 ERR("Can't create Windows font reg key\n");
2578 goto end;
2581 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2582 ERR("Can't create external font reg key\n");
2583 goto end;
2586 /* Delete all external fonts added last time */
2588 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2589 &valuelen, &datalen, NULL, NULL);
2590 valuelen++; /* returned value doesn't include room for '\0' */
2591 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2592 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2594 dlen = datalen * sizeof(WCHAR);
2595 vlen = valuelen;
2596 i = 0;
2597 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2598 &dlen) == ERROR_SUCCESS) {
2600 RegDeleteValueW(winnt_key, valueW);
2601 RegDeleteValueW(win9x_key, valueW);
2602 /* reset dlen and vlen */
2603 dlen = datalen;
2604 vlen = valuelen;
2606 HeapFree(GetProcessHeap(), 0, data);
2607 HeapFree(GetProcessHeap(), 0, valueW);
2609 /* Delete the old external fonts key */
2610 RegCloseKey(external_key);
2611 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2613 end:
2614 if(win9x_key) RegCloseKey(win9x_key);
2615 if(winnt_key) RegCloseKey(winnt_key);
2618 /*************************************************************
2619 * WineEngAddFontResourceEx
2622 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2624 INT ret = 0;
2626 GDI_CheckNotLock();
2628 if (ft_handle) /* do it only if we have freetype up and running */
2630 char *unixname;
2632 if(flags)
2633 FIXME("Ignoring flags %x\n", flags);
2635 if((unixname = wine_get_unix_file_name(file)))
2637 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2639 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2640 EnterCriticalSection( &freetype_cs );
2641 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2642 LeaveCriticalSection( &freetype_cs );
2643 HeapFree(GetProcessHeap(), 0, unixname);
2645 if (!ret && !strchrW(file, '\\')) {
2646 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2647 ret = load_font_from_winfonts_dir(file);
2648 if (!ret) {
2649 /* Try in datadir/fonts (or builddir/fonts),
2650 * needed for Magic the Gathering Online
2652 ret = load_font_from_data_dir(file);
2656 return ret;
2659 /*************************************************************
2660 * WineEngAddFontMemResourceEx
2663 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2665 GDI_CheckNotLock();
2667 if (ft_handle) /* do it only if we have freetype up and running */
2669 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2671 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2672 memcpy(pFontCopy, pbFont, cbFont);
2674 EnterCriticalSection( &freetype_cs );
2675 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2676 LeaveCriticalSection( &freetype_cs );
2678 if (*pcFonts == 0)
2680 TRACE("AddFontToList failed\n");
2681 HeapFree(GetProcessHeap(), 0, pFontCopy);
2682 return 0;
2684 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2685 * For now return something unique but quite random
2687 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2688 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2691 *pcFonts = 0;
2692 return 0;
2695 /*************************************************************
2696 * WineEngRemoveFontResourceEx
2699 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2701 GDI_CheckNotLock();
2702 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2703 return TRUE;
2706 static const struct nls_update_font_list
2708 UINT ansi_cp, oem_cp;
2709 const char *oem, *fixed, *system;
2710 const char *courier, *serif, *small, *sserif;
2711 /* these are for font substitutes */
2712 const char *shelldlg, *tmsrmn;
2713 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2714 *helv_0, *tmsrmn_0;
2715 const struct subst
2717 const char *from, *to;
2718 } arial_0, courier_new_0, times_new_roman_0;
2719 } nls_update_font_list[] =
2721 /* Latin 1 (United States) */
2722 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2723 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2724 "Tahoma","Times New Roman",
2725 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2726 { 0 }, { 0 }, { 0 }
2728 /* Latin 1 (Multilingual) */
2729 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2730 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2731 "Tahoma","Times New Roman", /* FIXME unverified */
2732 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2733 { 0 }, { 0 }, { 0 }
2735 /* Eastern Europe */
2736 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2737 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2738 "Tahoma","Times New Roman", /* FIXME unverified */
2739 "Fixedsys,238", "System,238",
2740 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2741 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2742 { "Arial CE,0", "Arial,238" },
2743 { "Courier New CE,0", "Courier New,238" },
2744 { "Times New Roman CE,0", "Times New Roman,238" }
2746 /* Cyrillic */
2747 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2748 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2749 "Tahoma","Times New Roman", /* FIXME unverified */
2750 "Fixedsys,204", "System,204",
2751 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2752 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2753 { "Arial Cyr,0", "Arial,204" },
2754 { "Courier New Cyr,0", "Courier New,204" },
2755 { "Times New Roman Cyr,0", "Times New Roman,204" }
2757 /* Greek */
2758 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2759 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2760 "Tahoma","Times New Roman", /* FIXME unverified */
2761 "Fixedsys,161", "System,161",
2762 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2763 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2764 { "Arial Greek,0", "Arial,161" },
2765 { "Courier New Greek,0", "Courier New,161" },
2766 { "Times New Roman Greek,0", "Times New Roman,161" }
2768 /* Turkish */
2769 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2770 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2771 "Tahoma","Times New Roman", /* FIXME unverified */
2772 "Fixedsys,162", "System,162",
2773 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2774 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2775 { "Arial Tur,0", "Arial,162" },
2776 { "Courier New Tur,0", "Courier New,162" },
2777 { "Times New Roman Tur,0", "Times New Roman,162" }
2779 /* Hebrew */
2780 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2781 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2782 "Tahoma","Times New Roman", /* FIXME unverified */
2783 "Fixedsys,177", "System,177",
2784 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2785 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2786 { 0 }, { 0 }, { 0 }
2788 /* Arabic */
2789 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2790 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2791 "Tahoma","Times New Roman", /* FIXME unverified */
2792 "Fixedsys,178", "System,178",
2793 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2794 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2795 { 0 }, { 0 }, { 0 }
2797 /* Baltic */
2798 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2799 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2800 "Tahoma","Times New Roman", /* FIXME unverified */
2801 "Fixedsys,186", "System,186",
2802 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2803 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2804 { "Arial Baltic,0", "Arial,186" },
2805 { "Courier New Baltic,0", "Courier New,186" },
2806 { "Times New Roman Baltic,0", "Times New Roman,186" }
2808 /* Vietnamese */
2809 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2810 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2811 "Tahoma","Times New Roman", /* FIXME unverified */
2812 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2813 { 0 }, { 0 }, { 0 }
2815 /* Thai */
2816 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2817 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2818 "Tahoma","Times New Roman", /* FIXME unverified */
2819 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2820 { 0 }, { 0 }, { 0 }
2822 /* Japanese */
2823 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2824 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2825 "MS UI Gothic","MS Serif",
2826 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2827 { 0 }, { 0 }, { 0 }
2829 /* Chinese Simplified */
2830 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2831 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2832 "SimSun", "NSimSun",
2833 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2834 { 0 }, { 0 }, { 0 }
2836 /* Korean */
2837 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2838 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2839 "Gulim", "Batang",
2840 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2841 { 0 }, { 0 }, { 0 }
2843 /* Chinese Traditional */
2844 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2845 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2846 "PMingLiU", "MingLiU",
2847 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2848 { 0 }, { 0 }, { 0 }
2852 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2854 return ( ansi_cp == 932 /* CP932 for Japanese */
2855 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2856 || ansi_cp == 949 /* CP949 for Korean */
2857 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2860 static inline HKEY create_fonts_NT_registry_key(void)
2862 HKEY hkey = 0;
2864 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2865 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2866 return hkey;
2869 static inline HKEY create_fonts_9x_registry_key(void)
2871 HKEY hkey = 0;
2873 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2874 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2875 return hkey;
2878 static inline HKEY create_config_fonts_registry_key(void)
2880 HKEY hkey = 0;
2882 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2883 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2884 return hkey;
2887 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2889 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2890 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2891 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2892 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2895 static void set_value_key(HKEY hkey, const char *name, const char *value)
2897 if (value)
2898 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2899 else if (name)
2900 RegDeleteValueA(hkey, name);
2903 static void update_font_info(void)
2905 char buf[40], cpbuf[40];
2906 DWORD len, type;
2907 HKEY hkey = 0;
2908 UINT i, ansi_cp = 0, oem_cp = 0;
2909 BOOL done = FALSE;
2911 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2912 return;
2914 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2915 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2916 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2917 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2918 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2920 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2921 if (is_dbcs_ansi_cp(ansi_cp))
2922 use_default_fallback = TRUE;
2924 len = sizeof(buf);
2925 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2927 if (!strcmp( buf, cpbuf )) /* already set correctly */
2929 RegCloseKey(hkey);
2930 return;
2932 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2934 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2936 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2937 RegCloseKey(hkey);
2939 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2941 HKEY hkey;
2943 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2944 nls_update_font_list[i].oem_cp == oem_cp)
2946 hkey = create_config_fonts_registry_key();
2947 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2948 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2949 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2950 RegCloseKey(hkey);
2952 hkey = create_fonts_NT_registry_key();
2953 add_font_list(hkey, &nls_update_font_list[i]);
2954 RegCloseKey(hkey);
2956 hkey = create_fonts_9x_registry_key();
2957 add_font_list(hkey, &nls_update_font_list[i]);
2958 RegCloseKey(hkey);
2960 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2962 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2963 strlen(nls_update_font_list[i].shelldlg)+1);
2964 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2965 strlen(nls_update_font_list[i].tmsrmn)+1);
2967 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2968 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2969 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2970 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2971 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2972 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2973 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2974 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2976 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2977 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2978 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2980 RegCloseKey(hkey);
2982 done = TRUE;
2984 else
2986 /* Delete the FontSubstitutes from other locales */
2987 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2989 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2990 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2991 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2992 RegCloseKey(hkey);
2996 if (!done)
2997 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3000 static BOOL init_freetype(void)
3002 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3003 if(!ft_handle) {
3004 WINE_MESSAGE(
3005 "Wine cannot find the FreeType font library. To enable Wine to\n"
3006 "use TrueType fonts please install a version of FreeType greater than\n"
3007 "or equal to 2.0.5.\n"
3008 "http://www.freetype.org\n");
3009 return FALSE;
3012 #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;}
3014 LOAD_FUNCPTR(FT_Done_Face)
3015 LOAD_FUNCPTR(FT_Get_Char_Index)
3016 LOAD_FUNCPTR(FT_Get_First_Char)
3017 LOAD_FUNCPTR(FT_Get_Module)
3018 LOAD_FUNCPTR(FT_Get_Next_Char)
3019 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3020 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3021 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3022 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3023 LOAD_FUNCPTR(FT_Init_FreeType)
3024 LOAD_FUNCPTR(FT_Library_Version)
3025 LOAD_FUNCPTR(FT_Load_Glyph)
3026 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3027 LOAD_FUNCPTR(FT_Matrix_Multiply)
3028 #ifndef FT_MULFIX_INLINED
3029 LOAD_FUNCPTR(FT_MulFix)
3030 #endif
3031 LOAD_FUNCPTR(FT_New_Face)
3032 LOAD_FUNCPTR(FT_New_Memory_Face)
3033 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3034 LOAD_FUNCPTR(FT_Outline_Transform)
3035 LOAD_FUNCPTR(FT_Outline_Translate)
3036 LOAD_FUNCPTR(FT_Render_Glyph)
3037 LOAD_FUNCPTR(FT_Select_Charmap)
3038 LOAD_FUNCPTR(FT_Set_Charmap)
3039 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3040 LOAD_FUNCPTR(FT_Vector_Transform)
3041 LOAD_FUNCPTR(FT_Vector_Unit)
3042 #undef LOAD_FUNCPTR
3043 /* Don't warn if these ones are missing */
3044 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3045 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3046 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3047 #endif
3049 if(pFT_Init_FreeType(&library) != 0) {
3050 ERR("Can't init FreeType library\n");
3051 wine_dlclose(ft_handle, NULL, 0);
3052 ft_handle = NULL;
3053 return FALSE;
3055 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3057 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3058 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3059 ((FT_Version.minor << 8) & 0x00ff00) |
3060 ((FT_Version.patch ) & 0x0000ff);
3062 font_driver = &freetype_funcs;
3063 return TRUE;
3065 sym_not_found:
3066 WINE_MESSAGE(
3067 "Wine cannot find certain functions that it needs inside the FreeType\n"
3068 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3069 "FreeType to at least version 2.1.4.\n"
3070 "http://www.freetype.org\n");
3071 wine_dlclose(ft_handle, NULL, 0);
3072 ft_handle = NULL;
3073 return FALSE;
3076 static void init_font_list(void)
3078 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3079 static const WCHAR pathW[] = {'P','a','t','h',0};
3080 HKEY hkey;
3081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3082 WCHAR windowsdir[MAX_PATH];
3083 char *unixname;
3084 const char *home;
3085 const char *data_dir;
3087 delete_external_font_keys();
3089 /* load the system bitmap fonts */
3090 load_system_fonts();
3092 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3093 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3094 strcatW(windowsdir, fontsW);
3095 if((unixname = wine_get_unix_file_name(windowsdir)))
3097 ReadFontDir(unixname, FALSE);
3098 HeapFree(GetProcessHeap(), 0, unixname);
3101 /* load the system truetype fonts */
3102 data_dir = wine_get_data_dir();
3103 if (!data_dir) data_dir = wine_get_build_dir();
3104 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3106 strcpy(unixname, data_dir);
3107 strcat(unixname, "/fonts/");
3108 ReadFontDir(unixname, TRUE);
3109 HeapFree(GetProcessHeap(), 0, unixname);
3112 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3113 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3114 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3115 will skip these. */
3116 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3117 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3118 &hkey) == ERROR_SUCCESS)
3120 LPWSTR data, valueW;
3121 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3122 &valuelen, &datalen, NULL, NULL);
3124 valuelen++; /* returned value doesn't include room for '\0' */
3125 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3126 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3127 if (valueW && data)
3129 dlen = datalen * sizeof(WCHAR);
3130 vlen = valuelen;
3131 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3132 &dlen) == ERROR_SUCCESS)
3134 if(data[0] && (data[1] == ':'))
3136 if((unixname = wine_get_unix_file_name(data)))
3138 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3139 HeapFree(GetProcessHeap(), 0, unixname);
3142 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3144 WCHAR pathW[MAX_PATH];
3145 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3146 BOOL added = FALSE;
3148 sprintfW(pathW, fmtW, windowsdir, data);
3149 if((unixname = wine_get_unix_file_name(pathW)))
3151 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3152 HeapFree(GetProcessHeap(), 0, unixname);
3154 if (!added)
3155 load_font_from_data_dir(data);
3157 /* reset dlen and vlen */
3158 dlen = datalen;
3159 vlen = valuelen;
3162 HeapFree(GetProcessHeap(), 0, data);
3163 HeapFree(GetProcessHeap(), 0, valueW);
3164 RegCloseKey(hkey);
3167 load_fontconfig_fonts();
3169 /* then look in any directories that we've specified in the config file */
3170 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3171 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3173 DWORD len;
3174 LPWSTR valueW;
3175 LPSTR valueA, ptr;
3177 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3179 len += sizeof(WCHAR);
3180 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3181 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3183 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3184 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3185 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3186 TRACE( "got font path %s\n", debugstr_a(valueA) );
3187 ptr = valueA;
3188 while (ptr)
3190 LPSTR next = strchr( ptr, ':' );
3191 if (next) *next++ = 0;
3192 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3193 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3195 strcpy( unixname, home );
3196 strcat( unixname, ptr + 1 );
3197 ReadFontDir( unixname, TRUE );
3198 HeapFree( GetProcessHeap(), 0, unixname );
3200 else
3201 ReadFontDir( ptr, TRUE );
3202 ptr = next;
3204 HeapFree( GetProcessHeap(), 0, valueA );
3206 HeapFree( GetProcessHeap(), 0, valueW );
3208 RegCloseKey(hkey);
3211 #ifdef __APPLE__
3212 /* Mac default font locations. */
3213 ReadFontDir( "/Library/Fonts", TRUE );
3214 ReadFontDir( "/Network/Library/Fonts", TRUE );
3215 ReadFontDir( "/System/Library/Fonts", TRUE );
3216 if ((home = getenv( "HOME" )))
3218 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3219 strcpy( unixname, home );
3220 strcat( unixname, "/Library/Fonts" );
3221 ReadFontDir( unixname, TRUE);
3222 HeapFree( GetProcessHeap(), 0, unixname );
3224 #endif
3227 static BOOL move_to_front(const WCHAR *name)
3229 Family *family, *cursor2;
3230 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3232 if(!strcmpiW(family->FamilyName, name))
3234 list_remove(&family->entry);
3235 list_add_head(&font_list, &family->entry);
3236 return TRUE;
3239 return FALSE;
3242 static BOOL set_default(const WCHAR **name_list)
3244 while (*name_list)
3246 if (move_to_front(*name_list)) return TRUE;
3247 name_list++;
3250 return FALSE;
3253 static void reorder_font_list(void)
3255 set_default( default_serif_list );
3256 set_default( default_fixed_list );
3257 set_default( default_sans_list );
3260 /*************************************************************
3261 * WineEngInit
3263 * Initialize FreeType library and create a list of available faces
3265 BOOL WineEngInit(void)
3267 HKEY hkey_font_cache;
3268 DWORD disposition;
3269 HANDLE font_mutex;
3271 /* update locale dependent font info in registry */
3272 update_font_info();
3274 if(!init_freetype()) return FALSE;
3276 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3278 ERR("Failed to create font mutex\n");
3279 return FALSE;
3281 WaitForSingleObject(font_mutex, INFINITE);
3283 create_font_cache_key(&hkey_font_cache, &disposition);
3285 if(disposition == REG_CREATED_NEW_KEY)
3286 init_font_list();
3287 else
3288 load_font_list_from_cache(hkey_font_cache);
3290 RegCloseKey(hkey_font_cache);
3292 reorder_font_list();
3294 DumpFontList();
3295 LoadSubstList();
3296 DumpSubstList();
3297 LoadReplaceList();
3299 if(disposition == REG_CREATED_NEW_KEY)
3300 update_reg_entries();
3302 init_system_links();
3304 ReleaseMutex(font_mutex);
3305 return TRUE;
3309 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3311 TT_OS2 *pOS2;
3312 TT_HoriHeader *pHori;
3314 LONG ppem;
3316 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3317 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3319 if(height == 0) height = 16;
3321 /* Calc. height of EM square:
3323 * For +ve lfHeight we have
3324 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3325 * Re-arranging gives:
3326 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3328 * For -ve lfHeight we have
3329 * |lfHeight| = ppem
3330 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3331 * with il = winAscent + winDescent - units_per_em]
3335 if(height > 0) {
3336 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3337 ppem = MulDiv(ft_face->units_per_EM, height,
3338 pHori->Ascender - pHori->Descender);
3339 else
3340 ppem = MulDiv(ft_face->units_per_EM, height,
3341 pOS2->usWinAscent + pOS2->usWinDescent);
3343 else
3344 ppem = -height;
3346 return ppem;
3349 static struct font_mapping *map_font_file( const char *name )
3351 struct font_mapping *mapping;
3352 struct stat st;
3353 int fd;
3355 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3356 if (fstat( fd, &st ) == -1) goto error;
3358 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3360 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3362 mapping->refcount++;
3363 close( fd );
3364 return mapping;
3367 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3368 goto error;
3370 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3371 close( fd );
3373 if (mapping->data == MAP_FAILED)
3375 HeapFree( GetProcessHeap(), 0, mapping );
3376 return NULL;
3378 mapping->refcount = 1;
3379 mapping->dev = st.st_dev;
3380 mapping->ino = st.st_ino;
3381 mapping->size = st.st_size;
3382 list_add_tail( &mappings_list, &mapping->entry );
3383 return mapping;
3385 error:
3386 close( fd );
3387 return NULL;
3390 static void unmap_font_file( struct font_mapping *mapping )
3392 if (!--mapping->refcount)
3394 list_remove( &mapping->entry );
3395 munmap( mapping->data, mapping->size );
3396 HeapFree( GetProcessHeap(), 0, mapping );
3400 static LONG load_VDMX(GdiFont*, LONG);
3402 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3404 FT_Error err;
3405 FT_Face ft_face;
3406 void *data_ptr;
3407 DWORD data_size;
3409 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3411 if (face->file)
3413 if (!(font->mapping = map_font_file( face->file )))
3415 WARN("failed to map %s\n", debugstr_a(face->file));
3416 return 0;
3418 data_ptr = font->mapping->data;
3419 data_size = font->mapping->size;
3421 else
3423 data_ptr = face->font_data_ptr;
3424 data_size = face->font_data_size;
3427 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3428 if(err) {
3429 ERR("FT_New_Face rets %d\n", err);
3430 return 0;
3433 /* set it here, as load_VDMX needs it */
3434 font->ft_face = ft_face;
3436 if(FT_IS_SCALABLE(ft_face)) {
3437 /* load the VDMX table if we have one */
3438 font->ppem = load_VDMX(font, height);
3439 if(font->ppem == 0)
3440 font->ppem = calc_ppem_for_height(ft_face, height);
3441 TRACE("height %d => ppem %d\n", height, font->ppem);
3443 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3444 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3445 } else {
3446 font->ppem = height;
3447 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3448 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3450 return ft_face;
3454 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3456 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3457 a single face with the requested charset. The idea is to check if
3458 the selected font supports the current ANSI codepage, if it does
3459 return the corresponding charset, else return the first charset */
3461 CHARSETINFO csi;
3462 int acp = GetACP(), i;
3463 DWORD fs0;
3465 *cp = acp;
3466 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3468 const SYSTEM_LINKS *font_link;
3470 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3471 return csi.ciCharset;
3473 font_link = find_font_link(family_name);
3474 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3475 return csi.ciCharset;
3478 for(i = 0; i < 32; i++) {
3479 fs0 = 1L << i;
3480 if(face->fs.fsCsb[0] & fs0) {
3481 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3482 *cp = csi.ciACP;
3483 return csi.ciCharset;
3485 else
3486 FIXME("TCI failing on %x\n", fs0);
3490 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3491 face->fs.fsCsb[0], face->file);
3492 *cp = acp;
3493 return DEFAULT_CHARSET;
3496 static GdiFont *alloc_font(void)
3498 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3499 ret->gmsize = 1;
3500 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3501 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3502 ret->potm = NULL;
3503 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3504 ret->total_kern_pairs = (DWORD)-1;
3505 ret->kern_pairs = NULL;
3506 list_init(&ret->hfontlist);
3507 list_init(&ret->child_fonts);
3508 return ret;
3511 static void free_font(GdiFont *font)
3513 struct list *cursor, *cursor2;
3514 DWORD i;
3516 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3518 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3519 list_remove(cursor);
3520 if(child->font)
3521 free_font(child->font);
3522 HeapFree(GetProcessHeap(), 0, child);
3525 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3527 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3528 DeleteObject(hfontlist->hfont);
3529 list_remove(&hfontlist->entry);
3530 HeapFree(GetProcessHeap(), 0, hfontlist);
3533 if (font->ft_face) pFT_Done_Face(font->ft_face);
3534 if (font->mapping) unmap_font_file( font->mapping );
3535 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3536 HeapFree(GetProcessHeap(), 0, font->potm);
3537 HeapFree(GetProcessHeap(), 0, font->name);
3538 for (i = 0; i < font->gmsize; i++)
3539 HeapFree(GetProcessHeap(),0,font->gm[i]);
3540 HeapFree(GetProcessHeap(), 0, font->gm);
3541 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3542 HeapFree(GetProcessHeap(), 0, font);
3546 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3548 FT_Face ft_face = font->ft_face;
3549 FT_ULong len;
3550 FT_Error err;
3552 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3554 if(!buf)
3555 len = 0;
3556 else
3557 len = cbData;
3559 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3561 /* make sure value of len is the value freetype says it needs */
3562 if (buf && len)
3564 FT_ULong needed = 0;
3565 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3566 if( !err && needed < len) len = needed;
3568 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3569 if (err)
3571 TRACE("Can't find table %c%c%c%c\n",
3572 /* bytes were reversed */
3573 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3574 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3575 return GDI_ERROR;
3577 return len;
3580 /*************************************************************
3581 * load_VDMX
3583 * load the vdmx entry for the specified height
3586 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3587 ( ( (FT_ULong)_x4 << 24 ) | \
3588 ( (FT_ULong)_x3 << 16 ) | \
3589 ( (FT_ULong)_x2 << 8 ) | \
3590 (FT_ULong)_x1 )
3592 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3594 typedef struct {
3595 BYTE bCharSet;
3596 BYTE xRatio;
3597 BYTE yStartRatio;
3598 BYTE yEndRatio;
3599 } Ratios;
3601 typedef struct {
3602 WORD recs;
3603 BYTE startsz;
3604 BYTE endsz;
3605 } VDMX_group;
3607 static LONG load_VDMX(GdiFont *font, LONG height)
3609 WORD hdr[3], tmp;
3610 VDMX_group group;
3611 BYTE devXRatio, devYRatio;
3612 USHORT numRecs, numRatios;
3613 DWORD result, offset = -1;
3614 LONG ppem = 0;
3615 int i;
3617 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3619 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3620 return ppem;
3622 /* FIXME: need the real device aspect ratio */
3623 devXRatio = 1;
3624 devYRatio = 1;
3626 numRecs = GET_BE_WORD(hdr[1]);
3627 numRatios = GET_BE_WORD(hdr[2]);
3629 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3630 for(i = 0; i < numRatios; i++) {
3631 Ratios ratio;
3633 offset = (3 * 2) + (i * sizeof(Ratios));
3634 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3635 offset = -1;
3637 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3639 if((ratio.xRatio == 0 &&
3640 ratio.yStartRatio == 0 &&
3641 ratio.yEndRatio == 0) ||
3642 (devXRatio == ratio.xRatio &&
3643 devYRatio >= ratio.yStartRatio &&
3644 devYRatio <= ratio.yEndRatio))
3646 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3647 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3648 offset = GET_BE_WORD(tmp);
3649 break;
3653 if(offset == -1) {
3654 FIXME("No suitable ratio found\n");
3655 return ppem;
3658 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3659 USHORT recs;
3660 BYTE startsz, endsz;
3661 WORD *vTable;
3663 recs = GET_BE_WORD(group.recs);
3664 startsz = group.startsz;
3665 endsz = group.endsz;
3667 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3669 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3670 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3671 if(result == GDI_ERROR) {
3672 FIXME("Failed to retrieve vTable\n");
3673 goto end;
3676 if(height > 0) {
3677 for(i = 0; i < recs; i++) {
3678 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3679 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3680 ppem = GET_BE_WORD(vTable[i * 3]);
3682 if(yMax + -yMin == height) {
3683 font->yMax = yMax;
3684 font->yMin = yMin;
3685 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3686 break;
3688 if(yMax + -yMin > height) {
3689 if(--i < 0) {
3690 ppem = 0;
3691 goto end; /* failed */
3693 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3694 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3695 ppem = GET_BE_WORD(vTable[i * 3]);
3696 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3697 break;
3700 if(!font->yMax) {
3701 ppem = 0;
3702 TRACE("ppem not found for height %d\n", height);
3705 end:
3706 HeapFree(GetProcessHeap(), 0, vTable);
3709 return ppem;
3712 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3714 if(font->font_desc.hash != fd->hash) return TRUE;
3715 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3716 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3717 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3718 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3721 static void calc_hash(FONT_DESC *pfd)
3723 DWORD hash = 0, *ptr, two_chars;
3724 WORD *pwc;
3725 unsigned int i;
3727 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3728 hash ^= *ptr;
3729 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3730 hash ^= *ptr;
3731 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3732 two_chars = *ptr;
3733 pwc = (WCHAR *)&two_chars;
3734 if(!*pwc) break;
3735 *pwc = toupperW(*pwc);
3736 pwc++;
3737 *pwc = toupperW(*pwc);
3738 hash ^= two_chars;
3739 if(!*pwc) break;
3741 hash ^= !pfd->can_use_bitmap;
3742 pfd->hash = hash;
3743 return;
3746 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3748 GdiFont *ret;
3749 FONT_DESC fd;
3750 HFONTLIST *hflist;
3751 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3753 fd.lf = *plf;
3754 fd.matrix = *pmat;
3755 fd.can_use_bitmap = can_use_bitmap;
3756 calc_hash(&fd);
3758 /* try the child list */
3759 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3760 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3761 if(!fontcmp(ret, &fd)) {
3762 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3763 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3764 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3765 if(hflist->hfont == hfont)
3766 return ret;
3771 /* try the in-use list */
3772 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3773 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3774 if(!fontcmp(ret, &fd)) {
3775 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3776 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3777 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3778 if(hflist->hfont == hfont)
3779 return ret;
3781 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3782 hflist->hfont = hfont;
3783 list_add_head(&ret->hfontlist, &hflist->entry);
3784 return ret;
3788 /* then the unused list */
3789 font_elem_ptr = list_head(&unused_gdi_font_list);
3790 while(font_elem_ptr) {
3791 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3792 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3793 if(!fontcmp(ret, &fd)) {
3794 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3795 assert(list_empty(&ret->hfontlist));
3796 TRACE("Found %p in unused list\n", ret);
3797 list_remove(&ret->entry);
3798 list_add_head(&gdi_font_list, &ret->entry);
3799 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3800 hflist->hfont = hfont;
3801 list_add_head(&ret->hfontlist, &hflist->entry);
3802 return ret;
3805 return NULL;
3808 static void add_to_cache(GdiFont *font)
3810 static DWORD cache_num = 1;
3812 font->cache_num = cache_num++;
3813 list_add_head(&gdi_font_list, &font->entry);
3816 /*************************************************************
3817 * create_child_font_list
3819 static BOOL create_child_font_list(GdiFont *font)
3821 BOOL ret = FALSE;
3822 SYSTEM_LINKS *font_link;
3823 CHILD_FONT *font_link_entry, *new_child;
3824 FontSubst *psub;
3825 WCHAR* font_name;
3827 psub = get_font_subst(&font_subst_list, font->name, -1);
3828 font_name = psub ? psub->to.name : font->name;
3829 font_link = find_font_link(font_name);
3830 if (font_link != NULL)
3832 TRACE("found entry in system list\n");
3833 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3835 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3836 new_child->face = font_link_entry->face;
3837 new_child->font = NULL;
3838 list_add_tail(&font->child_fonts, &new_child->entry);
3839 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3841 ret = TRUE;
3844 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3845 * Sans Serif. This is how asian windows get default fallbacks for fonts
3847 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3848 font->charset != OEM_CHARSET &&
3849 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3851 font_link = find_font_link(szDefaultFallbackLink);
3852 if (font_link != NULL)
3854 TRACE("found entry in default fallback list\n");
3855 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3857 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3858 new_child->face = font_link_entry->face;
3859 new_child->font = NULL;
3860 list_add_tail(&font->child_fonts, &new_child->entry);
3861 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3863 ret = TRUE;
3867 return ret;
3870 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3872 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3874 if (pFT_Set_Charmap)
3876 FT_Int i;
3877 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3879 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3881 for (i = 0; i < ft_face->num_charmaps; i++)
3883 if (ft_face->charmaps[i]->encoding == encoding)
3885 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3886 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3888 switch (ft_face->charmaps[i]->platform_id)
3890 default:
3891 cmap_def = ft_face->charmaps[i];
3892 break;
3893 case 0: /* Apple Unicode */
3894 cmap0 = ft_face->charmaps[i];
3895 break;
3896 case 1: /* Macintosh */
3897 cmap1 = ft_face->charmaps[i];
3898 break;
3899 case 2: /* ISO */
3900 cmap2 = ft_face->charmaps[i];
3901 break;
3902 case 3: /* Microsoft */
3903 cmap3 = ft_face->charmaps[i];
3904 break;
3908 if (cmap3) /* prefer Microsoft cmap table */
3909 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3910 else if (cmap1)
3911 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3912 else if (cmap2)
3913 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3914 else if (cmap0)
3915 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3916 else if (cmap_def)
3917 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3919 return ft_err == FT_Err_Ok;
3922 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3926 /*************************************************************
3927 * freetype_CreateDC
3929 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3930 LPCWSTR output, const DEVMODEW *devmode )
3932 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3934 if (!physdev) return FALSE;
3935 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3936 return TRUE;
3940 /*************************************************************
3941 * freetype_DeleteDC
3943 static BOOL freetype_DeleteDC( PHYSDEV dev )
3945 struct freetype_physdev *physdev = get_freetype_dev( dev );
3946 HeapFree( GetProcessHeap(), 0, physdev );
3947 return TRUE;
3951 /*************************************************************
3952 * freetype_SelectFont
3954 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3956 struct freetype_physdev *physdev = get_freetype_dev( dev );
3957 GdiFont *ret;
3958 Face *face, *best, *best_bitmap;
3959 Family *family, *last_resort_family;
3960 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
3961 INT height, width = 0;
3962 unsigned int score = 0, new_score;
3963 signed int diff = 0, newdiff;
3964 BOOL bd, it, can_use_bitmap, want_vertical;
3965 LOGFONTW lf;
3966 CHARSETINFO csi;
3967 HFONTLIST *hflist;
3968 FMAT2 dcmat;
3969 FontSubst *psub = NULL;
3970 DC *dc = get_dc_ptr( dev->hdc );
3971 const SYSTEM_LINKS *font_link;
3973 if (!hfont) /* notification that the font has been changed by another driver */
3975 dc->gdiFont = NULL;
3976 physdev->font = NULL;
3977 release_dc_ptr( dc );
3978 return 0;
3981 GetObjectW( hfont, sizeof(lf), &lf );
3982 lf.lfWidth = abs(lf.lfWidth);
3984 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3986 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3987 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3988 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3989 lf.lfEscapement);
3991 if(dc->GraphicsMode == GM_ADVANCED)
3993 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3994 /* Try to avoid not necessary glyph transformations */
3995 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3997 lf.lfHeight *= fabs(dcmat.eM11);
3998 lf.lfWidth *= fabs(dcmat.eM11);
3999 dcmat.eM11 = dcmat.eM22 = 1.0;
4002 else
4004 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4005 font scaling abilities. */
4006 dcmat.eM11 = dcmat.eM22 = 1.0;
4007 dcmat.eM21 = dcmat.eM12 = 0;
4008 if (dc->vport2WorldValid)
4010 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4011 lf.lfOrientation = -lf.lfOrientation;
4012 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4013 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4017 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4018 dcmat.eM21, dcmat.eM22);
4020 GDI_CheckNotLock();
4021 EnterCriticalSection( &freetype_cs );
4023 /* check the cache first */
4024 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4025 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4026 goto done;
4029 if(list_empty(&font_list)) /* No fonts installed */
4031 TRACE("No fonts installed\n");
4032 goto done;
4035 TRACE("not in cache\n");
4036 ret = alloc_font();
4038 ret->font_desc.matrix = dcmat;
4039 ret->font_desc.lf = lf;
4040 ret->font_desc.can_use_bitmap = can_use_bitmap;
4041 calc_hash(&ret->font_desc);
4042 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4043 hflist->hfont = hfont;
4044 list_add_head(&ret->hfontlist, &hflist->entry);
4046 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4047 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4048 original value lfCharSet. Note this is a special case for
4049 Symbol and doesn't happen at least for "Wingdings*" */
4051 if(!strcmpiW(lf.lfFaceName, SymbolW))
4052 lf.lfCharSet = SYMBOL_CHARSET;
4054 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4055 switch(lf.lfCharSet) {
4056 case DEFAULT_CHARSET:
4057 csi.fs.fsCsb[0] = 0;
4058 break;
4059 default:
4060 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4061 csi.fs.fsCsb[0] = 0;
4062 break;
4066 family = NULL;
4067 if(lf.lfFaceName[0] != '\0') {
4068 CHILD_FONT *font_link_entry;
4069 LPWSTR FaceName = lf.lfFaceName;
4071 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4073 if(psub) {
4074 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4075 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4076 if (psub->to.charset != -1)
4077 lf.lfCharSet = psub->to.charset;
4080 /* We want a match on name and charset or just name if
4081 charset was DEFAULT_CHARSET. If the latter then
4082 we fixup the returned charset later in get_nearest_charset
4083 where we'll either use the charset of the current ansi codepage
4084 or if that's unavailable the first charset that the font supports.
4086 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4087 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4088 if (!strcmpiW(family->FamilyName, FaceName) ||
4089 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4091 font_link = find_font_link(family->FamilyName);
4092 face_list = get_face_list_from_family(family);
4093 LIST_FOR_EACH(face_elem_ptr, face_list) {
4094 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4095 if (!(face->scalable || can_use_bitmap))
4096 continue;
4097 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4098 goto found;
4099 if (font_link != NULL &&
4100 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4101 goto found;
4102 if (!csi.fs.fsCsb[0])
4103 goto found;
4108 /* Search by full face name. */
4109 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4110 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4111 face_list = get_face_list_from_family(family);
4112 LIST_FOR_EACH(face_elem_ptr, face_list) {
4113 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4114 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4115 (face->scalable || can_use_bitmap))
4117 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4118 goto found_face;
4119 font_link = find_font_link(family->FamilyName);
4120 if (font_link != NULL &&
4121 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4122 goto found_face;
4128 * Try check the SystemLink list first for a replacement font.
4129 * We may find good replacements there.
4131 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4133 if(!strcmpiW(font_link->font_name, FaceName) ||
4134 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4136 TRACE("found entry in system list\n");
4137 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4139 const SYSTEM_LINKS *links;
4141 face = font_link_entry->face;
4142 if (!(face->scalable || can_use_bitmap))
4143 continue;
4144 family = face->family;
4145 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4146 goto found;
4147 links = find_font_link(family->FamilyName);
4148 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4149 goto found;
4155 psub = NULL; /* substitution is no more relevant */
4157 /* If requested charset was DEFAULT_CHARSET then try using charset
4158 corresponding to the current ansi codepage */
4159 if (!csi.fs.fsCsb[0])
4161 INT acp = GetACP();
4162 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4163 FIXME("TCI failed on codepage %d\n", acp);
4164 csi.fs.fsCsb[0] = 0;
4165 } else
4166 lf.lfCharSet = csi.ciCharset;
4169 want_vertical = (lf.lfFaceName[0] == '@');
4171 /* Face families are in the top 4 bits of lfPitchAndFamily,
4172 so mask with 0xF0 before testing */
4174 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4175 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4176 strcpyW(lf.lfFaceName, defFixed);
4177 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4178 strcpyW(lf.lfFaceName, defSerif);
4179 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4180 strcpyW(lf.lfFaceName, defSans);
4181 else
4182 strcpyW(lf.lfFaceName, defSans);
4183 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4184 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4185 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4186 font_link = find_font_link(family->FamilyName);
4187 face_list = get_face_list_from_family(family);
4188 LIST_FOR_EACH(face_elem_ptr, face_list) {
4189 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4190 if (!(face->scalable || can_use_bitmap))
4191 continue;
4192 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4193 goto found;
4194 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4195 goto found;
4200 last_resort_family = NULL;
4201 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4202 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4203 font_link = find_font_link(family->FamilyName);
4204 face_list = get_face_list_from_family(family);
4205 LIST_FOR_EACH(face_elem_ptr, face_list) {
4206 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4207 if(face->vertical == want_vertical &&
4208 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4209 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4210 if(face->scalable)
4211 goto found;
4212 if(can_use_bitmap && !last_resort_family)
4213 last_resort_family = family;
4218 if(last_resort_family) {
4219 family = last_resort_family;
4220 csi.fs.fsCsb[0] = 0;
4221 goto found;
4224 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4225 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4226 face_list = get_face_list_from_family(family);
4227 LIST_FOR_EACH(face_elem_ptr, face_list) {
4228 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4229 if(face->scalable && face->vertical == want_vertical) {
4230 csi.fs.fsCsb[0] = 0;
4231 WARN("just using first face for now\n");
4232 goto found;
4234 if(can_use_bitmap && !last_resort_family)
4235 last_resort_family = family;
4238 if(!last_resort_family) {
4239 FIXME("can't find a single appropriate font - bailing\n");
4240 free_font(ret);
4241 ret = NULL;
4242 goto done;
4245 WARN("could only find a bitmap font - this will probably look awful!\n");
4246 family = last_resort_family;
4247 csi.fs.fsCsb[0] = 0;
4249 found:
4250 it = lf.lfItalic ? 1 : 0;
4251 bd = lf.lfWeight > 550 ? 1 : 0;
4253 height = lf.lfHeight;
4255 face = best = best_bitmap = NULL;
4256 font_link = find_font_link(family->FamilyName);
4257 face_list = get_face_list_from_family(family);
4258 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4260 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4261 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4262 !csi.fs.fsCsb[0])
4264 BOOL italic, bold;
4266 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4267 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4268 new_score = (italic ^ it) + (bold ^ bd);
4269 if(!best || new_score <= score)
4271 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4272 italic, bold, it, bd);
4273 score = new_score;
4274 best = face;
4275 if(best->scalable && score == 0) break;
4276 if(!best->scalable)
4278 if(height > 0)
4279 newdiff = height - (signed int)(best->size.height);
4280 else
4281 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4282 if(!best_bitmap || new_score < score ||
4283 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4285 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4286 diff = newdiff;
4287 best_bitmap = best;
4288 if(score == 0 && diff == 0) break;
4294 if(best)
4295 face = best->scalable ? best : best_bitmap;
4296 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4297 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4299 found_face:
4300 height = lf.lfHeight;
4302 ret->fs = face->fs;
4304 if(csi.fs.fsCsb[0]) {
4305 ret->charset = lf.lfCharSet;
4306 ret->codepage = csi.ciACP;
4308 else
4309 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4311 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4312 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4314 ret->aveWidth = height ? lf.lfWidth : 0;
4316 if(!face->scalable) {
4317 /* Windows uses integer scaling factors for bitmap fonts */
4318 INT scale, scaled_height;
4319 GdiFont *cachedfont;
4321 /* FIXME: rotation of bitmap fonts is ignored */
4322 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4323 if (ret->aveWidth)
4324 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4325 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4326 dcmat.eM11 = dcmat.eM22 = 1.0;
4327 /* As we changed the matrix, we need to search the cache for the font again,
4328 * otherwise we might explode the cache. */
4329 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4330 TRACE("Found cached font after non-scalable matrix rescale!\n");
4331 free_font( ret );
4332 ret = cachedfont;
4333 goto done;
4335 calc_hash(&ret->font_desc);
4337 if (height != 0) height = diff;
4338 height += face->size.height;
4340 scale = (height + face->size.height - 1) / face->size.height;
4341 scaled_height = scale * face->size.height;
4342 /* Only jump to the next height if the difference <= 25% original height */
4343 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4344 /* The jump between unscaled and doubled is delayed by 1 */
4345 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4346 ret->scale_y = scale;
4348 width = face->size.x_ppem >> 6;
4349 height = face->size.y_ppem >> 6;
4351 else
4352 ret->scale_y = 1.0;
4353 TRACE("font scale y: %f\n", ret->scale_y);
4355 ret->ft_face = OpenFontFace(ret, face, width, height);
4357 if (!ret->ft_face)
4359 free_font( ret );
4360 ret = NULL;
4361 goto done;
4364 ret->ntmFlags = face->ntmFlags;
4366 if (ret->charset == SYMBOL_CHARSET &&
4367 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4368 /* No ops */
4370 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4371 /* No ops */
4373 else {
4374 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4377 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4378 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4379 ret->underline = lf.lfUnderline ? 0xff : 0;
4380 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4381 create_child_font_list(ret);
4383 if (face->vertical) /* We need to try to load the GSUB table */
4385 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4386 if (length != GDI_ERROR)
4388 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4389 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4390 TRACE("Loaded GSUB table of %i bytes\n",length);
4394 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4396 add_to_cache(ret);
4397 done:
4398 if (ret)
4400 dc->gdiFont = ret;
4401 physdev->font = ret;
4403 LeaveCriticalSection( &freetype_cs );
4404 release_dc_ptr( dc );
4405 return ret ? hfont : 0;
4408 static void dump_gdi_font_list(void)
4410 GdiFont *gdiFont;
4411 struct list *elem_ptr;
4413 TRACE("---------- gdiFont Cache ----------\n");
4414 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4415 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4416 TRACE("gdiFont=%p %s %d\n",
4417 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4420 TRACE("---------- Unused gdiFont Cache ----------\n");
4421 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4422 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4423 TRACE("gdiFont=%p %s %d\n",
4424 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4427 TRACE("---------- Child gdiFont Cache ----------\n");
4428 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4429 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4430 TRACE("gdiFont=%p %s %d\n",
4431 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4435 /*************************************************************
4436 * WineEngDestroyFontInstance
4438 * free the gdiFont associated with this handle
4441 BOOL WineEngDestroyFontInstance(HFONT handle)
4443 GdiFont *gdiFont;
4444 HFONTLIST *hflist;
4445 BOOL ret = FALSE;
4446 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4447 int i = 0;
4449 GDI_CheckNotLock();
4450 EnterCriticalSection( &freetype_cs );
4452 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4454 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4455 while(hfontlist_elem_ptr) {
4456 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4457 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4458 if(hflist->hfont == handle) {
4459 TRACE("removing child font %p from child list\n", gdiFont);
4460 list_remove(&gdiFont->entry);
4461 LeaveCriticalSection( &freetype_cs );
4462 return TRUE;
4467 TRACE("destroying hfont=%p\n", handle);
4468 if(TRACE_ON(font))
4469 dump_gdi_font_list();
4471 font_elem_ptr = list_head(&gdi_font_list);
4472 while(font_elem_ptr) {
4473 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4474 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4476 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4477 while(hfontlist_elem_ptr) {
4478 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4479 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4480 if(hflist->hfont == handle) {
4481 list_remove(&hflist->entry);
4482 HeapFree(GetProcessHeap(), 0, hflist);
4483 ret = TRUE;
4486 if(list_empty(&gdiFont->hfontlist)) {
4487 TRACE("Moving to Unused list\n");
4488 list_remove(&gdiFont->entry);
4489 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4494 font_elem_ptr = list_head(&unused_gdi_font_list);
4495 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4496 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4497 while(font_elem_ptr) {
4498 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4499 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4500 TRACE("freeing %p\n", gdiFont);
4501 list_remove(&gdiFont->entry);
4502 free_font(gdiFont);
4504 LeaveCriticalSection( &freetype_cs );
4505 return ret;
4508 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4510 HRSRC rsrc;
4511 HGLOBAL hMem;
4512 WCHAR *p;
4513 int i;
4515 id += IDS_FIRST_SCRIPT;
4516 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4517 if (!rsrc) return 0;
4518 hMem = LoadResource( gdi32_module, rsrc );
4519 if (!hMem) return 0;
4521 p = LockResource( hMem );
4522 id &= 0x000f;
4523 while (id--) p += *p + 1;
4525 i = min(LF_FACESIZE - 1, *p);
4526 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4527 buffer[i] = 0;
4528 return i;
4532 /***************************************************
4533 * create_enum_charset_list
4535 * This function creates charset enumeration list because in DEFAULT_CHARSET
4536 * case, the ANSI codepage's charset takes precedence over other charsets.
4537 * This function works as a filter other than DEFAULT_CHARSET case.
4539 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4541 CHARSETINFO csi;
4542 DWORD n = 0;
4544 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4545 csi.fs.fsCsb[0] != 0) {
4546 list->element[n].mask = csi.fs.fsCsb[0];
4547 list->element[n].charset = csi.ciCharset;
4548 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4549 n++;
4551 else { /* charset is DEFAULT_CHARSET or invalid. */
4552 INT acp, i;
4554 /* Set the current codepage's charset as the first element. */
4555 acp = GetACP();
4556 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4557 csi.fs.fsCsb[0] != 0) {
4558 list->element[n].mask = csi.fs.fsCsb[0];
4559 list->element[n].charset = csi.ciCharset;
4560 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4561 n++;
4564 /* Fill out left elements. */
4565 for (i = 0; i < 32; i++) {
4566 FONTSIGNATURE fs;
4567 fs.fsCsb[0] = 1L << i;
4568 fs.fsCsb[1] = 0;
4569 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4570 continue; /* skip, already added. */
4571 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4572 continue; /* skip, this is an invalid fsCsb bit. */
4574 list->element[n].mask = fs.fsCsb[0];
4575 list->element[n].charset = csi.ciCharset;
4576 load_script_name( i, list->element[n].name );
4577 n++;
4580 list->total = n;
4582 return n;
4585 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4586 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4588 GdiFont *font;
4589 LONG width, height;
4591 if (face->cached_enum_data)
4593 TRACE("Cached\n");
4594 *pelf = face->cached_enum_data->elf;
4595 *pntm = face->cached_enum_data->ntm;
4596 *ptype = face->cached_enum_data->type;
4597 return;
4600 font = alloc_font();
4602 if(face->scalable) {
4603 height = -2048; /* 2048 is the most common em size */
4604 width = 0;
4605 } else {
4606 height = face->size.y_ppem >> 6;
4607 width = face->size.x_ppem >> 6;
4609 font->scale_y = 1.0;
4611 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4613 free_font(font);
4614 return;
4617 font->name = strdupW(face->family->FamilyName);
4618 font->ntmFlags = face->ntmFlags;
4620 if (get_outline_text_metrics(font))
4622 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4624 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4626 lstrcpynW(pelf->elfLogFont.lfFaceName,
4627 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4628 LF_FACESIZE);
4629 lstrcpynW(pelf->elfFullName,
4630 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4631 LF_FULLFACESIZE);
4632 lstrcpynW(pelf->elfStyle,
4633 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4634 LF_FACESIZE);
4636 else
4638 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4640 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4642 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4643 if (face->FullName)
4644 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4645 else
4646 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4647 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4650 pntm->ntmTm.ntmFlags = face->ntmFlags;
4651 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4652 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4653 pntm->ntmFontSig = face->fs;
4655 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4657 pelf->elfLogFont.lfEscapement = 0;
4658 pelf->elfLogFont.lfOrientation = 0;
4659 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4660 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4661 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4662 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4663 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4664 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4665 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4666 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4667 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4668 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4669 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4671 *ptype = 0;
4672 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4673 *ptype |= TRUETYPE_FONTTYPE;
4674 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4675 *ptype |= DEVICE_FONTTYPE;
4676 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4677 *ptype |= RASTER_FONTTYPE;
4679 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4680 if (face->cached_enum_data)
4682 face->cached_enum_data->elf = *pelf;
4683 face->cached_enum_data->ntm = *pntm;
4684 face->cached_enum_data->type = *ptype;
4687 free_font(font);
4690 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
4692 static const WCHAR spaceW[] = { ' ', 0 };
4694 strcpyW(full_name, family_name);
4695 strcatW(full_name, spaceW);
4696 strcatW(full_name, style_name);
4699 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4701 const struct list *face_list, *face_elem_ptr;
4703 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4705 face_list = get_face_list_from_family(family);
4706 LIST_FOR_EACH(face_elem_ptr, face_list)
4708 WCHAR full_family_name[LF_FULLFACESIZE];
4709 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4711 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4713 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4714 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4715 continue;
4718 create_full_name(full_family_name, family->FamilyName, face->StyleName);
4719 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4722 return FALSE;
4725 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
4727 WCHAR full_family_name[LF_FULLFACESIZE];
4729 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
4731 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4733 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4734 debugstr_w(family_name), debugstr_w(face->StyleName));
4735 return FALSE;
4738 create_full_name(full_family_name, family_name, face->StyleName);
4739 return !strcmpiW(lf->lfFaceName, full_family_name);
4742 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
4743 FONTENUMPROCW proc, LPARAM lparam)
4745 ENUMLOGFONTEXW elf;
4746 NEWTEXTMETRICEXW ntm;
4747 DWORD type = 0;
4748 int i;
4750 GetEnumStructs(face, &elf, &ntm, &type);
4751 for(i = 0; i < list->total; i++) {
4752 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4753 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4754 load_script_name( IDS_OEM_DOS, elf.elfScript );
4755 i = list->total; /* break out of loop after enumeration */
4756 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4757 continue;
4758 else {
4759 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4760 strcpyW(elf.elfScript, list->element[i].name);
4761 if (!elf.elfScript[0])
4762 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4764 /* Font Replacement */
4765 if (family != face->family)
4767 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
4768 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
4770 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4771 debugstr_w(elf.elfLogFont.lfFaceName),
4772 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4773 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4774 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4775 ntm.ntmTm.ntmFlags);
4776 /* release section before callback (FIXME) */
4777 LeaveCriticalSection( &freetype_cs );
4778 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4779 EnterCriticalSection( &freetype_cs );
4781 return TRUE;
4784 /*************************************************************
4785 * freetype_EnumFonts
4787 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4789 Family *family;
4790 Face *face;
4791 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4792 LOGFONTW lf;
4793 struct enum_charset_list enum_charsets;
4795 if (!plf)
4797 lf.lfCharSet = DEFAULT_CHARSET;
4798 lf.lfPitchAndFamily = 0;
4799 lf.lfFaceName[0] = 0;
4800 plf = &lf;
4803 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4805 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4807 GDI_CheckNotLock();
4808 EnterCriticalSection( &freetype_cs );
4809 if(plf->lfFaceName[0]) {
4810 FontSubst *psub;
4811 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4813 if(psub) {
4814 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4815 debugstr_w(psub->to.name));
4816 lf = *plf;
4817 strcpyW(lf.lfFaceName, psub->to.name);
4818 plf = &lf;
4821 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4822 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4823 if(family_matches(family, plf)) {
4824 face_list = get_face_list_from_family(family);
4825 LIST_FOR_EACH(face_elem_ptr, face_list) {
4826 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4827 if (!face_matches(family->FamilyName, face, plf)) continue;
4828 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4832 } else {
4833 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4834 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4835 face_list = get_face_list_from_family(family);
4836 face_elem_ptr = list_head(face_list);
4837 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4838 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4841 LeaveCriticalSection( &freetype_cs );
4842 return TRUE;
4845 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4847 pt->x.value = vec->x >> 6;
4848 pt->x.fract = (vec->x & 0x3f) << 10;
4849 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4850 pt->y.value = vec->y >> 6;
4851 pt->y.fract = (vec->y & 0x3f) << 10;
4852 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4853 return;
4856 /***************************************************
4857 * According to the MSDN documentation on WideCharToMultiByte,
4858 * certain codepages cannot set the default_used parameter.
4859 * This returns TRUE if the codepage can set that parameter, false else
4860 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4862 static BOOL codepage_sets_default_used(UINT codepage)
4864 switch (codepage)
4866 case CP_UTF7:
4867 case CP_UTF8:
4868 case CP_SYMBOL:
4869 return FALSE;
4870 default:
4871 return TRUE;
4876 * GSUB Table handling functions
4879 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4881 const GSUB_CoverageFormat1* cf1;
4883 cf1 = table;
4885 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4887 int count = GET_BE_WORD(cf1->GlyphCount);
4888 int i;
4889 TRACE("Coverage Format 1, %i glyphs\n",count);
4890 for (i = 0; i < count; i++)
4891 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4892 return i;
4893 return -1;
4895 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4897 const GSUB_CoverageFormat2* cf2;
4898 int i;
4899 int count;
4900 cf2 = (const GSUB_CoverageFormat2*)cf1;
4902 count = GET_BE_WORD(cf2->RangeCount);
4903 TRACE("Coverage Format 2, %i ranges\n",count);
4904 for (i = 0; i < count; i++)
4906 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4907 return -1;
4908 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4909 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4911 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4912 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4915 return -1;
4917 else
4918 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4920 return -1;
4923 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4925 const GSUB_ScriptList *script;
4926 const GSUB_Script *deflt = NULL;
4927 int i;
4928 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4930 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4931 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4933 const GSUB_Script *scr;
4934 int offset;
4936 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4937 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4939 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4940 return scr;
4941 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4942 deflt = scr;
4944 return deflt;
4947 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4949 int i;
4950 int offset;
4951 const GSUB_LangSys *Lang;
4953 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4955 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4957 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4958 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4960 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4961 return Lang;
4963 offset = GET_BE_WORD(script->DefaultLangSys);
4964 if (offset)
4966 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4967 return Lang;
4969 return NULL;
4972 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4974 int i;
4975 const GSUB_FeatureList *feature;
4976 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4978 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4979 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4981 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4982 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4984 const GSUB_Feature *feat;
4985 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4986 return feat;
4989 return NULL;
4992 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4994 int i;
4995 int offset;
4996 const GSUB_LookupList *lookup;
4997 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4999 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5000 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5002 const GSUB_LookupTable *look;
5003 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5004 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5005 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5006 if (GET_BE_WORD(look->LookupType) != 1)
5007 FIXME("We only handle SubType 1\n");
5008 else
5010 int j;
5012 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5014 const GSUB_SingleSubstFormat1 *ssf1;
5015 offset = GET_BE_WORD(look->SubTable[j]);
5016 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5017 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5019 int offset = GET_BE_WORD(ssf1->Coverage);
5020 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5021 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5023 TRACE(" Glyph 0x%x ->",glyph);
5024 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5025 TRACE(" 0x%x\n",glyph);
5028 else
5030 const GSUB_SingleSubstFormat2 *ssf2;
5031 INT index;
5032 INT offset;
5034 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5035 offset = GET_BE_WORD(ssf1->Coverage);
5036 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5037 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5038 TRACE(" Coverage index %i\n",index);
5039 if (index != -1)
5041 TRACE(" Glyph is 0x%x ->",glyph);
5042 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5043 TRACE("0x%x\n",glyph);
5049 return glyph;
5052 static const char* get_opentype_script(const GdiFont *font)
5055 * I am not sure if this is the correct way to generate our script tag
5058 switch (font->charset)
5060 case ANSI_CHARSET: return "latn";
5061 case BALTIC_CHARSET: return "latn"; /* ?? */
5062 case CHINESEBIG5_CHARSET: return "hani";
5063 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5064 case GB2312_CHARSET: return "hani";
5065 case GREEK_CHARSET: return "grek";
5066 case HANGUL_CHARSET: return "hang";
5067 case RUSSIAN_CHARSET: return "cyrl";
5068 case SHIFTJIS_CHARSET: return "kana";
5069 case TURKISH_CHARSET: return "latn"; /* ?? */
5070 case VIETNAMESE_CHARSET: return "latn";
5071 case JOHAB_CHARSET: return "latn"; /* ?? */
5072 case ARABIC_CHARSET: return "arab";
5073 case HEBREW_CHARSET: return "hebr";
5074 case THAI_CHARSET: return "thai";
5075 default: return "latn";
5079 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5081 const GSUB_Header *header;
5082 const GSUB_Script *script;
5083 const GSUB_LangSys *language;
5084 const GSUB_Feature *feature;
5086 if (!font->GSUB_Table)
5087 return glyph;
5089 header = font->GSUB_Table;
5091 script = GSUB_get_script_table(header, get_opentype_script(font));
5092 if (!script)
5094 TRACE("Script not found\n");
5095 return glyph;
5097 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5098 if (!language)
5100 TRACE("Language not found\n");
5101 return glyph;
5103 feature = GSUB_get_feature(header, language, "vrt2");
5104 if (!feature)
5105 feature = GSUB_get_feature(header, language, "vert");
5106 if (!feature)
5108 TRACE("vrt2/vert feature not found\n");
5109 return glyph;
5111 return GSUB_apply_feature(header, feature, glyph);
5114 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5116 FT_UInt glyphId;
5118 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5119 WCHAR wc = (WCHAR)glyph;
5120 BOOL default_used;
5121 BOOL *default_used_pointer;
5122 FT_UInt ret;
5123 char buf;
5124 default_used_pointer = NULL;
5125 default_used = FALSE;
5126 if (codepage_sets_default_used(font->codepage))
5127 default_used_pointer = &default_used;
5128 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5129 ret = 0;
5130 else
5131 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5132 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5133 return ret;
5136 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5138 if (glyph < 0x100) glyph += 0xf000;
5139 /* there is a number of old pre-Unicode "broken" TTFs, which
5140 do have symbols at U+00XX instead of U+f0XX */
5141 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5142 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5144 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5146 return glyphId;
5149 /*************************************************************
5150 * freetype_GetGlyphIndices
5152 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5154 struct freetype_physdev *physdev = get_freetype_dev( dev );
5155 int i;
5156 WORD default_char;
5157 BOOL got_default = FALSE;
5159 if (!physdev->font)
5161 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5162 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5165 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5167 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5168 got_default = TRUE;
5171 GDI_CheckNotLock();
5172 EnterCriticalSection( &freetype_cs );
5174 for(i = 0; i < count; i++)
5176 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5177 if (pgi[i] == 0)
5179 if (!got_default)
5181 if (FT_IS_SFNT(physdev->font->ft_face))
5183 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5184 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5186 else
5188 TEXTMETRICW textm;
5189 get_text_metrics(physdev->font, &textm);
5190 default_char = textm.tmDefaultChar;
5192 got_default = TRUE;
5194 pgi[i] = default_char;
5197 LeaveCriticalSection( &freetype_cs );
5198 return count;
5201 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5203 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5204 return !memcmp(matrix, &identity, sizeof(FMAT2));
5207 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5209 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5210 return !memcmp(matrix, &identity, sizeof(MAT2));
5213 static inline BYTE get_max_level( UINT format )
5215 switch( format )
5217 case GGO_GRAY2_BITMAP: return 4;
5218 case GGO_GRAY4_BITMAP: return 16;
5219 case GGO_GRAY8_BITMAP: return 64;
5221 return 255;
5224 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5226 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5227 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5228 const MAT2* lpmat)
5230 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5231 FT_Face ft_face = incoming_font->ft_face;
5232 GdiFont *font = incoming_font;
5233 FT_UInt glyph_index;
5234 DWORD width, height, pitch, needed = 0;
5235 FT_Bitmap ft_bitmap;
5236 FT_Error err;
5237 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5238 FT_Angle angle = 0;
5239 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5240 double widthRatio = 1.0;
5241 FT_Matrix transMat = identityMat;
5242 FT_Matrix transMatUnrotated;
5243 BOOL needsTransform = FALSE;
5244 BOOL tategaki = (font->GSUB_Table != NULL);
5245 UINT original_index;
5247 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5248 buflen, buf, lpmat);
5250 TRACE("font transform %f %f %f %f\n",
5251 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5252 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5254 if(format & GGO_GLYPH_INDEX) {
5255 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5256 original_index = glyph;
5257 format &= ~GGO_GLYPH_INDEX;
5258 } else {
5259 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5260 ft_face = font->ft_face;
5261 original_index = glyph_index;
5264 if(format & GGO_UNHINTED) {
5265 load_flags |= FT_LOAD_NO_HINTING;
5266 format &= ~GGO_UNHINTED;
5269 /* tategaki never appears to happen to lower glyph index */
5270 if (glyph_index < TATEGAKI_LOWER_BOUND )
5271 tategaki = FALSE;
5273 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5274 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5275 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5276 font->gmsize * sizeof(GM*));
5277 } else {
5278 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5279 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5281 *lpgm = FONT_GM(font,original_index)->gm;
5282 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5283 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5284 lpgm->gmCellIncX, lpgm->gmCellIncY);
5285 return 1; /* FIXME */
5289 if (!font->gm[original_index / GM_BLOCK_SIZE])
5290 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5292 /* Scaling factor */
5293 if (font->aveWidth)
5295 TEXTMETRICW tm;
5297 get_text_metrics(font, &tm);
5299 widthRatio = (double)font->aveWidth;
5300 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5302 else
5303 widthRatio = font->scale_y;
5305 /* Scaling transform */
5306 if (widthRatio != 1.0 || font->scale_y != 1.0)
5308 FT_Matrix scaleMat;
5309 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5310 scaleMat.xy = 0;
5311 scaleMat.yx = 0;
5312 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5314 pFT_Matrix_Multiply(&scaleMat, &transMat);
5315 needsTransform = TRUE;
5318 /* Slant transform */
5319 if (font->fake_italic) {
5320 FT_Matrix slantMat;
5322 slantMat.xx = (1 << 16);
5323 slantMat.xy = ((1 << 16) >> 2);
5324 slantMat.yx = 0;
5325 slantMat.yy = (1 << 16);
5326 pFT_Matrix_Multiply(&slantMat, &transMat);
5327 needsTransform = TRUE;
5330 /* Rotation transform */
5331 transMatUnrotated = transMat;
5332 if(font->orientation && !tategaki) {
5333 FT_Matrix rotationMat;
5334 FT_Vector vecAngle;
5335 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5336 pFT_Vector_Unit(&vecAngle, angle);
5337 rotationMat.xx = vecAngle.x;
5338 rotationMat.xy = -vecAngle.y;
5339 rotationMat.yx = -rotationMat.xy;
5340 rotationMat.yy = rotationMat.xx;
5342 pFT_Matrix_Multiply(&rotationMat, &transMat);
5343 needsTransform = TRUE;
5346 /* World transform */
5347 if (!is_identity_FMAT2(&font->font_desc.matrix))
5349 FT_Matrix worldMat;
5350 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5351 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5352 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5353 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5354 pFT_Matrix_Multiply(&worldMat, &transMat);
5355 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5356 needsTransform = TRUE;
5359 /* Extra transformation specified by caller */
5360 if (!is_identity_MAT2(lpmat))
5362 FT_Matrix extraMat;
5363 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5364 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5365 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5366 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5367 pFT_Matrix_Multiply(&extraMat, &transMat);
5368 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5369 needsTransform = TRUE;
5372 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5373 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5374 format == GGO_GRAY8_BITMAP))
5376 load_flags |= FT_LOAD_NO_BITMAP;
5379 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5381 if(err) {
5382 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5383 return GDI_ERROR;
5386 if(!needsTransform) {
5387 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5388 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5389 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5391 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5392 bottom = (ft_face->glyph->metrics.horiBearingY -
5393 ft_face->glyph->metrics.height) & -64;
5394 lpgm->gmCellIncX = adv;
5395 lpgm->gmCellIncY = 0;
5396 } else {
5397 INT xc, yc;
5398 FT_Vector vec;
5400 left = right = 0;
5402 for(xc = 0; xc < 2; xc++) {
5403 for(yc = 0; yc < 2; yc++) {
5404 vec.x = (ft_face->glyph->metrics.horiBearingX +
5405 xc * ft_face->glyph->metrics.width);
5406 vec.y = ft_face->glyph->metrics.horiBearingY -
5407 yc * ft_face->glyph->metrics.height;
5408 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5409 pFT_Vector_Transform(&vec, &transMat);
5410 if(xc == 0 && yc == 0) {
5411 left = right = vec.x;
5412 top = bottom = vec.y;
5413 } else {
5414 if(vec.x < left) left = vec.x;
5415 else if(vec.x > right) right = vec.x;
5416 if(vec.y < bottom) bottom = vec.y;
5417 else if(vec.y > top) top = vec.y;
5421 left = left & -64;
5422 right = (right + 63) & -64;
5423 bottom = bottom & -64;
5424 top = (top + 63) & -64;
5426 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5427 vec.x = ft_face->glyph->metrics.horiAdvance;
5428 vec.y = 0;
5429 pFT_Vector_Transform(&vec, &transMat);
5430 lpgm->gmCellIncX = (vec.x+63) >> 6;
5431 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5433 vec.x = ft_face->glyph->metrics.horiAdvance;
5434 vec.y = 0;
5435 pFT_Vector_Transform(&vec, &transMatUnrotated);
5436 adv = (vec.x+63) >> 6;
5439 lsb = left >> 6;
5440 bbx = (right - left) >> 6;
5441 lpgm->gmBlackBoxX = (right - left) >> 6;
5442 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5443 lpgm->gmptGlyphOrigin.x = left >> 6;
5444 lpgm->gmptGlyphOrigin.y = top >> 6;
5446 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5447 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5448 lpgm->gmCellIncX, lpgm->gmCellIncY);
5450 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5451 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5453 FONT_GM(font,original_index)->gm = *lpgm;
5454 FONT_GM(font,original_index)->adv = adv;
5455 FONT_GM(font,original_index)->lsb = lsb;
5456 FONT_GM(font,original_index)->bbx = bbx;
5457 FONT_GM(font,original_index)->init = TRUE;
5460 if(format == GGO_METRICS)
5462 return 1; /* FIXME */
5465 if(ft_face->glyph->format != ft_glyph_format_outline &&
5466 (format == GGO_NATIVE || format == GGO_BEZIER))
5468 TRACE("loaded a bitmap\n");
5469 return GDI_ERROR;
5472 switch(format) {
5473 case GGO_BITMAP:
5474 width = lpgm->gmBlackBoxX;
5475 height = lpgm->gmBlackBoxY;
5476 pitch = ((width + 31) >> 5) << 2;
5477 needed = pitch * height;
5479 if(!buf || !buflen) break;
5481 switch(ft_face->glyph->format) {
5482 case ft_glyph_format_bitmap:
5484 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5485 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5486 INT h = ft_face->glyph->bitmap.rows;
5487 while(h--) {
5488 memcpy(dst, src, w);
5489 src += ft_face->glyph->bitmap.pitch;
5490 dst += pitch;
5492 break;
5495 case ft_glyph_format_outline:
5496 ft_bitmap.width = width;
5497 ft_bitmap.rows = height;
5498 ft_bitmap.pitch = pitch;
5499 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5500 ft_bitmap.buffer = buf;
5502 if(needsTransform)
5503 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5505 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5507 /* Note: FreeType will only set 'black' bits for us. */
5508 memset(buf, 0, needed);
5509 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5510 break;
5512 default:
5513 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5514 return GDI_ERROR;
5516 break;
5518 case GGO_GRAY2_BITMAP:
5519 case GGO_GRAY4_BITMAP:
5520 case GGO_GRAY8_BITMAP:
5521 case WINE_GGO_GRAY16_BITMAP:
5523 unsigned int max_level, row, col;
5524 BYTE *start, *ptr;
5526 width = lpgm->gmBlackBoxX;
5527 height = lpgm->gmBlackBoxY;
5528 pitch = (width + 3) / 4 * 4;
5529 needed = pitch * height;
5531 if(!buf || !buflen) break;
5533 max_level = get_max_level( format );
5535 switch(ft_face->glyph->format) {
5536 case ft_glyph_format_bitmap:
5538 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5539 INT h = ft_face->glyph->bitmap.rows;
5540 INT x;
5541 memset( buf, 0, needed );
5542 while(h--) {
5543 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5544 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5545 src += ft_face->glyph->bitmap.pitch;
5546 dst += pitch;
5548 return needed;
5550 case ft_glyph_format_outline:
5552 ft_bitmap.width = width;
5553 ft_bitmap.rows = height;
5554 ft_bitmap.pitch = pitch;
5555 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5556 ft_bitmap.buffer = buf;
5558 if(needsTransform)
5559 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5561 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5563 memset(ft_bitmap.buffer, 0, buflen);
5565 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5567 if (max_level != 255)
5569 for (row = 0, start = buf; row < height; row++)
5571 for (col = 0, ptr = start; col < width; col++, ptr++)
5572 *ptr = (((int)*ptr) * max_level + 128) / 256;
5573 start += pitch;
5576 return needed;
5579 default:
5580 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5581 return GDI_ERROR;
5583 break;
5586 case WINE_GGO_HRGB_BITMAP:
5587 case WINE_GGO_HBGR_BITMAP:
5588 case WINE_GGO_VRGB_BITMAP:
5589 case WINE_GGO_VBGR_BITMAP:
5590 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5592 switch (ft_face->glyph->format)
5594 case FT_GLYPH_FORMAT_BITMAP:
5596 BYTE *src, *dst;
5597 INT src_pitch, x;
5599 width = lpgm->gmBlackBoxX;
5600 height = lpgm->gmBlackBoxY;
5601 pitch = width * 4;
5602 needed = pitch * height;
5604 if (!buf || !buflen) break;
5606 memset(buf, 0, buflen);
5607 dst = buf;
5608 src = ft_face->glyph->bitmap.buffer;
5609 src_pitch = ft_face->glyph->bitmap.pitch;
5611 height = min( height, ft_face->glyph->bitmap.rows );
5612 while ( height-- )
5614 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5616 if ( src[x / 8] & masks[x % 8] )
5617 ((unsigned int *)dst)[x] = ~0u;
5619 src += src_pitch;
5620 dst += pitch;
5623 break;
5626 case FT_GLYPH_FORMAT_OUTLINE:
5628 unsigned int *dst;
5629 BYTE *src;
5630 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5631 INT x_shift, y_shift;
5632 BOOL rgb;
5633 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5634 FT_Render_Mode render_mode =
5635 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5636 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5638 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5640 if ( render_mode == FT_RENDER_MODE_LCD)
5642 lpgm->gmBlackBoxX += 2;
5643 lpgm->gmptGlyphOrigin.x -= 1;
5645 else
5647 lpgm->gmBlackBoxY += 2;
5648 lpgm->gmptGlyphOrigin.y += 1;
5652 width = lpgm->gmBlackBoxX;
5653 height = lpgm->gmBlackBoxY;
5654 pitch = width * 4;
5655 needed = pitch * height;
5657 if (!buf || !buflen) break;
5659 memset(buf, 0, buflen);
5660 dst = buf;
5661 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5663 if ( needsTransform )
5664 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5666 if ( pFT_Library_SetLcdFilter )
5667 pFT_Library_SetLcdFilter( library, lcdfilter );
5668 pFT_Render_Glyph (ft_face->glyph, render_mode);
5670 src = ft_face->glyph->bitmap.buffer;
5671 src_pitch = ft_face->glyph->bitmap.pitch;
5672 src_width = ft_face->glyph->bitmap.width;
5673 src_height = ft_face->glyph->bitmap.rows;
5675 if ( render_mode == FT_RENDER_MODE_LCD)
5677 rgb_interval = 1;
5678 hmul = 3;
5679 vmul = 1;
5681 else
5683 rgb_interval = src_pitch;
5684 hmul = 1;
5685 vmul = 3;
5688 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5689 if ( x_shift < 0 ) x_shift = 0;
5690 if ( x_shift + (src_width / hmul) > width )
5691 x_shift = width - (src_width / hmul);
5693 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5694 if ( y_shift < 0 ) y_shift = 0;
5695 if ( y_shift + (src_height / vmul) > height )
5696 y_shift = height - (src_height / vmul);
5698 dst += x_shift + y_shift * ( pitch / 4 );
5699 while ( src_height )
5701 for ( x = 0; x < src_width / hmul; x++ )
5703 if ( rgb )
5705 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5706 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5707 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5708 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5710 else
5712 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5713 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5714 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5715 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5718 src += src_pitch * vmul;
5719 dst += pitch / 4;
5720 src_height -= vmul;
5723 break;
5726 default:
5727 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5728 return GDI_ERROR;
5731 break;
5733 #else
5734 return GDI_ERROR;
5735 #endif
5737 case GGO_NATIVE:
5739 int contour, point = 0, first_pt;
5740 FT_Outline *outline = &ft_face->glyph->outline;
5741 TTPOLYGONHEADER *pph;
5742 TTPOLYCURVE *ppc;
5743 DWORD pph_start, cpfx, type;
5745 if(buflen == 0) buf = NULL;
5747 if (needsTransform && buf) {
5748 pFT_Outline_Transform(outline, &transMat);
5751 for(contour = 0; contour < outline->n_contours; contour++) {
5752 pph_start = needed;
5753 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5754 first_pt = point;
5755 if(buf) {
5756 pph->dwType = TT_POLYGON_TYPE;
5757 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5759 needed += sizeof(*pph);
5760 point++;
5761 while(point <= outline->contours[contour]) {
5762 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5763 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5764 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5765 cpfx = 0;
5766 do {
5767 if(buf)
5768 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5769 cpfx++;
5770 point++;
5771 } while(point <= outline->contours[contour] &&
5772 (outline->tags[point] & FT_Curve_Tag_On) ==
5773 (outline->tags[point-1] & FT_Curve_Tag_On));
5774 /* At the end of a contour Windows adds the start point, but
5775 only for Beziers */
5776 if(point > outline->contours[contour] &&
5777 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5778 if(buf)
5779 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5780 cpfx++;
5781 } else if(point <= outline->contours[contour] &&
5782 outline->tags[point] & FT_Curve_Tag_On) {
5783 /* add closing pt for bezier */
5784 if(buf)
5785 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5786 cpfx++;
5787 point++;
5789 if(buf) {
5790 ppc->wType = type;
5791 ppc->cpfx = cpfx;
5793 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5795 if(buf)
5796 pph->cb = needed - pph_start;
5798 break;
5800 case GGO_BEZIER:
5802 /* Convert the quadratic Beziers to cubic Beziers.
5803 The parametric eqn for a cubic Bezier is, from PLRM:
5804 r(t) = at^3 + bt^2 + ct + r0
5805 with the control points:
5806 r1 = r0 + c/3
5807 r2 = r1 + (c + b)/3
5808 r3 = r0 + c + b + a
5810 A quadratic Bezier has the form:
5811 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5813 So equating powers of t leads to:
5814 r1 = 2/3 p1 + 1/3 p0
5815 r2 = 2/3 p1 + 1/3 p2
5816 and of course r0 = p0, r3 = p2
5819 int contour, point = 0, first_pt;
5820 FT_Outline *outline = &ft_face->glyph->outline;
5821 TTPOLYGONHEADER *pph;
5822 TTPOLYCURVE *ppc;
5823 DWORD pph_start, cpfx, type;
5824 FT_Vector cubic_control[4];
5825 if(buflen == 0) buf = NULL;
5827 if (needsTransform && buf) {
5828 pFT_Outline_Transform(outline, &transMat);
5831 for(contour = 0; contour < outline->n_contours; contour++) {
5832 pph_start = needed;
5833 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5834 first_pt = point;
5835 if(buf) {
5836 pph->dwType = TT_POLYGON_TYPE;
5837 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5839 needed += sizeof(*pph);
5840 point++;
5841 while(point <= outline->contours[contour]) {
5842 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5843 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5844 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5845 cpfx = 0;
5846 do {
5847 if(type == TT_PRIM_LINE) {
5848 if(buf)
5849 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5850 cpfx++;
5851 point++;
5852 } else {
5853 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5854 so cpfx = 3n */
5856 /* FIXME: Possible optimization in endpoint calculation
5857 if there are two consecutive curves */
5858 cubic_control[0] = outline->points[point-1];
5859 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5860 cubic_control[0].x += outline->points[point].x + 1;
5861 cubic_control[0].y += outline->points[point].y + 1;
5862 cubic_control[0].x >>= 1;
5863 cubic_control[0].y >>= 1;
5865 if(point+1 > outline->contours[contour])
5866 cubic_control[3] = outline->points[first_pt];
5867 else {
5868 cubic_control[3] = outline->points[point+1];
5869 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5870 cubic_control[3].x += outline->points[point].x + 1;
5871 cubic_control[3].y += outline->points[point].y + 1;
5872 cubic_control[3].x >>= 1;
5873 cubic_control[3].y >>= 1;
5876 /* r1 = 1/3 p0 + 2/3 p1
5877 r2 = 1/3 p2 + 2/3 p1 */
5878 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5879 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5880 cubic_control[2] = cubic_control[1];
5881 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5882 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5883 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5884 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5885 if(buf) {
5886 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5887 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5888 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5890 cpfx += 3;
5891 point++;
5893 } while(point <= outline->contours[contour] &&
5894 (outline->tags[point] & FT_Curve_Tag_On) ==
5895 (outline->tags[point-1] & FT_Curve_Tag_On));
5896 /* At the end of a contour Windows adds the start point,
5897 but only for Beziers and we've already done that.
5899 if(point <= outline->contours[contour] &&
5900 outline->tags[point] & FT_Curve_Tag_On) {
5901 /* This is the closing pt of a bezier, but we've already
5902 added it, so just inc point and carry on */
5903 point++;
5905 if(buf) {
5906 ppc->wType = type;
5907 ppc->cpfx = cpfx;
5909 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5911 if(buf)
5912 pph->cb = needed - pph_start;
5914 break;
5917 default:
5918 FIXME("Unsupported format %d\n", format);
5919 return GDI_ERROR;
5921 return needed;
5924 static BOOL get_bitmap_text_metrics(GdiFont *font)
5926 FT_Face ft_face = font->ft_face;
5927 FT_WinFNT_HeaderRec winfnt_header;
5928 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5929 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5930 font->potm->otmSize = size;
5932 #define TM font->potm->otmTextMetrics
5933 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5935 TM.tmHeight = winfnt_header.pixel_height;
5936 TM.tmAscent = winfnt_header.ascent;
5937 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5938 TM.tmInternalLeading = winfnt_header.internal_leading;
5939 TM.tmExternalLeading = winfnt_header.external_leading;
5940 TM.tmAveCharWidth = winfnt_header.avg_width;
5941 TM.tmMaxCharWidth = winfnt_header.max_width;
5942 TM.tmWeight = winfnt_header.weight;
5943 TM.tmOverhang = 0;
5944 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5945 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5946 TM.tmFirstChar = winfnt_header.first_char;
5947 TM.tmLastChar = winfnt_header.last_char;
5948 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5949 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5950 TM.tmItalic = winfnt_header.italic;
5951 TM.tmUnderlined = font->underline;
5952 TM.tmStruckOut = font->strikeout;
5953 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5954 TM.tmCharSet = winfnt_header.charset;
5956 else
5958 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5959 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5960 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5961 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5962 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5963 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5964 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5965 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5966 TM.tmOverhang = 0;
5967 TM.tmDigitizedAspectX = 96; /* FIXME */
5968 TM.tmDigitizedAspectY = 96; /* FIXME */
5969 TM.tmFirstChar = 1;
5970 TM.tmLastChar = 255;
5971 TM.tmDefaultChar = 32;
5972 TM.tmBreakChar = 32;
5973 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5974 TM.tmUnderlined = font->underline;
5975 TM.tmStruckOut = font->strikeout;
5976 /* NB inverted meaning of TMPF_FIXED_PITCH */
5977 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5978 TM.tmCharSet = font->charset;
5980 #undef TM
5982 return TRUE;
5986 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5988 double scale_x, scale_y;
5990 if (font->aveWidth)
5992 scale_x = (double)font->aveWidth;
5993 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5995 else
5996 scale_x = font->scale_y;
5998 scale_x *= fabs(font->font_desc.matrix.eM11);
5999 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6001 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6002 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6004 SCALE_Y(ptm->tmHeight);
6005 SCALE_Y(ptm->tmAscent);
6006 SCALE_Y(ptm->tmDescent);
6007 SCALE_Y(ptm->tmInternalLeading);
6008 SCALE_Y(ptm->tmExternalLeading);
6009 SCALE_Y(ptm->tmOverhang);
6011 SCALE_X(ptm->tmAveCharWidth);
6012 SCALE_X(ptm->tmMaxCharWidth);
6014 #undef SCALE_X
6015 #undef SCALE_Y
6018 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6020 double scale_x, scale_y;
6022 if (font->aveWidth)
6024 scale_x = (double)font->aveWidth;
6025 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6027 else
6028 scale_x = font->scale_y;
6030 scale_x *= fabs(font->font_desc.matrix.eM11);
6031 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6033 scale_font_metrics(font, &potm->otmTextMetrics);
6035 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6036 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6038 SCALE_Y(potm->otmAscent);
6039 SCALE_Y(potm->otmDescent);
6040 SCALE_Y(potm->otmLineGap);
6041 SCALE_Y(potm->otmsCapEmHeight);
6042 SCALE_Y(potm->otmsXHeight);
6043 SCALE_Y(potm->otmrcFontBox.top);
6044 SCALE_Y(potm->otmrcFontBox.bottom);
6045 SCALE_X(potm->otmrcFontBox.left);
6046 SCALE_X(potm->otmrcFontBox.right);
6047 SCALE_Y(potm->otmMacAscent);
6048 SCALE_Y(potm->otmMacDescent);
6049 SCALE_Y(potm->otmMacLineGap);
6050 SCALE_X(potm->otmptSubscriptSize.x);
6051 SCALE_Y(potm->otmptSubscriptSize.y);
6052 SCALE_X(potm->otmptSubscriptOffset.x);
6053 SCALE_Y(potm->otmptSubscriptOffset.y);
6054 SCALE_X(potm->otmptSuperscriptSize.x);
6055 SCALE_Y(potm->otmptSuperscriptSize.y);
6056 SCALE_X(potm->otmptSuperscriptOffset.x);
6057 SCALE_Y(potm->otmptSuperscriptOffset.y);
6058 SCALE_Y(potm->otmsStrikeoutSize);
6059 SCALE_Y(potm->otmsStrikeoutPosition);
6060 SCALE_Y(potm->otmsUnderscoreSize);
6061 SCALE_Y(potm->otmsUnderscorePosition);
6063 #undef SCALE_X
6064 #undef SCALE_Y
6067 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6069 if(!font->potm)
6071 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6073 /* Make sure that the font has sane width/height ratio */
6074 if (font->aveWidth)
6076 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6078 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6079 font->aveWidth = 0;
6083 *ptm = font->potm->otmTextMetrics;
6084 scale_font_metrics(font, ptm);
6085 return TRUE;
6088 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6090 int i;
6092 for(i = 0; i < ft_face->num_charmaps; i++)
6094 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6095 return TRUE;
6097 return FALSE;
6100 static BOOL get_outline_text_metrics(GdiFont *font)
6102 BOOL ret = FALSE;
6103 FT_Face ft_face = font->ft_face;
6104 UINT needed, lenfam, lensty;
6105 TT_OS2 *pOS2;
6106 TT_HoriHeader *pHori;
6107 TT_Postscript *pPost;
6108 FT_Fixed x_scale, y_scale;
6109 WCHAR *family_nameW, *style_nameW;
6110 static const WCHAR spaceW[] = {' ', '\0'};
6111 char *cp;
6112 INT ascent, descent;
6114 TRACE("font=%p\n", font);
6116 if(!FT_IS_SCALABLE(ft_face))
6117 return FALSE;
6119 needed = sizeof(*font->potm);
6121 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6122 family_nameW = strdupW(font->name);
6124 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6125 * sizeof(WCHAR);
6126 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6127 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6128 style_nameW, lensty/sizeof(WCHAR));
6130 /* These names should be read from the TT name table */
6132 /* length of otmpFamilyName */
6133 needed += lenfam;
6135 /* length of otmpFaceName */
6136 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6137 needed += lenfam; /* just the family name */
6138 } else {
6139 needed += lenfam + lensty; /* family + " " + style */
6142 /* length of otmpStyleName */
6143 needed += lensty;
6145 /* length of otmpFullName */
6146 needed += lenfam + lensty;
6149 x_scale = ft_face->size->metrics.x_scale;
6150 y_scale = ft_face->size->metrics.y_scale;
6152 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6153 if(!pOS2) {
6154 FIXME("Can't find OS/2 table - not TT font?\n");
6155 goto end;
6158 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6159 if(!pHori) {
6160 FIXME("Can't find HHEA table - not TT font?\n");
6161 goto end;
6164 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6166 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",
6167 pOS2->usWinAscent, pOS2->usWinDescent,
6168 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6169 ft_face->ascender, ft_face->descender, ft_face->height,
6170 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6171 ft_face->bbox.yMax, ft_face->bbox.yMin);
6173 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6174 font->potm->otmSize = needed;
6176 #define TM font->potm->otmTextMetrics
6178 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6179 ascent = pHori->Ascender;
6180 descent = -pHori->Descender;
6181 } else {
6182 ascent = pOS2->usWinAscent;
6183 descent = pOS2->usWinDescent;
6186 if(font->yMax) {
6187 TM.tmAscent = font->yMax;
6188 TM.tmDescent = -font->yMin;
6189 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6190 } else {
6191 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6192 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6193 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6194 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6197 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6199 /* MSDN says:
6200 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6202 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6203 ((ascent + descent) -
6204 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6206 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6207 if (TM.tmAveCharWidth == 0) {
6208 TM.tmAveCharWidth = 1;
6210 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6211 TM.tmWeight = FW_REGULAR;
6212 if (font->fake_bold)
6213 TM.tmWeight = FW_BOLD;
6214 else
6216 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6218 if (pOS2->usWeightClass > FW_MEDIUM)
6219 TM.tmWeight = pOS2->usWeightClass;
6221 else if (pOS2->usWeightClass <= FW_MEDIUM)
6222 TM.tmWeight = pOS2->usWeightClass;
6224 TM.tmOverhang = 0;
6225 TM.tmDigitizedAspectX = 300;
6226 TM.tmDigitizedAspectY = 300;
6227 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6228 * symbol range to 0 - f0ff
6231 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6233 TM.tmFirstChar = 0;
6234 switch(GetACP())
6236 case 1257: /* Baltic */
6237 TM.tmLastChar = 0xf8fd;
6238 break;
6239 default:
6240 TM.tmLastChar = 0xf0ff;
6242 TM.tmBreakChar = 0x20;
6243 TM.tmDefaultChar = 0x1f;
6245 else
6247 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6248 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6250 if(pOS2->usFirstCharIndex <= 1)
6251 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6252 else if (pOS2->usFirstCharIndex > 0xff)
6253 TM.tmBreakChar = 0x20;
6254 else
6255 TM.tmBreakChar = pOS2->usFirstCharIndex;
6256 TM.tmDefaultChar = TM.tmBreakChar - 1;
6258 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6259 TM.tmUnderlined = font->underline;
6260 TM.tmStruckOut = font->strikeout;
6262 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6263 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6264 (pOS2->version == 0xFFFFU ||
6265 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6266 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6267 else
6268 TM.tmPitchAndFamily = 0;
6270 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6272 case PAN_FAMILY_SCRIPT:
6273 TM.tmPitchAndFamily |= FF_SCRIPT;
6274 break;
6276 case PAN_FAMILY_DECORATIVE:
6277 TM.tmPitchAndFamily |= FF_DECORATIVE;
6278 break;
6280 case PAN_ANY:
6281 case PAN_NO_FIT:
6282 case PAN_FAMILY_TEXT_DISPLAY:
6283 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6284 /* which is clearly not what the panose spec says. */
6285 default:
6286 if(TM.tmPitchAndFamily == 0 || /* fixed */
6287 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6288 TM.tmPitchAndFamily = FF_MODERN;
6289 else
6291 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6293 case PAN_ANY:
6294 case PAN_NO_FIT:
6295 default:
6296 TM.tmPitchAndFamily |= FF_DONTCARE;
6297 break;
6299 case PAN_SERIF_COVE:
6300 case PAN_SERIF_OBTUSE_COVE:
6301 case PAN_SERIF_SQUARE_COVE:
6302 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6303 case PAN_SERIF_SQUARE:
6304 case PAN_SERIF_THIN:
6305 case PAN_SERIF_BONE:
6306 case PAN_SERIF_EXAGGERATED:
6307 case PAN_SERIF_TRIANGLE:
6308 TM.tmPitchAndFamily |= FF_ROMAN;
6309 break;
6311 case PAN_SERIF_NORMAL_SANS:
6312 case PAN_SERIF_OBTUSE_SANS:
6313 case PAN_SERIF_PERP_SANS:
6314 case PAN_SERIF_FLARED:
6315 case PAN_SERIF_ROUNDED:
6316 TM.tmPitchAndFamily |= FF_SWISS;
6317 break;
6320 break;
6323 if(FT_IS_SCALABLE(ft_face))
6324 TM.tmPitchAndFamily |= TMPF_VECTOR;
6326 if(FT_IS_SFNT(ft_face))
6328 if (font->ntmFlags & NTM_PS_OPENTYPE)
6329 TM.tmPitchAndFamily |= TMPF_DEVICE;
6330 else
6331 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6334 TM.tmCharSet = font->charset;
6336 font->potm->otmFiller = 0;
6337 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6338 font->potm->otmfsSelection = pOS2->fsSelection;
6339 font->potm->otmfsType = pOS2->fsType;
6340 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6341 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6342 font->potm->otmItalicAngle = 0; /* POST table */
6343 font->potm->otmEMSquare = ft_face->units_per_EM;
6344 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6345 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6346 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6347 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6348 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6349 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6350 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6351 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6352 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6353 font->potm->otmMacAscent = TM.tmAscent;
6354 font->potm->otmMacDescent = -TM.tmDescent;
6355 font->potm->otmMacLineGap = font->potm->otmLineGap;
6356 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6357 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6358 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6359 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6360 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6361 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6362 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6363 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6364 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6365 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6366 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6367 if(!pPost) {
6368 font->potm->otmsUnderscoreSize = 0;
6369 font->potm->otmsUnderscorePosition = 0;
6370 } else {
6371 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6372 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6374 #undef TM
6376 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6377 cp = (char*)font->potm + sizeof(*font->potm);
6378 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6379 strcpyW((WCHAR*)cp, family_nameW);
6380 cp += lenfam;
6381 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6382 strcpyW((WCHAR*)cp, style_nameW);
6383 cp += lensty;
6384 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6385 strcpyW((WCHAR*)cp, family_nameW);
6386 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6387 strcatW((WCHAR*)cp, spaceW);
6388 strcatW((WCHAR*)cp, style_nameW);
6389 cp += lenfam + lensty;
6390 } else
6391 cp += lenfam;
6392 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6393 strcpyW((WCHAR*)cp, family_nameW);
6394 strcatW((WCHAR*)cp, spaceW);
6395 strcatW((WCHAR*)cp, style_nameW);
6396 ret = TRUE;
6398 end:
6399 HeapFree(GetProcessHeap(), 0, style_nameW);
6400 HeapFree(GetProcessHeap(), 0, family_nameW);
6401 return ret;
6404 /*************************************************************
6405 * freetype_GetGlyphOutline
6407 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6408 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6410 struct freetype_physdev *physdev = get_freetype_dev( dev );
6411 DWORD ret;
6413 if (!physdev->font)
6415 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6416 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6419 GDI_CheckNotLock();
6420 EnterCriticalSection( &freetype_cs );
6421 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6422 LeaveCriticalSection( &freetype_cs );
6423 return ret;
6426 /*************************************************************
6427 * freetype_GetTextMetrics
6429 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6431 struct freetype_physdev *physdev = get_freetype_dev( dev );
6432 BOOL ret;
6434 if (!physdev->font)
6436 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6437 return dev->funcs->pGetTextMetrics( dev, metrics );
6440 GDI_CheckNotLock();
6441 EnterCriticalSection( &freetype_cs );
6442 ret = get_text_metrics( physdev->font, metrics );
6443 LeaveCriticalSection( &freetype_cs );
6444 return ret;
6447 /*************************************************************
6448 * freetype_GetOutlineTextMetrics
6450 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6452 struct freetype_physdev *physdev = get_freetype_dev( dev );
6453 UINT ret = 0;
6455 if (!physdev->font)
6457 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6458 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6461 TRACE("font=%p\n", physdev->font);
6463 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6465 GDI_CheckNotLock();
6466 EnterCriticalSection( &freetype_cs );
6468 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6470 if(cbSize >= physdev->font->potm->otmSize)
6472 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6473 scale_outline_font_metrics(physdev->font, potm);
6475 ret = physdev->font->potm->otmSize;
6477 LeaveCriticalSection( &freetype_cs );
6478 return ret;
6481 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6483 HFONTLIST *hfontlist;
6484 child->font = alloc_font();
6485 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6486 if(!child->font->ft_face)
6488 free_font(child->font);
6489 child->font = NULL;
6490 return FALSE;
6493 child->font->font_desc = font->font_desc;
6494 child->font->ntmFlags = child->face->ntmFlags;
6495 child->font->orientation = font->orientation;
6496 child->font->scale_y = font->scale_y;
6497 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6498 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6499 child->font->name = strdupW(child->face->family->FamilyName);
6500 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6501 child->font->base_font = font;
6502 list_add_head(&child_font_list, &child->font->entry);
6503 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6504 return TRUE;
6507 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6509 FT_UInt g;
6510 CHILD_FONT *child_font;
6512 if(font->base_font)
6513 font = font->base_font;
6515 *linked_font = font;
6517 if((*glyph = get_glyph_index(font, c)))
6519 *glyph = get_GSUB_vert_glyph(font, *glyph);
6520 return TRUE;
6523 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6525 if(!child_font->font)
6526 if(!load_child_font(font, child_font))
6527 continue;
6529 if(!child_font->font->ft_face)
6530 continue;
6531 g = get_glyph_index(child_font->font, c);
6532 g = get_GSUB_vert_glyph(child_font->font, g);
6533 if(g)
6535 *glyph = g;
6536 *linked_font = child_font->font;
6537 return TRUE;
6540 return FALSE;
6543 /*************************************************************
6544 * freetype_GetCharWidth
6546 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6548 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6549 UINT c;
6550 GLYPHMETRICS gm;
6551 FT_UInt glyph_index;
6552 GdiFont *linked_font;
6553 struct freetype_physdev *physdev = get_freetype_dev( dev );
6555 if (!physdev->font)
6557 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6558 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6561 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6563 GDI_CheckNotLock();
6564 EnterCriticalSection( &freetype_cs );
6565 for(c = firstChar; c <= lastChar; c++) {
6566 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6567 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6568 &gm, 0, NULL, &identity);
6569 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6571 LeaveCriticalSection( &freetype_cs );
6572 return TRUE;
6575 /*************************************************************
6576 * freetype_GetCharABCWidths
6578 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6580 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6581 UINT c;
6582 GLYPHMETRICS gm;
6583 FT_UInt glyph_index;
6584 GdiFont *linked_font;
6585 struct freetype_physdev *physdev = get_freetype_dev( dev );
6587 if (!physdev->font)
6589 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6590 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6593 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6595 GDI_CheckNotLock();
6596 EnterCriticalSection( &freetype_cs );
6598 for(c = firstChar; c <= lastChar; c++) {
6599 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6600 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6601 &gm, 0, NULL, &identity);
6602 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6603 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6604 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6605 FONT_GM(linked_font,glyph_index)->bbx;
6607 LeaveCriticalSection( &freetype_cs );
6608 return TRUE;
6611 /*************************************************************
6612 * freetype_GetCharABCWidthsI
6614 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6616 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6617 UINT c;
6618 GLYPHMETRICS gm;
6619 FT_UInt glyph_index;
6620 GdiFont *linked_font;
6621 struct freetype_physdev *physdev = get_freetype_dev( dev );
6623 if (!physdev->font)
6625 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6626 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6629 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6630 return FALSE;
6632 GDI_CheckNotLock();
6633 EnterCriticalSection( &freetype_cs );
6635 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6636 if (!pgi)
6637 for(c = firstChar; c < firstChar+count; c++) {
6638 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6639 &gm, 0, NULL, &identity);
6640 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6641 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6642 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6643 - FONT_GM(linked_font,c)->bbx;
6645 else
6646 for(c = 0; c < count; c++) {
6647 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6648 &gm, 0, NULL, &identity);
6649 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6650 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6651 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6652 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6655 LeaveCriticalSection( &freetype_cs );
6656 return TRUE;
6659 /*************************************************************
6660 * freetype_GetTextExtentExPoint
6662 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6663 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6665 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6666 INT idx;
6667 INT nfit = 0, ext;
6668 GLYPHMETRICS gm;
6669 TEXTMETRICW tm;
6670 FT_UInt glyph_index;
6671 GdiFont *linked_font;
6672 struct freetype_physdev *physdev = get_freetype_dev( dev );
6674 if (!physdev->font)
6676 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6677 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6680 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6682 GDI_CheckNotLock();
6683 EnterCriticalSection( &freetype_cs );
6685 size->cx = 0;
6686 get_text_metrics( physdev->font, &tm );
6687 size->cy = tm.tmHeight;
6689 for(idx = 0; idx < count; idx++) {
6690 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6691 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6692 &gm, 0, NULL, &identity);
6693 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6694 ext = size->cx;
6695 if (! pnfit || ext <= max_ext) {
6696 ++nfit;
6697 if (dxs)
6698 dxs[idx] = ext;
6702 if (pnfit)
6703 *pnfit = nfit;
6705 LeaveCriticalSection( &freetype_cs );
6706 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6707 return TRUE;
6710 /*************************************************************
6711 * freetype_GetTextExtentExPointI
6713 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6714 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6716 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6717 INT idx;
6718 INT nfit = 0, ext;
6719 GLYPHMETRICS gm;
6720 TEXTMETRICW tm;
6721 struct freetype_physdev *physdev = get_freetype_dev( dev );
6723 if (!physdev->font)
6725 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6726 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6729 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6731 GDI_CheckNotLock();
6732 EnterCriticalSection( &freetype_cs );
6734 size->cx = 0;
6735 get_text_metrics(physdev->font, &tm);
6736 size->cy = tm.tmHeight;
6738 for(idx = 0; idx < count; idx++) {
6739 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6740 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6741 ext = size->cx;
6742 if (! pnfit || ext <= max_ext) {
6743 ++nfit;
6744 if (dxs)
6745 dxs[idx] = ext;
6749 if (pnfit)
6750 *pnfit = nfit;
6752 LeaveCriticalSection( &freetype_cs );
6753 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6754 return TRUE;
6757 /*************************************************************
6758 * freetype_GetFontData
6760 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6762 struct freetype_physdev *physdev = get_freetype_dev( dev );
6764 if (!physdev->font)
6766 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6767 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6770 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6771 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6772 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6774 return get_font_data( physdev->font, table, offset, buf, cbData );
6777 /*************************************************************
6778 * freetype_GetTextFace
6780 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6782 INT n;
6783 struct freetype_physdev *physdev = get_freetype_dev( dev );
6785 if (!physdev->font)
6787 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6788 return dev->funcs->pGetTextFace( dev, count, str );
6791 n = strlenW(physdev->font->name) + 1;
6792 if (str)
6794 lstrcpynW(str, physdev->font->name, count);
6795 n = min(count, n);
6797 return n;
6800 /*************************************************************
6801 * freetype_GetTextCharsetInfo
6803 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6805 struct freetype_physdev *physdev = get_freetype_dev( dev );
6807 if (!physdev->font)
6809 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6810 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6812 if (fs) *fs = physdev->font->fs;
6813 return physdev->font->charset;
6816 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6818 GdiFont *font = dc->gdiFont, *linked_font;
6819 struct list *first_hfont;
6820 BOOL ret;
6822 GDI_CheckNotLock();
6823 EnterCriticalSection( &freetype_cs );
6824 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6825 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6826 if(font == linked_font)
6827 *new_hfont = dc->hFont;
6828 else
6830 first_hfont = list_head(&linked_font->hfontlist);
6831 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6833 LeaveCriticalSection( &freetype_cs );
6834 return ret;
6837 /* Retrieve a list of supported Unicode ranges for a given font.
6838 * Can be called with NULL gs to calculate the buffer size. Returns
6839 * the number of ranges found.
6841 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6843 DWORD num_ranges = 0;
6845 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6847 FT_UInt glyph_code;
6848 FT_ULong char_code, char_code_prev;
6850 glyph_code = 0;
6851 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6853 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6854 face->num_glyphs, glyph_code, char_code);
6856 if (!glyph_code) return 0;
6858 if (gs)
6860 gs->ranges[0].wcLow = (USHORT)char_code;
6861 gs->ranges[0].cGlyphs = 0;
6862 gs->cGlyphsSupported = 0;
6865 num_ranges = 1;
6866 while (glyph_code)
6868 if (char_code < char_code_prev)
6870 ERR("expected increasing char code from FT_Get_Next_Char\n");
6871 return 0;
6873 if (char_code - char_code_prev > 1)
6875 num_ranges++;
6876 if (gs)
6878 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6879 gs->ranges[num_ranges - 1].cGlyphs = 1;
6880 gs->cGlyphsSupported++;
6883 else if (gs)
6885 gs->ranges[num_ranges - 1].cGlyphs++;
6886 gs->cGlyphsSupported++;
6888 char_code_prev = char_code;
6889 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6892 else
6893 FIXME("encoding %u not supported\n", face->charmap->encoding);
6895 return num_ranges;
6898 /*************************************************************
6899 * freetype_GetFontUnicodeRanges
6901 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6903 struct freetype_physdev *physdev = get_freetype_dev( dev );
6904 DWORD size, num_ranges;
6906 if (!physdev->font)
6908 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6909 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6912 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6913 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6914 if (glyphset)
6916 glyphset->cbThis = size;
6917 glyphset->cRanges = num_ranges;
6918 glyphset->flAccel = 0;
6920 return size;
6923 /*************************************************************
6924 * freetype_FontIsLinked
6926 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6928 struct freetype_physdev *physdev = get_freetype_dev( dev );
6929 BOOL ret;
6931 if (!physdev->font)
6933 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6934 return dev->funcs->pFontIsLinked( dev );
6937 GDI_CheckNotLock();
6938 EnterCriticalSection( &freetype_cs );
6939 ret = !list_empty(&physdev->font->child_fonts);
6940 LeaveCriticalSection( &freetype_cs );
6941 return ret;
6944 static BOOL is_hinting_enabled(void)
6946 /* Use the >= 2.2.0 function if available */
6947 if(pFT_Get_TrueType_Engine_Type)
6949 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6950 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6952 #ifdef FT_DRIVER_HAS_HINTER
6953 else
6955 FT_Module mod;
6957 /* otherwise if we've been compiled with < 2.2.0 headers
6958 use the internal macro */
6959 mod = pFT_Get_Module(library, "truetype");
6960 if(mod && FT_DRIVER_HAS_HINTER(mod))
6961 return TRUE;
6963 #endif
6965 return FALSE;
6968 static BOOL is_subpixel_rendering_enabled( void )
6970 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6971 return pFT_Library_SetLcdFilter &&
6972 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6973 #else
6974 return FALSE;
6975 #endif
6978 /*************************************************************************
6979 * GetRasterizerCaps (GDI32.@)
6981 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6983 static int hinting = -1;
6984 static int subpixel = -1;
6986 if(hinting == -1)
6988 hinting = is_hinting_enabled();
6989 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6992 if ( subpixel == -1 )
6994 subpixel = is_subpixel_rendering_enabled();
6995 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6998 lprs->nSize = sizeof(RASTERIZER_STATUS);
6999 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7000 if ( subpixel )
7001 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7002 lprs->nLanguageID = 0;
7003 return TRUE;
7006 /*************************************************************
7007 * freetype_GdiRealizationInfo
7009 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7011 struct freetype_physdev *physdev = get_freetype_dev( dev );
7012 realization_info_t *info = ptr;
7014 if (!physdev->font)
7016 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7017 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7020 FIXME("(%p, %p): stub!\n", physdev->font, info);
7022 info->flags = 1;
7023 if(FT_IS_SCALABLE(physdev->font->ft_face))
7024 info->flags |= 2;
7026 info->cache_num = physdev->font->cache_num;
7027 info->unknown2 = -1;
7028 return TRUE;
7031 /*************************************************************************
7032 * Kerning support for TrueType fonts
7034 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7036 struct TT_kern_table
7038 USHORT version;
7039 USHORT nTables;
7042 struct TT_kern_subtable
7044 USHORT version;
7045 USHORT length;
7046 union
7048 USHORT word;
7049 struct
7051 USHORT horizontal : 1;
7052 USHORT minimum : 1;
7053 USHORT cross_stream: 1;
7054 USHORT override : 1;
7055 USHORT reserved1 : 4;
7056 USHORT format : 8;
7057 } bits;
7058 } coverage;
7061 struct TT_format0_kern_subtable
7063 USHORT nPairs;
7064 USHORT searchRange;
7065 USHORT entrySelector;
7066 USHORT rangeShift;
7069 struct TT_kern_pair
7071 USHORT left;
7072 USHORT right;
7073 short value;
7076 static DWORD parse_format0_kern_subtable(GdiFont *font,
7077 const struct TT_format0_kern_subtable *tt_f0_ks,
7078 const USHORT *glyph_to_char,
7079 KERNINGPAIR *kern_pair, DWORD cPairs)
7081 USHORT i, nPairs;
7082 const struct TT_kern_pair *tt_kern_pair;
7084 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7086 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7088 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7089 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7090 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7092 if (!kern_pair || !cPairs)
7093 return nPairs;
7095 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7097 nPairs = min(nPairs, cPairs);
7099 for (i = 0; i < nPairs; i++)
7101 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7102 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7103 /* this algorithm appears to better match what Windows does */
7104 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7105 if (kern_pair->iKernAmount < 0)
7107 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7108 kern_pair->iKernAmount -= font->ppem;
7110 else if (kern_pair->iKernAmount > 0)
7112 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7113 kern_pair->iKernAmount += font->ppem;
7115 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7117 TRACE("left %u right %u value %d\n",
7118 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7120 kern_pair++;
7122 TRACE("copied %u entries\n", nPairs);
7123 return nPairs;
7126 /*************************************************************
7127 * freetype_GetKerningPairs
7129 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7131 DWORD length;
7132 void *buf;
7133 const struct TT_kern_table *tt_kern_table;
7134 const struct TT_kern_subtable *tt_kern_subtable;
7135 USHORT i, nTables;
7136 USHORT *glyph_to_char;
7137 GdiFont *font;
7138 struct freetype_physdev *physdev = get_freetype_dev( dev );
7140 if (!(font = physdev->font))
7142 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7143 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7146 GDI_CheckNotLock();
7147 EnterCriticalSection( &freetype_cs );
7148 if (font->total_kern_pairs != (DWORD)-1)
7150 if (cPairs && kern_pair)
7152 cPairs = min(cPairs, font->total_kern_pairs);
7153 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7155 else cPairs = font->total_kern_pairs;
7157 LeaveCriticalSection( &freetype_cs );
7158 return cPairs;
7161 font->total_kern_pairs = 0;
7163 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7165 if (length == GDI_ERROR)
7167 TRACE("no kerning data in the font\n");
7168 LeaveCriticalSection( &freetype_cs );
7169 return 0;
7172 buf = HeapAlloc(GetProcessHeap(), 0, length);
7173 if (!buf)
7175 WARN("Out of memory\n");
7176 LeaveCriticalSection( &freetype_cs );
7177 return 0;
7180 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7182 /* build a glyph index to char code map */
7183 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7184 if (!glyph_to_char)
7186 WARN("Out of memory allocating a glyph index to char code map\n");
7187 HeapFree(GetProcessHeap(), 0, buf);
7188 LeaveCriticalSection( &freetype_cs );
7189 return 0;
7192 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7194 FT_UInt glyph_code;
7195 FT_ULong char_code;
7197 glyph_code = 0;
7198 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7200 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7201 font->ft_face->num_glyphs, glyph_code, char_code);
7203 while (glyph_code)
7205 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7207 /* FIXME: This doesn't match what Windows does: it does some fancy
7208 * things with duplicate glyph index to char code mappings, while
7209 * we just avoid overriding existing entries.
7211 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7212 glyph_to_char[glyph_code] = (USHORT)char_code;
7214 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7217 else
7219 ULONG n;
7221 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7222 for (n = 0; n <= 65535; n++)
7223 glyph_to_char[n] = (USHORT)n;
7226 tt_kern_table = buf;
7227 nTables = GET_BE_WORD(tt_kern_table->nTables);
7228 TRACE("version %u, nTables %u\n",
7229 GET_BE_WORD(tt_kern_table->version), nTables);
7231 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7233 for (i = 0; i < nTables; i++)
7235 struct TT_kern_subtable tt_kern_subtable_copy;
7237 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7238 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7239 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7241 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7242 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7243 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7245 /* According to the TrueType specification this is the only format
7246 * that will be properly interpreted by Windows and OS/2
7248 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7250 DWORD new_chunk, old_total = font->total_kern_pairs;
7252 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7253 glyph_to_char, NULL, 0);
7254 font->total_kern_pairs += new_chunk;
7256 if (!font->kern_pairs)
7257 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7258 font->total_kern_pairs * sizeof(*font->kern_pairs));
7259 else
7260 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7261 font->total_kern_pairs * sizeof(*font->kern_pairs));
7263 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7264 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7266 else
7267 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7269 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7272 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7273 HeapFree(GetProcessHeap(), 0, buf);
7275 if (cPairs && kern_pair)
7277 cPairs = min(cPairs, font->total_kern_pairs);
7278 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7280 else cPairs = font->total_kern_pairs;
7282 LeaveCriticalSection( &freetype_cs );
7283 return cPairs;
7286 static const struct gdi_dc_funcs freetype_funcs =
7288 NULL, /* pAbortDoc */
7289 NULL, /* pAbortPath */
7290 NULL, /* pAlphaBlend */
7291 NULL, /* pAngleArc */
7292 NULL, /* pArc */
7293 NULL, /* pArcTo */
7294 NULL, /* pBeginPath */
7295 NULL, /* pBlendImage */
7296 NULL, /* pChoosePixelFormat */
7297 NULL, /* pChord */
7298 NULL, /* pCloseFigure */
7299 NULL, /* pCopyBitmap */
7300 NULL, /* pCreateBitmap */
7301 NULL, /* pCreateCompatibleDC */
7302 freetype_CreateDC, /* pCreateDC */
7303 NULL, /* pDeleteBitmap */
7304 freetype_DeleteDC, /* pDeleteDC */
7305 NULL, /* pDeleteObject */
7306 NULL, /* pDescribePixelFormat */
7307 NULL, /* pDeviceCapabilities */
7308 NULL, /* pEllipse */
7309 NULL, /* pEndDoc */
7310 NULL, /* pEndPage */
7311 NULL, /* pEndPath */
7312 freetype_EnumFonts, /* pEnumFonts */
7313 NULL, /* pEnumICMProfiles */
7314 NULL, /* pExcludeClipRect */
7315 NULL, /* pExtDeviceMode */
7316 NULL, /* pExtEscape */
7317 NULL, /* pExtFloodFill */
7318 NULL, /* pExtSelectClipRgn */
7319 NULL, /* pExtTextOut */
7320 NULL, /* pFillPath */
7321 NULL, /* pFillRgn */
7322 NULL, /* pFlattenPath */
7323 freetype_FontIsLinked, /* pFontIsLinked */
7324 NULL, /* pFrameRgn */
7325 NULL, /* pGdiComment */
7326 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7327 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7328 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7329 freetype_GetCharWidth, /* pGetCharWidth */
7330 NULL, /* pGetDeviceCaps */
7331 NULL, /* pGetDeviceGammaRamp */
7332 freetype_GetFontData, /* pGetFontData */
7333 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7334 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7335 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7336 NULL, /* pGetICMProfile */
7337 NULL, /* pGetImage */
7338 freetype_GetKerningPairs, /* pGetKerningPairs */
7339 NULL, /* pGetNearestColor */
7340 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7341 NULL, /* pGetPixel */
7342 NULL, /* pGetPixelFormat */
7343 NULL, /* pGetSystemPaletteEntries */
7344 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7345 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7346 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7347 freetype_GetTextFace, /* pGetTextFace */
7348 freetype_GetTextMetrics, /* pGetTextMetrics */
7349 NULL, /* pGradientFill */
7350 NULL, /* pIntersectClipRect */
7351 NULL, /* pInvertRgn */
7352 NULL, /* pLineTo */
7353 NULL, /* pModifyWorldTransform */
7354 NULL, /* pMoveTo */
7355 NULL, /* pOffsetClipRgn */
7356 NULL, /* pOffsetViewportOrg */
7357 NULL, /* pOffsetWindowOrg */
7358 NULL, /* pPaintRgn */
7359 NULL, /* pPatBlt */
7360 NULL, /* pPie */
7361 NULL, /* pPolyBezier */
7362 NULL, /* pPolyBezierTo */
7363 NULL, /* pPolyDraw */
7364 NULL, /* pPolyPolygon */
7365 NULL, /* pPolyPolyline */
7366 NULL, /* pPolygon */
7367 NULL, /* pPolyline */
7368 NULL, /* pPolylineTo */
7369 NULL, /* pPutImage */
7370 NULL, /* pRealizeDefaultPalette */
7371 NULL, /* pRealizePalette */
7372 NULL, /* pRectangle */
7373 NULL, /* pResetDC */
7374 NULL, /* pRestoreDC */
7375 NULL, /* pRoundRect */
7376 NULL, /* pSaveDC */
7377 NULL, /* pScaleViewportExt */
7378 NULL, /* pScaleWindowExt */
7379 NULL, /* pSelectBitmap */
7380 NULL, /* pSelectBrush */
7381 NULL, /* pSelectClipPath */
7382 freetype_SelectFont, /* pSelectFont */
7383 NULL, /* pSelectPalette */
7384 NULL, /* pSelectPen */
7385 NULL, /* pSetArcDirection */
7386 NULL, /* pSetBkColor */
7387 NULL, /* pSetBkMode */
7388 NULL, /* pSetDCBrushColor */
7389 NULL, /* pSetDCPenColor */
7390 NULL, /* pSetDIBColorTable */
7391 NULL, /* pSetDIBitsToDevice */
7392 NULL, /* pSetDeviceClipping */
7393 NULL, /* pSetDeviceGammaRamp */
7394 NULL, /* pSetLayout */
7395 NULL, /* pSetMapMode */
7396 NULL, /* pSetMapperFlags */
7397 NULL, /* pSetPixel */
7398 NULL, /* pSetPixelFormat */
7399 NULL, /* pSetPolyFillMode */
7400 NULL, /* pSetROP2 */
7401 NULL, /* pSetRelAbs */
7402 NULL, /* pSetStretchBltMode */
7403 NULL, /* pSetTextAlign */
7404 NULL, /* pSetTextCharacterExtra */
7405 NULL, /* pSetTextColor */
7406 NULL, /* pSetTextJustification */
7407 NULL, /* pSetViewportExt */
7408 NULL, /* pSetViewportOrg */
7409 NULL, /* pSetWindowExt */
7410 NULL, /* pSetWindowOrg */
7411 NULL, /* pSetWorldTransform */
7412 NULL, /* pStartDoc */
7413 NULL, /* pStartPage */
7414 NULL, /* pStretchBlt */
7415 NULL, /* pStretchDIBits */
7416 NULL, /* pStrokeAndFillPath */
7417 NULL, /* pStrokePath */
7418 NULL, /* pSwapBuffers */
7419 NULL, /* pUnrealizePalette */
7420 NULL, /* pWidenPath */
7421 /* OpenGL not supported */
7424 #else /* HAVE_FREETYPE */
7426 /*************************************************************************/
7428 BOOL WineEngInit(void)
7430 return FALSE;
7432 BOOL WineEngDestroyFontInstance(HFONT hfont)
7434 return FALSE;
7437 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7439 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7440 return 1;
7443 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7445 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7446 return TRUE;
7449 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7451 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7452 return NULL;
7455 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7457 return FALSE;
7460 /*************************************************************************
7461 * GetRasterizerCaps (GDI32.@)
7463 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7465 lprs->nSize = sizeof(RASTERIZER_STATUS);
7466 lprs->wFlags = 0;
7467 lprs->nLanguageID = 0;
7468 return TRUE;
7471 #endif /* HAVE_FREETYPE */