gdi32: Fix a build failure on Mac OS X.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blobef2f152053db63d361bb35de0c3ab347bd6e73d7
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 FONTSIGNATURE fs_links;
269 DWORD ntmFlags;
270 FT_Fixed font_version;
271 BOOL scalable;
272 BOOL vertical;
273 Bitmap_Size size; /* set if face is a bitmap */
274 BOOL external; /* TRUE if we should manually add this font to the registry */
275 struct tagFamily *family;
276 /* Cached data for Enum */
277 struct enum_data *cached_enum_data;
278 } Face;
280 typedef struct tagFamily {
281 struct list entry;
282 const WCHAR *FamilyName;
283 const WCHAR *EnglishName;
284 struct list faces;
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 struct list links;
355 } SYSTEM_LINKS;
357 struct enum_charset_element {
358 DWORD mask;
359 DWORD charset;
360 WCHAR name[LF_FACESIZE];
363 struct enum_charset_list {
364 DWORD total;
365 struct enum_charset_element element[32];
368 #define GM_BLOCK_SIZE 128
369 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
371 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
372 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
373 #define UNUSED_CACHE_SIZE 10
374 static struct list child_font_list = LIST_INIT(child_font_list);
375 static struct list system_links = LIST_INIT(system_links);
377 static struct list font_subst_list = LIST_INIT(font_subst_list);
379 static struct list font_list = LIST_INIT(font_list);
381 struct freetype_physdev
383 struct gdi_physdev dev;
384 GdiFont *font;
387 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
389 return (struct freetype_physdev *)dev;
392 static const struct gdi_dc_funcs freetype_funcs;
394 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
395 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
396 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
398 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
399 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
400 'W','i','n','d','o','w','s','\\',
401 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
402 'F','o','n','t','s','\0'};
404 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
405 'W','i','n','d','o','w','s',' ','N','T','\\',
406 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
407 'F','o','n','t','s','\0'};
409 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
410 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
411 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
412 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
414 static const WCHAR * const SystemFontValues[] = {
415 System_Value,
416 OEMFont_Value,
417 FixedSys_Value,
418 NULL
421 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
422 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
424 /* Interesting and well-known (frequently-assumed!) font names */
425 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
426 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 };
427 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
428 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
429 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
430 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
431 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
432 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
434 static const WCHAR arial[] = {'A','r','i','a','l',0};
435 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
436 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};
437 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};
438 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
439 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
440 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
441 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
442 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
443 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
445 static const WCHAR *default_serif_list[] =
447 times_new_roman,
448 liberation_serif,
449 bitstream_vera_serif,
450 NULL
453 static const WCHAR *default_fixed_list[] =
455 courier_new,
456 liberation_mono,
457 bitstream_vera_sans_mono,
458 NULL
461 static const WCHAR *default_sans_list[] =
463 arial,
464 liberation_sans,
465 bitstream_vera_sans,
466 NULL
469 typedef struct {
470 WCHAR *name;
471 INT charset;
472 } NameCs;
474 typedef struct tagFontSubst {
475 struct list entry;
476 NameCs from;
477 NameCs to;
478 } FontSubst;
480 /* Registry font cache key and value names */
481 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
482 'F','o','n','t','s',0};
483 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
484 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
485 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
486 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
487 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
488 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
489 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
490 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
491 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
492 static const WCHAR face_size_value[] = {'S','i','z','e',0};
493 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
494 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
495 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
496 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
497 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
500 struct font_mapping
502 struct list entry;
503 int refcount;
504 dev_t dev;
505 ino_t ino;
506 void *data;
507 size_t size;
510 static struct list mappings_list = LIST_INIT( mappings_list );
512 static CRITICAL_SECTION freetype_cs;
513 static CRITICAL_SECTION_DEBUG critsect_debug =
515 0, 0, &freetype_cs,
516 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
517 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
519 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
521 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
523 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
524 static BOOL use_default_fallback = FALSE;
526 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
527 static BOOL get_outline_text_metrics(GdiFont *font);
528 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
530 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
531 'W','i','n','d','o','w','s',' ','N','T','\\',
532 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
533 'S','y','s','t','e','m','L','i','n','k',0};
535 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
536 'F','o','n','t','L','i','n','k','\\',
537 'S','y','s','t','e','m','L','i','n','k',0};
539 /****************************************
540 * Notes on .fon files
542 * The fonts System, FixedSys and Terminal are special. There are typically multiple
543 * versions installed for different resolutions and codepages. Windows stores which one to use
544 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
545 * Key Meaning
546 * FIXEDFON.FON FixedSys
547 * FONTS.FON System
548 * OEMFONT.FON Terminal
549 * LogPixels Current dpi set by the display control panel applet
550 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
551 * also has a LogPixels value that appears to mirror this)
553 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
554 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
555 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
556 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
557 * so that makes sense.
559 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
560 * to be mapped into the registry on Windows 2000 at least).
561 * I have
562 * woafont=app850.fon
563 * ega80woa.fon=ega80850.fon
564 * ega40woa.fon=ega40850.fon
565 * cga80woa.fon=cga80850.fon
566 * cga40woa.fon=cga40850.fon
569 /* These are all structures needed for the GSUB table */
571 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
572 #define TATEGAKI_LOWER_BOUND 0x02F1
574 typedef struct {
575 DWORD version;
576 WORD ScriptList;
577 WORD FeatureList;
578 WORD LookupList;
579 } GSUB_Header;
581 typedef struct {
582 CHAR ScriptTag[4];
583 WORD Script;
584 } GSUB_ScriptRecord;
586 typedef struct {
587 WORD ScriptCount;
588 GSUB_ScriptRecord ScriptRecord[1];
589 } GSUB_ScriptList;
591 typedef struct {
592 CHAR LangSysTag[4];
593 WORD LangSys;
594 } GSUB_LangSysRecord;
596 typedef struct {
597 WORD DefaultLangSys;
598 WORD LangSysCount;
599 GSUB_LangSysRecord LangSysRecord[1];
600 } GSUB_Script;
602 typedef struct {
603 WORD LookupOrder; /* Reserved */
604 WORD ReqFeatureIndex;
605 WORD FeatureCount;
606 WORD FeatureIndex[1];
607 } GSUB_LangSys;
609 typedef struct {
610 CHAR FeatureTag[4];
611 WORD Feature;
612 } GSUB_FeatureRecord;
614 typedef struct {
615 WORD FeatureCount;
616 GSUB_FeatureRecord FeatureRecord[1];
617 } GSUB_FeatureList;
619 typedef struct {
620 WORD FeatureParams; /* Reserved */
621 WORD LookupCount;
622 WORD LookupListIndex[1];
623 } GSUB_Feature;
625 typedef struct {
626 WORD LookupCount;
627 WORD Lookup[1];
628 } GSUB_LookupList;
630 typedef struct {
631 WORD LookupType;
632 WORD LookupFlag;
633 WORD SubTableCount;
634 WORD SubTable[1];
635 } GSUB_LookupTable;
637 typedef struct {
638 WORD CoverageFormat;
639 WORD GlyphCount;
640 WORD GlyphArray[1];
641 } GSUB_CoverageFormat1;
643 typedef struct {
644 WORD Start;
645 WORD End;
646 WORD StartCoverageIndex;
647 } GSUB_RangeRecord;
649 typedef struct {
650 WORD CoverageFormat;
651 WORD RangeCount;
652 GSUB_RangeRecord RangeRecord[1];
653 } GSUB_CoverageFormat2;
655 typedef struct {
656 WORD SubstFormat; /* = 1 */
657 WORD Coverage;
658 WORD DeltaGlyphID;
659 } GSUB_SingleSubstFormat1;
661 typedef struct {
662 WORD SubstFormat; /* = 2 */
663 WORD Coverage;
664 WORD GlyphCount;
665 WORD Substitute[1];
666 }GSUB_SingleSubstFormat2;
668 #ifdef HAVE_CARBON_CARBON_H
669 static char *find_cache_dir(void)
671 FSRef ref;
672 OSErr err;
673 static char cached_path[MAX_PATH];
674 static const char *wine = "/Wine", *fonts = "/Fonts";
676 if(*cached_path) return cached_path;
678 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
679 if(err != noErr)
681 WARN("can't create cached data folder\n");
682 return NULL;
684 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
685 if(err != noErr)
687 WARN("can't create cached data path\n");
688 *cached_path = '\0';
689 return NULL;
691 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
693 ERR("Could not create full path\n");
694 *cached_path = '\0';
695 return NULL;
697 strcat(cached_path, wine);
699 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
701 WARN("Couldn't mkdir %s\n", cached_path);
702 *cached_path = '\0';
703 return NULL;
705 strcat(cached_path, fonts);
706 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
708 WARN("Couldn't mkdir %s\n", cached_path);
709 *cached_path = '\0';
710 return NULL;
712 return cached_path;
715 /******************************************************************
716 * expand_mac_font
718 * Extracts individual TrueType font files from a Mac suitcase font
719 * and saves them into the user's caches directory (see
720 * find_cache_dir()).
721 * Returns a NULL terminated array of filenames.
723 * We do this because they are apps that try to read ttf files
724 * themselves and they don't like Mac suitcase files.
726 static char **expand_mac_font(const char *path)
728 FSRef ref;
729 SInt16 res_ref;
730 OSStatus s;
731 unsigned int idx;
732 const char *out_dir;
733 const char *filename;
734 int output_len;
735 struct {
736 char **array;
737 unsigned int size, max_size;
738 } ret;
740 TRACE("path %s\n", path);
742 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
743 if(s != noErr)
745 WARN("failed to get ref\n");
746 return NULL;
749 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
750 if(s != noErr)
752 TRACE("no data fork, so trying resource fork\n");
753 res_ref = FSOpenResFile(&ref, fsRdPerm);
754 if(res_ref == -1)
756 TRACE("unable to open resource fork\n");
757 return NULL;
761 ret.size = 0;
762 ret.max_size = 10;
763 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
764 if(!ret.array)
766 CloseResFile(res_ref);
767 return NULL;
770 out_dir = find_cache_dir();
772 filename = strrchr(path, '/');
773 if(!filename) filename = path;
774 else filename++;
776 /* output filename has the form out_dir/filename_%04x.ttf */
777 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
779 UseResFile(res_ref);
780 idx = 1;
781 while(1)
783 FamRec *fam_rec;
784 unsigned short *num_faces_ptr, num_faces, face;
785 AsscEntry *assoc;
786 Handle fond;
787 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
789 fond = Get1IndResource(fond_res, idx);
790 if(!fond) break;
791 TRACE("got fond resource %d\n", idx);
792 HLock(fond);
794 fam_rec = *(FamRec**)fond;
795 num_faces_ptr = (unsigned short *)(fam_rec + 1);
796 num_faces = GET_BE_WORD(*num_faces_ptr);
797 num_faces++;
798 assoc = (AsscEntry*)(num_faces_ptr + 1);
799 TRACE("num faces %04x\n", num_faces);
800 for(face = 0; face < num_faces; face++, assoc++)
802 Handle sfnt;
803 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
804 unsigned short size, font_id;
805 char *output;
807 size = GET_BE_WORD(assoc->fontSize);
808 font_id = GET_BE_WORD(assoc->fontID);
809 if(size != 0)
811 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
812 continue;
815 TRACE("trying to load sfnt id %04x\n", font_id);
816 sfnt = GetResource(sfnt_res, font_id);
817 if(!sfnt)
819 TRACE("can't get sfnt resource %04x\n", font_id);
820 continue;
823 output = HeapAlloc(GetProcessHeap(), 0, output_len);
824 if(output)
826 int fd;
828 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
830 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
831 if(fd != -1 || errno == EEXIST)
833 if(fd != -1)
835 unsigned char *sfnt_data;
837 HLock(sfnt);
838 sfnt_data = *(unsigned char**)sfnt;
839 write(fd, sfnt_data, GetHandleSize(sfnt));
840 HUnlock(sfnt);
841 close(fd);
843 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
845 ret.max_size *= 2;
846 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
848 ret.array[ret.size++] = output;
850 else
852 WARN("unable to create %s\n", output);
853 HeapFree(GetProcessHeap(), 0, output);
856 ReleaseResource(sfnt);
858 HUnlock(fond);
859 ReleaseResource(fond);
860 idx++;
862 CloseResFile(res_ref);
864 return ret.array;
867 #endif /* HAVE_CARBON_CARBON_H */
869 static inline BOOL is_win9x(void)
871 return GetVersion() & 0x80000000;
874 This function builds an FT_Fixed from a double. It fails if the absolute
875 value of the float number is greater than 32768.
877 static inline FT_Fixed FT_FixedFromFloat(double f)
879 return f * 0x10000;
883 This function builds an FT_Fixed from a FIXED. It simply put f.value
884 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
886 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
888 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
892 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
894 Family *family;
895 Face *face;
896 const char *file;
897 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
898 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
900 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
901 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
903 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
905 if(face_name && strcmpiW(face_name, family->FamilyName))
906 continue;
907 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
909 if (!face->file)
910 continue;
911 file = strrchr(face->file, '/');
912 if(!file)
913 file = face->file;
914 else
915 file++;
916 if(!strcasecmp(file, file_nameA))
918 HeapFree(GetProcessHeap(), 0, file_nameA);
919 return face;
923 HeapFree(GetProcessHeap(), 0, file_nameA);
924 return NULL;
927 static Family *find_family_from_name(const WCHAR *name)
929 Family *family;
931 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
933 if(!strcmpiW(family->FamilyName, name))
934 return family;
937 return NULL;
940 static Family *find_family_from_any_name(const WCHAR *name)
942 Family *family;
944 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
946 if(!strcmpiW(family->FamilyName, name))
947 return family;
948 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
949 return family;
952 return NULL;
955 static void DumpSubstList(void)
957 FontSubst *psub;
959 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
961 if(psub->from.charset != -1 || psub->to.charset != -1)
962 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
963 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
964 else
965 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
966 debugstr_w(psub->to.name));
968 return;
971 static LPWSTR strdupW(LPCWSTR p)
973 LPWSTR ret;
974 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
975 ret = HeapAlloc(GetProcessHeap(), 0, len);
976 memcpy(ret, p, len);
977 return ret;
980 static LPSTR strdupA(LPCSTR p)
982 LPSTR ret;
983 DWORD len = (strlen(p) + 1);
984 ret = HeapAlloc(GetProcessHeap(), 0, len);
985 memcpy(ret, p, len);
986 return ret;
989 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
990 INT from_charset)
992 FontSubst *element;
994 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
996 if(!strcmpiW(element->from.name, from_name) &&
997 (element->from.charset == from_charset ||
998 element->from.charset == -1))
999 return element;
1002 return NULL;
1005 #define ADD_FONT_SUBST_FORCE 1
1007 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1009 FontSubst *from_exist, *to_exist;
1011 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1013 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1015 list_remove(&from_exist->entry);
1016 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1017 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1018 HeapFree(GetProcessHeap(), 0, from_exist);
1019 from_exist = NULL;
1022 if(!from_exist)
1024 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1026 if(to_exist)
1028 HeapFree(GetProcessHeap(), 0, subst->to.name);
1029 subst->to.name = strdupW(to_exist->to.name);
1032 list_add_tail(subst_list, &subst->entry);
1034 return TRUE;
1037 HeapFree(GetProcessHeap(), 0, subst->from.name);
1038 HeapFree(GetProcessHeap(), 0, subst->to.name);
1039 HeapFree(GetProcessHeap(), 0, subst);
1040 return FALSE;
1043 static WCHAR *towstr(UINT cp, const char *str)
1045 int len;
1046 WCHAR *wstr;
1048 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1049 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1050 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1051 return wstr;
1054 static void split_subst_info(NameCs *nc, LPSTR str)
1056 CHAR *p = strrchr(str, ',');
1058 nc->charset = -1;
1059 if(p && *(p+1)) {
1060 nc->charset = strtol(p+1, NULL, 10);
1061 *p = '\0';
1063 nc->name = towstr(CP_ACP, str);
1066 static void LoadSubstList(void)
1068 FontSubst *psub;
1069 HKEY hkey;
1070 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1071 LPSTR value;
1072 LPVOID data;
1074 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1075 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1076 &hkey) == ERROR_SUCCESS) {
1078 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1079 &valuelen, &datalen, NULL, NULL);
1081 valuelen++; /* returned value doesn't include room for '\0' */
1082 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1083 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1085 dlen = datalen;
1086 vlen = valuelen;
1087 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1088 &dlen) == ERROR_SUCCESS) {
1089 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1091 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1092 split_subst_info(&psub->from, value);
1093 split_subst_info(&psub->to, data);
1095 /* Win 2000 doesn't allow mapping between different charsets
1096 or mapping of DEFAULT_CHARSET */
1097 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1098 psub->to.charset == DEFAULT_CHARSET) {
1099 HeapFree(GetProcessHeap(), 0, psub->to.name);
1100 HeapFree(GetProcessHeap(), 0, psub->from.name);
1101 HeapFree(GetProcessHeap(), 0, psub);
1102 } else {
1103 add_font_subst(&font_subst_list, psub, 0);
1105 /* reset dlen and vlen */
1106 dlen = datalen;
1107 vlen = valuelen;
1109 HeapFree(GetProcessHeap(), 0, data);
1110 HeapFree(GetProcessHeap(), 0, value);
1111 RegCloseKey(hkey);
1116 /*****************************************************************
1117 * get_name_table_entry
1119 * Supply the platform, encoding, language and name ids in req
1120 * and if the name exists the function will fill in the string
1121 * and string_len members. The string is owned by FreeType so
1122 * don't free it. Returns TRUE if the name is found else FALSE.
1124 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1126 FT_SfntName name;
1127 FT_UInt num_names, name_index;
1129 if(FT_IS_SFNT(ft_face))
1131 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1133 for(name_index = 0; name_index < num_names; name_index++)
1135 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1137 if((name.platform_id == req->platform_id) &&
1138 (name.encoding_id == req->encoding_id) &&
1139 (name.language_id == req->language_id) &&
1140 (name.name_id == req->name_id))
1142 req->string = name.string;
1143 req->string_len = name.string_len;
1144 return TRUE;
1149 req->string = NULL;
1150 req->string_len = 0;
1151 return FALSE;
1154 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1156 WCHAR *ret = NULL;
1157 FT_SfntName name;
1159 name.platform_id = TT_PLATFORM_MICROSOFT;
1160 name.encoding_id = TT_MS_ID_UNICODE_CS;
1161 name.language_id = language_id;
1162 name.name_id = name_id;
1164 if(get_name_table_entry(ft_face, &name))
1166 FT_UInt i;
1168 /* String is not nul terminated and string_len is a byte length. */
1169 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1170 for(i = 0; i < name.string_len / 2; i++)
1172 WORD *tmp = (WORD *)&name.string[i * 2];
1173 ret[i] = GET_BE_WORD(*tmp);
1175 ret[i] = 0;
1176 TRACE("Got localised name %s\n", debugstr_w(ret));
1179 return ret;
1182 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1184 DWORD type, needed;
1185 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1186 if(r != ERROR_SUCCESS) return r;
1187 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1188 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1191 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1193 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1196 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1198 DWORD needed;
1199 DWORD num_strikes, max_strike_key_len;
1201 /* If we have a File Name key then this is a real font, not just the parent
1202 key of a bunch of non-scalable strikes */
1203 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1205 DWORD italic, bold;
1206 Face *face;
1207 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1208 face->cached_enum_data = NULL;
1210 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1211 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1213 face->StyleName = strdupW(face_name);
1214 face->family = family;
1215 face->vertical = (family->FamilyName[0] == '@');
1217 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1219 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1220 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1221 face->FullName = fullName;
1223 else
1224 face->FullName = NULL;
1226 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1227 reg_load_dword(hkey_face, face_italic_value, &italic);
1228 reg_load_dword(hkey_face, face_bold_value, &bold);
1229 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1230 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1232 needed = sizeof(face->fs);
1233 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1234 memset(&face->fs_links, 0, sizeof(face->fs_links));
1236 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1238 face->scalable = TRUE;
1239 memset(&face->size, 0, sizeof(face->size));
1241 else
1243 face->scalable = FALSE;
1244 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1245 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1246 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1247 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1248 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1250 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1251 face->size.height, face->size.width, face->size.size >> 6,
1252 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1255 face->ntmFlags = 0;
1256 if (italic) face->ntmFlags |= NTM_ITALIC;
1257 if (bold) face->ntmFlags |= NTM_BOLD;
1258 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1260 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1261 face->fs.fsCsb[0], face->fs.fsCsb[1],
1262 face->fs.fsUsb[0], face->fs.fsUsb[1],
1263 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1265 if(!italic && !bold)
1266 list_add_head(&family->faces, &face->entry);
1267 else
1268 list_add_tail(&family->faces, &face->entry);
1270 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1273 /* do we have any bitmap strikes? */
1274 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1275 NULL, NULL, NULL, NULL);
1276 if(num_strikes != 0)
1278 WCHAR strike_name[10];
1279 DWORD strike_index = 0;
1281 needed = sizeof(strike_name) / sizeof(WCHAR);
1282 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1283 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1285 HKEY hkey_strike;
1286 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1287 load_face(hkey_strike, face_name, family);
1288 RegCloseKey(hkey_strike);
1289 needed = sizeof(strike_name) / sizeof(WCHAR);
1294 static void load_font_list_from_cache(HKEY hkey_font_cache)
1296 DWORD max_family_key_len, size;
1297 WCHAR *family_name;
1298 DWORD family_index = 0;
1299 Family *family;
1300 HKEY hkey_family;
1302 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1303 NULL, NULL, NULL, NULL);
1304 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1306 size = max_family_key_len + 1;
1307 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1308 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1310 WCHAR *english_family = NULL;
1311 DWORD face_index = 0;
1312 WCHAR *face_name;
1313 DWORD max_face_key_len;
1315 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1316 TRACE("opened family key %s\n", debugstr_w(family_name));
1317 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1319 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1320 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1323 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1324 family->FamilyName = strdupW(family_name);
1325 family->EnglishName = english_family;
1326 list_init(&family->faces);
1327 list_add_tail(&font_list, &family->entry);
1329 if(english_family)
1331 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1332 subst->from.name = strdupW(english_family);
1333 subst->from.charset = -1;
1334 subst->to.name = strdupW(family_name);
1335 subst->to.charset = -1;
1336 add_font_subst(&font_subst_list, subst, 0);
1339 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1340 NULL, NULL, NULL, NULL);
1342 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1343 size = max_face_key_len + 1;
1344 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1345 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1347 HKEY hkey_face;
1349 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1350 load_face(hkey_face, face_name, family);
1351 RegCloseKey(hkey_face);
1352 size = max_face_key_len + 1;
1354 HeapFree(GetProcessHeap(), 0, face_name);
1355 RegCloseKey(hkey_family);
1356 size = max_family_key_len + 1;
1359 HeapFree(GetProcessHeap(), 0, family_name);
1362 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1364 LONG ret;
1365 HKEY hkey_wine_fonts;
1367 /* We don't want to create the fonts key as volatile, so open this first */
1368 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1369 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1370 if(ret != ERROR_SUCCESS)
1372 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1373 return ret;
1376 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1377 KEY_ALL_ACCESS, NULL, hkey, disposition);
1378 RegCloseKey(hkey_wine_fonts);
1379 return ret;
1382 static void add_face_to_cache(Face *face)
1384 HKEY hkey_font_cache, hkey_family, hkey_face;
1385 WCHAR *face_key_name;
1387 create_font_cache_key(&hkey_font_cache, NULL);
1389 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1390 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1391 if(face->family->EnglishName)
1392 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1393 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1395 if(face->scalable)
1396 face_key_name = face->StyleName;
1397 else
1399 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1400 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1401 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1403 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1404 &hkey_face, NULL);
1405 if(!face->scalable)
1406 HeapFree(GetProcessHeap(), 0, face_key_name);
1408 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1409 if (face->FullName)
1410 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1411 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1413 reg_save_dword(hkey_face, face_index_value, face->face_index);
1414 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1415 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1416 reg_save_dword(hkey_face, face_version_value, face->font_version);
1417 reg_save_dword(hkey_face, face_external_value, face->external);
1419 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1421 if(!face->scalable)
1423 reg_save_dword(hkey_face, face_height_value, face->size.height);
1424 reg_save_dword(hkey_face, face_width_value, face->size.width);
1425 reg_save_dword(hkey_face, face_size_value, face->size.size);
1426 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1427 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1428 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1430 RegCloseKey(hkey_face);
1431 RegCloseKey(hkey_family);
1432 RegCloseKey(hkey_font_cache);
1435 static inline int TestStyles(DWORD flags, DWORD styles)
1437 return (flags & styles) == styles;
1440 static int StyleOrdering(Face *face)
1442 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1443 return 3;
1444 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1445 return 2;
1446 if (TestStyles(face->ntmFlags, NTM_BOLD))
1447 return 1;
1448 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1449 return 0;
1451 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1452 debugstr_w(face->family->FamilyName),
1453 debugstr_w(face->StyleName),
1454 face->ntmFlags);
1456 return 9999;
1459 /* Add a style of face to a font family using an ordering of the list such
1460 that regular fonts come before bold and italic, and single styles come
1461 before compound styles. */
1462 static void AddFaceToFamily(Face *face, Family *family)
1464 struct list *entry;
1466 LIST_FOR_EACH( entry, &family->faces )
1468 Face *ent = LIST_ENTRY(entry, Face, entry);
1469 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1471 list_add_before( entry, &face->entry );
1474 static WCHAR *prepend_at(WCHAR *family)
1476 WCHAR *str;
1478 if (!family)
1479 return NULL;
1481 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1482 str[0] = '@';
1483 strcpyW(str + 1, family);
1484 HeapFree(GetProcessHeap(), 0, family);
1485 return str;
1488 #define ADDFONT_EXTERNAL_FONT 0x01
1489 #define ADDFONT_FORCE_BITMAP 0x02
1490 #define ADDFONT_ADD_TO_CACHE 0x04
1492 static void AddFaceToList(FT_Face ft_face, char *fake_family, const char *file, void *font_data_ptr, DWORD font_data_size, FT_Long face_index, DWORD flags, BOOL vertical)
1494 int bitmap_num = 0;
1495 Family *family;
1496 WCHAR *StyleW;
1498 do {
1499 TT_OS2 *pOS2;
1500 TT_Header *pHeader;
1501 WCHAR *english_family, *localised_family;
1502 Face *face;
1503 struct list *face_elem_ptr;
1504 FT_WinFNT_HeaderRec winfnt_header;
1505 int internal_leading;
1506 FONTSIGNATURE fs;
1507 My_FT_Bitmap_Size *size = NULL;
1508 FT_ULong tmp_size;
1510 if(!FT_IS_SCALABLE(ft_face))
1511 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1513 if (fake_family)
1515 english_family = towstr(CP_ACP, fake_family);
1516 localised_family = NULL;
1518 else
1520 english_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1521 if (!english_family)
1522 english_family = towstr(CP_ACP, ft_face->family_name);
1524 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1525 if (localised_family && !strcmpiW(localised_family, english_family))
1527 HeapFree(GetProcessHeap(), 0, localised_family);
1528 localised_family = NULL;
1532 if (vertical)
1534 english_family = prepend_at(english_family);
1535 localised_family = prepend_at(localised_family);
1538 family = find_family_from_name(localised_family ? localised_family : english_family);
1539 if(!family) {
1540 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1541 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1542 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1543 list_init(&family->faces);
1544 list_add_tail(&font_list, &family->entry);
1546 if(localised_family) {
1547 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1548 subst->from.name = strdupW(english_family);
1549 subst->from.charset = -1;
1550 subst->to.name = strdupW(localised_family);
1551 subst->to.charset = -1;
1552 add_font_subst(&font_subst_list, subst, 0);
1555 HeapFree(GetProcessHeap(), 0, localised_family);
1556 HeapFree(GetProcessHeap(), 0, english_family);
1558 StyleW = towstr(CP_ACP, ft_face->style_name);
1560 internal_leading = 0;
1561 memset(&fs, 0, sizeof(fs));
1563 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1564 if(pOS2) {
1565 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1566 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1567 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1568 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1569 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1570 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1571 if(pOS2->version == 0) {
1572 FT_UInt dummy;
1574 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1575 fs.fsCsb[0] |= FS_LATIN1;
1576 else
1577 fs.fsCsb[0] |= FS_SYMBOL;
1580 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1581 CHARSETINFO csi;
1582 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1583 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1584 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1585 fs = csi.fs;
1586 internal_leading = winfnt_header.internal_leading;
1589 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1590 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1591 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1592 if(!strcmpiW(face->StyleName, StyleW) &&
1593 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1594 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1595 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1596 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1598 if(fake_family) {
1599 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1600 HeapFree(GetProcessHeap(), 0, StyleW);
1601 return;
1603 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1604 TRACE("Original font is newer so skipping this one\n");
1605 HeapFree(GetProcessHeap(), 0, StyleW);
1606 return;
1607 } else {
1608 TRACE("Replacing original with this one\n");
1609 list_remove(&face->entry);
1610 HeapFree(GetProcessHeap(), 0, face->file);
1611 HeapFree(GetProcessHeap(), 0, face->StyleName);
1612 HeapFree(GetProcessHeap(), 0, face->FullName);
1613 HeapFree(GetProcessHeap(), 0, face);
1614 break;
1618 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1619 face->cached_enum_data = NULL;
1620 face->StyleName = StyleW;
1621 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1622 if (file)
1624 face->file = strdupA(file);
1625 face->font_data_ptr = NULL;
1626 face->font_data_size = 0;
1628 else
1630 face->file = NULL;
1631 face->font_data_ptr = font_data_ptr;
1632 face->font_data_size = font_data_size;
1634 face->face_index = face_index;
1635 face->ntmFlags = 0;
1636 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1637 face->ntmFlags |= NTM_ITALIC;
1638 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1639 face->ntmFlags |= NTM_BOLD;
1640 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1641 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1642 face->family = family;
1643 face->vertical = vertical;
1644 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1645 face->fs = fs;
1646 memset(&face->fs_links, 0, sizeof(face->fs_links));
1648 if(FT_IS_SCALABLE(ft_face)) {
1649 memset(&face->size, 0, sizeof(face->size));
1650 face->scalable = TRUE;
1651 } else {
1652 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1653 size->height, size->width, size->size >> 6,
1654 size->x_ppem >> 6, size->y_ppem >> 6);
1655 face->size.height = size->height;
1656 face->size.width = size->width;
1657 face->size.size = size->size;
1658 face->size.x_ppem = size->x_ppem;
1659 face->size.y_ppem = size->y_ppem;
1660 face->size.internal_leading = internal_leading;
1661 face->scalable = FALSE;
1664 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1665 tmp_size = 0;
1666 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1668 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1669 face->ntmFlags |= NTM_PS_OPENTYPE;
1672 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1673 face->fs.fsCsb[0], face->fs.fsCsb[1],
1674 face->fs.fsUsb[0], face->fs.fsUsb[1],
1675 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1677 if(face->fs.fsCsb[0] == 0)
1679 int i;
1681 /* let's see if we can find any interesting cmaps */
1682 for(i = 0; i < ft_face->num_charmaps; i++) {
1683 switch(ft_face->charmaps[i]->encoding) {
1684 case FT_ENCODING_UNICODE:
1685 case FT_ENCODING_APPLE_ROMAN:
1686 face->fs.fsCsb[0] |= FS_LATIN1;
1687 break;
1688 case FT_ENCODING_MS_SYMBOL:
1689 face->fs.fsCsb[0] |= FS_SYMBOL;
1690 break;
1691 default:
1692 break;
1697 if(flags & ADDFONT_ADD_TO_CACHE)
1698 add_face_to_cache(face);
1700 AddFaceToFamily(face, family);
1702 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1704 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1705 debugstr_w(StyleW));
1708 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1710 FT_Face ft_face;
1711 TT_OS2 *pOS2;
1712 TT_Header *pHeader = NULL;
1713 WCHAR *localised_family;
1714 FT_Error err;
1715 FT_Long face_index = 0, num_faces;
1716 INT ret = 0;
1718 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1719 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1721 #ifdef HAVE_CARBON_CARBON_H
1722 if(file && !fake_family)
1724 char **mac_list = expand_mac_font(file);
1725 if(mac_list)
1727 BOOL had_one = FALSE;
1728 char **cursor;
1729 for(cursor = mac_list; *cursor; cursor++)
1731 had_one = TRUE;
1732 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1733 HeapFree(GetProcessHeap(), 0, *cursor);
1735 HeapFree(GetProcessHeap(), 0, mac_list);
1736 if(had_one)
1737 return 1;
1740 #endif /* HAVE_CARBON_CARBON_H */
1742 do {
1743 if (file)
1745 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1746 err = pFT_New_Face(library, file, face_index, &ft_face);
1747 } else
1749 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1750 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1753 if(err != 0) {
1754 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1755 return 0;
1758 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*/
1759 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1760 pFT_Done_Face(ft_face);
1761 return 0;
1764 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1765 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1766 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1767 pFT_Done_Face(ft_face);
1768 return 0;
1771 if(FT_IS_SFNT(ft_face))
1773 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1774 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1775 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1777 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1778 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1779 pFT_Done_Face(ft_face);
1780 return 0;
1783 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1784 we don't want to load these. */
1785 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1787 FT_ULong len = 0;
1789 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1791 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1792 pFT_Done_Face(ft_face);
1793 return 0;
1798 if(!ft_face->family_name || !ft_face->style_name) {
1799 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1800 pFT_Done_Face(ft_face);
1801 return 0;
1804 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1806 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1807 pFT_Done_Face(ft_face);
1808 return 0;
1811 if (target_family)
1813 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1814 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1816 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1817 HeapFree(GetProcessHeap(), 0, localised_family);
1818 num_faces = ft_face->num_faces;
1819 pFT_Done_Face(ft_face);
1820 continue;
1822 HeapFree(GetProcessHeap(), 0, localised_family);
1825 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1826 ++ret;
1828 if (FT_HAS_VERTICAL(ft_face))
1830 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1831 ++ret;
1834 num_faces = ft_face->num_faces;
1835 pFT_Done_Face(ft_face);
1836 } while(num_faces > ++face_index);
1837 return ret;
1840 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1842 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1845 static void DumpFontList(void)
1847 Family *family;
1848 Face *face;
1849 struct list *family_elem_ptr, *face_elem_ptr;
1851 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1852 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1853 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1854 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1855 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1856 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1857 if(!face->scalable)
1858 TRACE(" %d", face->size.height);
1859 TRACE("\n");
1862 return;
1865 /***********************************************************
1866 * The replacement list is a way to map an entire font
1867 * family onto another family. For example adding
1869 * [HKCU\Software\Wine\Fonts\Replacements]
1870 * "Wingdings"="Winedings"
1872 * would enumerate the Winedings font both as Winedings and
1873 * Wingdings. However if a real Wingdings font is present the
1874 * replacement does not take place.
1877 static void LoadReplaceList(void)
1879 HKEY hkey;
1880 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1881 LPWSTR value;
1882 LPVOID data;
1883 CHAR familyA[400];
1885 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1886 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1888 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1889 &valuelen, &datalen, NULL, NULL);
1891 valuelen++; /* returned value doesn't include room for '\0' */
1892 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1893 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1895 dlen = datalen;
1896 vlen = valuelen;
1897 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1898 &dlen) == ERROR_SUCCESS) {
1899 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1900 /* "NewName"="Oldname" */
1901 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1903 if(!find_family_from_any_name(value))
1905 /* Find the old family and hence all of the font files
1906 in that family */
1907 const Family * const family = find_family_from_any_name(data);
1908 if (family != NULL)
1910 const struct list *face_elem_ptr;
1911 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1912 const Face * const face = LIST_ENTRY(face_elem_ptr, Face, entry);
1913 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1914 debugstr_w(face->StyleName), familyA);
1915 /* Now add a new entry with the new family name */
1916 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1917 familyA, family->FamilyName,
1918 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1921 else
1923 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1926 else
1928 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1930 /* reset dlen and vlen */
1931 dlen = datalen;
1932 vlen = valuelen;
1934 HeapFree(GetProcessHeap(), 0, data);
1935 HeapFree(GetProcessHeap(), 0, value);
1936 RegCloseKey(hkey);
1940 static const WCHAR *font_links_list[] =
1942 Lucida_Sans_Unicode,
1943 Microsoft_Sans_Serif,
1944 Tahoma
1947 static const struct font_links_defaults_list
1949 /* Keyed off substitution for "MS Shell Dlg" */
1950 const WCHAR *shelldlg;
1951 /* Maximum of four substitutes, plus terminating NULL pointer */
1952 const WCHAR *substitutes[5];
1953 } font_links_defaults_list[] =
1955 /* Non East-Asian */
1956 { Tahoma, /* FIXME unverified ordering */
1957 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
1959 /* Below lists are courtesy of
1960 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1962 /* Japanese */
1963 { MS_UI_Gothic,
1964 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
1966 /* Chinese Simplified */
1967 { SimSun,
1968 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
1970 /* Korean */
1971 { Gulim,
1972 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
1974 /* Chinese Traditional */
1975 { PMingLiU,
1976 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
1981 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
1983 const WCHAR *value;
1984 int i;
1985 FontSubst *psub;
1986 Family *family;
1987 Face *face;
1988 const char *file;
1989 WCHAR *fileW;
1990 FONTSIGNATURE fs;
1992 if (values)
1994 SYSTEM_LINKS *font_link;
1995 BOOL existing = FALSE;
1997 memset(&fs, 0, sizeof(fs));
1998 psub = get_font_subst(&font_subst_list, name, -1);
1999 /* Don't store fonts that are only substitutes for other fonts */
2000 if(psub)
2002 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2003 return;
2006 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2008 if(!strcmpiW(font_link->font_name, name))
2010 existing = TRUE;
2011 break;
2015 if (!existing)
2017 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2018 font_link->font_name = strdupW(name);
2019 list_init(&font_link->links);
2022 for (i = 0; values[i] != NULL; i++)
2024 CHILD_FONT *child_font;
2026 value = values[i];
2027 if (!strcmpiW(name,value))
2028 continue;
2029 psub = get_font_subst(&font_subst_list, value, -1);
2030 if(psub)
2031 value = psub->to.name;
2032 family = find_family_from_name(value);
2033 if (!family)
2034 continue;
2035 file = NULL;
2036 /* Use first extant filename for this Family */
2037 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2039 if (!face->file)
2040 continue;
2041 file = strrchr(face->file, '/');
2042 if (!file)
2043 file = face->file;
2044 else
2045 file++;
2046 break;
2048 if (!file)
2049 continue;
2050 fileW = towstr(CP_UNIXCP, file);
2052 face = find_face_from_filename(fileW, value);
2053 if(!face)
2055 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2056 continue;
2059 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2060 child_font->face = face;
2061 child_font->font = NULL;
2062 fs.fsCsb[0] |= face->fs.fsCsb[0];
2063 fs.fsCsb[1] |= face->fs.fsCsb[1];
2064 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2065 list_add_tail(&font_link->links, &child_font->entry);
2067 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2068 HeapFree(GetProcessHeap(), 0, fileW);
2071 family = find_family_from_name(font_link->font_name);
2072 if(family)
2074 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2076 face->fs_links = fs;
2079 if (!existing)
2080 list_add_tail(&system_links, &font_link->entry);
2085 /*************************************************************
2086 * init_system_links
2088 static BOOL init_system_links(void)
2090 HKEY hkey;
2091 BOOL ret = FALSE;
2092 DWORD type, max_val, max_data, val_len, data_len, index;
2093 WCHAR *value, *data;
2094 WCHAR *entry, *next;
2095 SYSTEM_LINKS *font_link, *system_font_link;
2096 CHILD_FONT *child_font;
2097 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2098 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2099 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2100 FONTSIGNATURE fs;
2101 Family *family;
2102 Face *face;
2103 FontSubst *psub;
2104 UINT i, j;
2106 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2108 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2109 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2110 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2111 val_len = max_val + 1;
2112 data_len = max_data;
2113 index = 0;
2114 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2116 memset(&fs, 0, sizeof(fs));
2117 psub = get_font_subst(&font_subst_list, value, -1);
2118 /* Don't store fonts that are only substitutes for other fonts */
2119 if(psub)
2121 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2122 goto next;
2124 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2125 font_link->font_name = strdupW(value);
2126 list_init(&font_link->links);
2127 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2129 WCHAR *face_name;
2130 CHILD_FONT *child_font;
2132 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2134 next = entry + strlenW(entry) + 1;
2136 face_name = strchrW(entry, ',');
2137 if(face_name)
2139 *face_name++ = 0;
2140 while(isspaceW(*face_name))
2141 face_name++;
2143 psub = get_font_subst(&font_subst_list, face_name, -1);
2144 if(psub)
2145 face_name = psub->to.name;
2147 face = find_face_from_filename(entry, face_name);
2148 if(!face)
2150 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2151 continue;
2154 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2155 child_font->face = face;
2156 child_font->font = NULL;
2157 fs.fsCsb[0] |= face->fs.fsCsb[0];
2158 fs.fsCsb[1] |= face->fs.fsCsb[1];
2159 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2160 list_add_tail(&font_link->links, &child_font->entry);
2162 family = find_family_from_name(font_link->font_name);
2163 if(family)
2165 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2167 face->fs_links = fs;
2170 list_add_tail(&system_links, &font_link->entry);
2171 next:
2172 val_len = max_val + 1;
2173 data_len = max_data;
2176 HeapFree(GetProcessHeap(), 0, value);
2177 HeapFree(GetProcessHeap(), 0, data);
2178 RegCloseKey(hkey);
2182 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2183 if (!psub) {
2184 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2185 goto skip_internal;
2188 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2190 const FontSubst *psub2;
2191 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2193 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2195 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2196 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2198 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2199 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2201 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2203 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2207 skip_internal:
2209 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2210 that Tahoma has */
2212 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2213 system_font_link->font_name = strdupW(System);
2214 list_init(&system_font_link->links);
2215 memset(&fs, 0, sizeof(fs));
2217 face = find_face_from_filename(tahoma_ttf, Tahoma);
2218 if(face)
2220 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2221 child_font->face = face;
2222 child_font->font = NULL;
2223 fs.fsCsb[0] |= face->fs.fsCsb[0];
2224 fs.fsCsb[1] |= face->fs.fsCsb[1];
2225 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2226 list_add_tail(&system_font_link->links, &child_font->entry);
2228 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2230 if(!strcmpiW(font_link->font_name, Tahoma))
2232 CHILD_FONT *font_link_entry;
2233 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2235 CHILD_FONT *new_child;
2236 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2237 new_child->face = font_link_entry->face;
2238 new_child->font = NULL;
2239 fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2240 fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2241 list_add_tail(&system_font_link->links, &new_child->entry);
2243 break;
2246 family = find_family_from_name(system_font_link->font_name);
2247 if(family)
2249 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2251 face->fs_links = fs;
2254 list_add_tail(&system_links, &system_font_link->entry);
2255 return ret;
2258 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2260 DIR *dir;
2261 struct dirent *dent;
2262 char path[MAX_PATH];
2264 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2266 dir = opendir(dirname);
2267 if(!dir) {
2268 WARN("Can't open directory %s\n", debugstr_a(dirname));
2269 return FALSE;
2271 while((dent = readdir(dir)) != NULL) {
2272 struct stat statbuf;
2274 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2275 continue;
2277 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2279 sprintf(path, "%s/%s", dirname, dent->d_name);
2281 if(stat(path, &statbuf) == -1)
2283 WARN("Can't stat %s\n", debugstr_a(path));
2284 continue;
2286 if(S_ISDIR(statbuf.st_mode))
2287 ReadFontDir(path, external_fonts);
2288 else
2290 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2291 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2292 AddFontFileToList(path, NULL, NULL, addfont_flags);
2295 closedir(dir);
2296 return TRUE;
2299 #ifdef SONAME_LIBFONTCONFIG
2300 static void load_fontconfig_fonts(void)
2302 void *fc_handle = NULL;
2303 FcConfig *config;
2304 FcPattern *pat;
2305 FcObjectSet *os;
2306 FcFontSet *fontset;
2307 int i, len;
2308 char *file;
2309 const char *ext;
2311 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2312 if(!fc_handle) {
2313 TRACE("Wine cannot find the fontconfig library (%s).\n",
2314 SONAME_LIBFONTCONFIG);
2315 return;
2317 #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;}
2318 LOAD_FUNCPTR(FcConfigGetCurrent);
2319 LOAD_FUNCPTR(FcFontList);
2320 LOAD_FUNCPTR(FcFontSetDestroy);
2321 LOAD_FUNCPTR(FcInit);
2322 LOAD_FUNCPTR(FcObjectSetAdd);
2323 LOAD_FUNCPTR(FcObjectSetCreate);
2324 LOAD_FUNCPTR(FcObjectSetDestroy);
2325 LOAD_FUNCPTR(FcPatternCreate);
2326 LOAD_FUNCPTR(FcPatternDestroy);
2327 LOAD_FUNCPTR(FcPatternGetBool);
2328 LOAD_FUNCPTR(FcPatternGetString);
2329 #undef LOAD_FUNCPTR
2331 if(!pFcInit()) return;
2333 config = pFcConfigGetCurrent();
2334 pat = pFcPatternCreate();
2335 os = pFcObjectSetCreate();
2336 pFcObjectSetAdd(os, FC_FILE);
2337 pFcObjectSetAdd(os, FC_SCALABLE);
2338 fontset = pFcFontList(config, pat, os);
2339 if(!fontset) return;
2340 for(i = 0; i < fontset->nfont; i++) {
2341 FcBool scalable;
2343 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2344 continue;
2345 TRACE("fontconfig: %s\n", file);
2347 /* We're just interested in OT/TT fonts for now, so this hack just
2348 picks up the scalable fonts without extensions .pf[ab] to save time
2349 loading every other font */
2351 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2353 TRACE("not scalable\n");
2354 continue;
2357 len = strlen( file );
2358 if(len < 4) continue;
2359 ext = &file[ len - 3 ];
2360 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2361 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2363 pFcFontSetDestroy(fontset);
2364 pFcObjectSetDestroy(os);
2365 pFcPatternDestroy(pat);
2366 sym_not_found:
2367 return;
2370 #elif defined(HAVE_CARBON_CARBON_H)
2372 static void load_mac_font_callback(const void *value, void *context)
2374 CFStringRef pathStr = value;
2375 CFIndex len;
2376 char* path;
2378 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2379 path = HeapAlloc(GetProcessHeap(), 0, len);
2380 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2382 TRACE("font file %s\n", path);
2383 AddFontFileToList(path, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2385 HeapFree(GetProcessHeap(), 0, path);
2388 static void load_mac_fonts(void)
2390 CFStringRef removeDupesKey;
2391 CFBooleanRef removeDupesValue;
2392 CFDictionaryRef options;
2393 CTFontCollectionRef col;
2394 CFArrayRef descs;
2395 CFMutableSetRef paths;
2396 CFIndex i;
2398 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2399 removeDupesValue = kCFBooleanTrue;
2400 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2401 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2402 col = CTFontCollectionCreateFromAvailableFonts(options);
2403 if (options) CFRelease(options);
2404 if (!col)
2406 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2407 return;
2410 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2411 CFRelease(col);
2412 if (!descs)
2414 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2415 return;
2418 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2419 if (!paths)
2421 WARN("CFSetCreateMutable failed\n");
2422 CFRelease(descs);
2423 return;
2426 for (i = 0; i < CFArrayGetCount(descs); i++)
2428 CTFontDescriptorRef desc;
2429 CTFontRef font;
2430 ATSFontRef atsFont;
2431 OSStatus status;
2432 FSRef fsref;
2433 CFURLRef url;
2434 CFStringRef ext;
2435 CFStringRef path;
2437 desc = CFArrayGetValueAtIndex(descs, i);
2439 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2440 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2441 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2442 if (!font) continue;
2444 atsFont = CTFontGetPlatformFont(font, NULL);
2445 if (!atsFont)
2447 CFRelease(font);
2448 continue;
2451 status = ATSFontGetFileReference(atsFont, &fsref);
2452 CFRelease(font);
2453 if (status != noErr) continue;
2455 url = CFURLCreateFromFSRef(NULL, &fsref);
2456 if (!url) continue;
2458 ext = CFURLCopyPathExtension(url);
2459 if (ext)
2461 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2462 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2463 CFRelease(ext);
2464 if (skip)
2466 CFRelease(url);
2467 continue;
2471 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2472 CFRelease(url);
2473 if (!path) continue;
2475 CFSetAddValue(paths, path);
2476 CFRelease(path);
2479 CFRelease(descs);
2481 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2482 CFRelease(paths);
2485 #endif
2487 static BOOL load_font_from_data_dir(LPCWSTR file)
2489 BOOL ret = FALSE;
2490 const char *data_dir = wine_get_data_dir();
2492 if (!data_dir) data_dir = wine_get_build_dir();
2494 if (data_dir)
2496 INT len;
2497 char *unix_name;
2499 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2501 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2503 strcpy(unix_name, data_dir);
2504 strcat(unix_name, "/fonts/");
2506 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2508 EnterCriticalSection( &freetype_cs );
2509 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2510 LeaveCriticalSection( &freetype_cs );
2511 HeapFree(GetProcessHeap(), 0, unix_name);
2513 return ret;
2516 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2518 static const WCHAR slashW[] = {'\\','\0'};
2519 BOOL ret = FALSE;
2520 WCHAR windowsdir[MAX_PATH];
2521 char *unixname;
2523 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2524 strcatW(windowsdir, fontsW);
2525 strcatW(windowsdir, slashW);
2526 strcatW(windowsdir, file);
2527 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2528 EnterCriticalSection( &freetype_cs );
2529 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2530 LeaveCriticalSection( &freetype_cs );
2531 HeapFree(GetProcessHeap(), 0, unixname);
2533 return ret;
2536 static void load_system_fonts(void)
2538 HKEY hkey;
2539 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2540 const WCHAR * const *value;
2541 DWORD dlen, type;
2542 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2543 char *unixname;
2545 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2546 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2547 strcatW(windowsdir, fontsW);
2548 for(value = SystemFontValues; *value; value++) {
2549 dlen = sizeof(data);
2550 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2551 type == REG_SZ) {
2552 BOOL added = FALSE;
2554 sprintfW(pathW, fmtW, windowsdir, data);
2555 if((unixname = wine_get_unix_file_name(pathW))) {
2556 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2557 HeapFree(GetProcessHeap(), 0, unixname);
2559 if (!added)
2560 load_font_from_data_dir(data);
2563 RegCloseKey(hkey);
2567 /*************************************************************
2569 * This adds registry entries for any externally loaded fonts
2570 * (fonts from fontconfig or FontDirs). It also deletes entries
2571 * of no longer existing fonts.
2574 static void update_reg_entries(void)
2576 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2577 LPWSTR valueW;
2578 DWORD len, len_fam;
2579 Family *family;
2580 Face *face;
2581 struct list *family_elem_ptr, *face_elem_ptr;
2582 WCHAR *file;
2583 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2584 static const WCHAR spaceW[] = {' ', '\0'};
2585 char *path;
2587 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2588 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2589 ERR("Can't create Windows font reg key\n");
2590 goto end;
2593 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2594 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2595 ERR("Can't create Windows font reg key\n");
2596 goto end;
2599 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2600 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2601 ERR("Can't create external font reg key\n");
2602 goto end;
2605 /* enumerate the fonts and add external ones to the two keys */
2607 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2608 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2609 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2610 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2611 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2612 if(!face->external) continue;
2613 len = len_fam;
2614 if (!(face->ntmFlags & NTM_REGULAR))
2615 len = len_fam + strlenW(face->StyleName) + 1;
2616 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2617 strcpyW(valueW, family->FamilyName);
2618 if(len != len_fam) {
2619 strcatW(valueW, spaceW);
2620 strcatW(valueW, face->StyleName);
2622 strcatW(valueW, TrueType);
2624 file = wine_get_dos_file_name(face->file);
2625 if(file)
2626 len = strlenW(file) + 1;
2627 else
2629 if((path = strrchr(face->file, '/')) == NULL)
2630 path = face->file;
2631 else
2632 path++;
2633 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2635 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2636 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2638 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2639 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2640 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2642 HeapFree(GetProcessHeap(), 0, file);
2643 HeapFree(GetProcessHeap(), 0, valueW);
2646 end:
2647 if(external_key) RegCloseKey(external_key);
2648 if(win9x_key) RegCloseKey(win9x_key);
2649 if(winnt_key) RegCloseKey(winnt_key);
2650 return;
2653 static void delete_external_font_keys(void)
2655 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2656 DWORD dlen, vlen, datalen, valuelen, i, type;
2657 LPWSTR valueW;
2658 LPVOID data;
2660 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2661 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2662 ERR("Can't create Windows font reg key\n");
2663 goto end;
2666 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2667 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2668 ERR("Can't create Windows font reg key\n");
2669 goto end;
2672 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2673 ERR("Can't create external font reg key\n");
2674 goto end;
2677 /* Delete all external fonts added last time */
2679 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2680 &valuelen, &datalen, NULL, NULL);
2681 valuelen++; /* returned value doesn't include room for '\0' */
2682 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2683 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2685 dlen = datalen * sizeof(WCHAR);
2686 vlen = valuelen;
2687 i = 0;
2688 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2689 &dlen) == ERROR_SUCCESS) {
2691 RegDeleteValueW(winnt_key, valueW);
2692 RegDeleteValueW(win9x_key, valueW);
2693 /* reset dlen and vlen */
2694 dlen = datalen;
2695 vlen = valuelen;
2697 HeapFree(GetProcessHeap(), 0, data);
2698 HeapFree(GetProcessHeap(), 0, valueW);
2700 /* Delete the old external fonts key */
2701 RegCloseKey(external_key);
2702 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2704 end:
2705 if(win9x_key) RegCloseKey(win9x_key);
2706 if(winnt_key) RegCloseKey(winnt_key);
2709 /*************************************************************
2710 * WineEngAddFontResourceEx
2713 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2715 INT ret = 0;
2717 GDI_CheckNotLock();
2719 if (ft_handle) /* do it only if we have freetype up and running */
2721 char *unixname;
2723 if(flags)
2724 FIXME("Ignoring flags %x\n", flags);
2726 if((unixname = wine_get_unix_file_name(file)))
2728 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2730 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2731 EnterCriticalSection( &freetype_cs );
2732 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2733 LeaveCriticalSection( &freetype_cs );
2734 HeapFree(GetProcessHeap(), 0, unixname);
2736 if (!ret && !strchrW(file, '\\')) {
2737 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2738 ret = load_font_from_winfonts_dir(file);
2739 if (!ret) {
2740 /* Try in datadir/fonts (or builddir/fonts),
2741 * needed for Magic the Gathering Online
2743 ret = load_font_from_data_dir(file);
2747 return ret;
2750 /*************************************************************
2751 * WineEngAddFontMemResourceEx
2754 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2756 GDI_CheckNotLock();
2758 if (ft_handle) /* do it only if we have freetype up and running */
2760 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2762 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2763 memcpy(pFontCopy, pbFont, cbFont);
2765 EnterCriticalSection( &freetype_cs );
2766 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2767 LeaveCriticalSection( &freetype_cs );
2769 if (*pcFonts == 0)
2771 TRACE("AddFontToList failed\n");
2772 HeapFree(GetProcessHeap(), 0, pFontCopy);
2773 return 0;
2775 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2776 * For now return something unique but quite random
2778 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2779 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2782 *pcFonts = 0;
2783 return 0;
2786 /*************************************************************
2787 * WineEngRemoveFontResourceEx
2790 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2792 GDI_CheckNotLock();
2793 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2794 return TRUE;
2797 static const struct nls_update_font_list
2799 UINT ansi_cp, oem_cp;
2800 const char *oem, *fixed, *system;
2801 const char *courier, *serif, *small, *sserif;
2802 /* these are for font substitutes */
2803 const char *shelldlg, *tmsrmn;
2804 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2805 *helv_0, *tmsrmn_0;
2806 const struct subst
2808 const char *from, *to;
2809 } arial_0, courier_new_0, times_new_roman_0;
2810 } nls_update_font_list[] =
2812 /* Latin 1 (United States) */
2813 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2814 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2815 "Tahoma","Times New Roman",
2816 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2817 { 0 }, { 0 }, { 0 }
2819 /* Latin 1 (Multilingual) */
2820 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2821 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2822 "Tahoma","Times New Roman", /* FIXME unverified */
2823 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2824 { 0 }, { 0 }, { 0 }
2826 /* Eastern Europe */
2827 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2828 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2829 "Tahoma","Times New Roman", /* FIXME unverified */
2830 "Fixedsys,238", "System,238",
2831 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2832 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2833 { "Arial CE,0", "Arial,238" },
2834 { "Courier New CE,0", "Courier New,238" },
2835 { "Times New Roman CE,0", "Times New Roman,238" }
2837 /* Cyrillic */
2838 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2839 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2840 "Tahoma","Times New Roman", /* FIXME unverified */
2841 "Fixedsys,204", "System,204",
2842 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2843 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2844 { "Arial Cyr,0", "Arial,204" },
2845 { "Courier New Cyr,0", "Courier New,204" },
2846 { "Times New Roman Cyr,0", "Times New Roman,204" }
2848 /* Greek */
2849 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2850 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2851 "Tahoma","Times New Roman", /* FIXME unverified */
2852 "Fixedsys,161", "System,161",
2853 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2854 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2855 { "Arial Greek,0", "Arial,161" },
2856 { "Courier New Greek,0", "Courier New,161" },
2857 { "Times New Roman Greek,0", "Times New Roman,161" }
2859 /* Turkish */
2860 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2861 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2862 "Tahoma","Times New Roman", /* FIXME unverified */
2863 "Fixedsys,162", "System,162",
2864 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2865 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2866 { "Arial Tur,0", "Arial,162" },
2867 { "Courier New Tur,0", "Courier New,162" },
2868 { "Times New Roman Tur,0", "Times New Roman,162" }
2870 /* Hebrew */
2871 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2872 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2873 "Tahoma","Times New Roman", /* FIXME unverified */
2874 "Fixedsys,177", "System,177",
2875 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2876 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2877 { 0 }, { 0 }, { 0 }
2879 /* Arabic */
2880 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2881 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2882 "Tahoma","Times New Roman", /* FIXME unverified */
2883 "Fixedsys,178", "System,178",
2884 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2885 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2886 { 0 }, { 0 }, { 0 }
2888 /* Baltic */
2889 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2890 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2891 "Tahoma","Times New Roman", /* FIXME unverified */
2892 "Fixedsys,186", "System,186",
2893 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2894 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2895 { "Arial Baltic,0", "Arial,186" },
2896 { "Courier New Baltic,0", "Courier New,186" },
2897 { "Times New Roman Baltic,0", "Times New Roman,186" }
2899 /* Vietnamese */
2900 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2901 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2902 "Tahoma","Times New Roman", /* FIXME unverified */
2903 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2904 { 0 }, { 0 }, { 0 }
2906 /* Thai */
2907 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2908 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2909 "Tahoma","Times New Roman", /* FIXME unverified */
2910 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2911 { 0 }, { 0 }, { 0 }
2913 /* Japanese */
2914 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2915 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2916 "MS UI Gothic","MS Serif",
2917 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2918 { 0 }, { 0 }, { 0 }
2920 /* Chinese Simplified */
2921 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2922 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2923 "SimSun", "NSimSun",
2924 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2925 { 0 }, { 0 }, { 0 }
2927 /* Korean */
2928 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2929 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2930 "Gulim", "Batang",
2931 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2932 { 0 }, { 0 }, { 0 }
2934 /* Chinese Traditional */
2935 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2936 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2937 "PMingLiU", "MingLiU",
2938 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2939 { 0 }, { 0 }, { 0 }
2943 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2945 return ( ansi_cp == 932 /* CP932 for Japanese */
2946 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2947 || ansi_cp == 949 /* CP949 for Korean */
2948 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2951 static inline HKEY create_fonts_NT_registry_key(void)
2953 HKEY hkey = 0;
2955 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2956 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2957 return hkey;
2960 static inline HKEY create_fonts_9x_registry_key(void)
2962 HKEY hkey = 0;
2964 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2965 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2966 return hkey;
2969 static inline HKEY create_config_fonts_registry_key(void)
2971 HKEY hkey = 0;
2973 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2974 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2975 return hkey;
2978 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2980 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2981 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2982 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2983 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2986 static void set_value_key(HKEY hkey, const char *name, const char *value)
2988 if (value)
2989 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2990 else if (name)
2991 RegDeleteValueA(hkey, name);
2994 static void update_font_info(void)
2996 char buf[40], cpbuf[40];
2997 DWORD len, type;
2998 HKEY hkey = 0;
2999 UINT i, ansi_cp = 0, oem_cp = 0;
3000 BOOL done = FALSE;
3002 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3003 return;
3005 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3006 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3007 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3008 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3009 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3011 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3012 if (is_dbcs_ansi_cp(ansi_cp))
3013 use_default_fallback = TRUE;
3015 len = sizeof(buf);
3016 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3018 if (!strcmp( buf, cpbuf )) /* already set correctly */
3020 RegCloseKey(hkey);
3021 return;
3023 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
3025 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
3027 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3028 RegCloseKey(hkey);
3030 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3032 HKEY hkey;
3034 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3035 nls_update_font_list[i].oem_cp == oem_cp)
3037 hkey = create_config_fonts_registry_key();
3038 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3039 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3040 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3041 RegCloseKey(hkey);
3043 hkey = create_fonts_NT_registry_key();
3044 add_font_list(hkey, &nls_update_font_list[i]);
3045 RegCloseKey(hkey);
3047 hkey = create_fonts_9x_registry_key();
3048 add_font_list(hkey, &nls_update_font_list[i]);
3049 RegCloseKey(hkey);
3051 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3053 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3054 strlen(nls_update_font_list[i].shelldlg)+1);
3055 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3056 strlen(nls_update_font_list[i].tmsrmn)+1);
3058 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3059 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3060 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3061 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3062 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3063 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3064 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3065 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3067 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3068 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3069 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3071 RegCloseKey(hkey);
3073 done = TRUE;
3075 else
3077 /* Delete the FontSubstitutes from other locales */
3078 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3080 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3081 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3082 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3083 RegCloseKey(hkey);
3087 if (!done)
3088 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3091 static BOOL init_freetype(void)
3093 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3094 if(!ft_handle) {
3095 WINE_MESSAGE(
3096 "Wine cannot find the FreeType font library. To enable Wine to\n"
3097 "use TrueType fonts please install a version of FreeType greater than\n"
3098 "or equal to 2.0.5.\n"
3099 "http://www.freetype.org\n");
3100 return FALSE;
3103 #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;}
3105 LOAD_FUNCPTR(FT_Done_Face)
3106 LOAD_FUNCPTR(FT_Get_Char_Index)
3107 LOAD_FUNCPTR(FT_Get_First_Char)
3108 LOAD_FUNCPTR(FT_Get_Module)
3109 LOAD_FUNCPTR(FT_Get_Next_Char)
3110 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3111 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3112 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3113 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3114 LOAD_FUNCPTR(FT_Init_FreeType)
3115 LOAD_FUNCPTR(FT_Library_Version)
3116 LOAD_FUNCPTR(FT_Load_Glyph)
3117 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3118 LOAD_FUNCPTR(FT_Matrix_Multiply)
3119 #ifndef FT_MULFIX_INLINED
3120 LOAD_FUNCPTR(FT_MulFix)
3121 #endif
3122 LOAD_FUNCPTR(FT_New_Face)
3123 LOAD_FUNCPTR(FT_New_Memory_Face)
3124 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3125 LOAD_FUNCPTR(FT_Outline_Transform)
3126 LOAD_FUNCPTR(FT_Outline_Translate)
3127 LOAD_FUNCPTR(FT_Render_Glyph)
3128 LOAD_FUNCPTR(FT_Select_Charmap)
3129 LOAD_FUNCPTR(FT_Set_Charmap)
3130 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3131 LOAD_FUNCPTR(FT_Vector_Transform)
3132 LOAD_FUNCPTR(FT_Vector_Unit)
3133 #undef LOAD_FUNCPTR
3134 /* Don't warn if these ones are missing */
3135 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3136 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3137 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3138 #endif
3140 if(pFT_Init_FreeType(&library) != 0) {
3141 ERR("Can't init FreeType library\n");
3142 wine_dlclose(ft_handle, NULL, 0);
3143 ft_handle = NULL;
3144 return FALSE;
3146 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3148 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3149 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3150 ((FT_Version.minor << 8) & 0x00ff00) |
3151 ((FT_Version.patch ) & 0x0000ff);
3153 font_driver = &freetype_funcs;
3154 return TRUE;
3156 sym_not_found:
3157 WINE_MESSAGE(
3158 "Wine cannot find certain functions that it needs inside the FreeType\n"
3159 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3160 "FreeType to at least version 2.1.4.\n"
3161 "http://www.freetype.org\n");
3162 wine_dlclose(ft_handle, NULL, 0);
3163 ft_handle = NULL;
3164 return FALSE;
3167 static void init_font_list(void)
3169 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3170 static const WCHAR pathW[] = {'P','a','t','h',0};
3171 HKEY hkey;
3172 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3173 WCHAR windowsdir[MAX_PATH];
3174 char *unixname;
3175 const char *data_dir;
3177 delete_external_font_keys();
3179 /* load the system bitmap fonts */
3180 load_system_fonts();
3182 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3183 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3184 strcatW(windowsdir, fontsW);
3185 if((unixname = wine_get_unix_file_name(windowsdir)))
3187 ReadFontDir(unixname, FALSE);
3188 HeapFree(GetProcessHeap(), 0, unixname);
3191 /* load the system truetype fonts */
3192 data_dir = wine_get_data_dir();
3193 if (!data_dir) data_dir = wine_get_build_dir();
3194 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3196 strcpy(unixname, data_dir);
3197 strcat(unixname, "/fonts/");
3198 ReadFontDir(unixname, TRUE);
3199 HeapFree(GetProcessHeap(), 0, unixname);
3202 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3203 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3204 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3205 will skip these. */
3206 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3207 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3208 &hkey) == ERROR_SUCCESS)
3210 LPWSTR data, valueW;
3211 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3212 &valuelen, &datalen, NULL, NULL);
3214 valuelen++; /* returned value doesn't include room for '\0' */
3215 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3216 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3217 if (valueW && data)
3219 dlen = datalen * sizeof(WCHAR);
3220 vlen = valuelen;
3221 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3222 &dlen) == ERROR_SUCCESS)
3224 if(data[0] && (data[1] == ':'))
3226 if((unixname = wine_get_unix_file_name(data)))
3228 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3229 HeapFree(GetProcessHeap(), 0, unixname);
3232 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3234 WCHAR pathW[MAX_PATH];
3235 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3236 BOOL added = FALSE;
3238 sprintfW(pathW, fmtW, windowsdir, data);
3239 if((unixname = wine_get_unix_file_name(pathW)))
3241 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3242 HeapFree(GetProcessHeap(), 0, unixname);
3244 if (!added)
3245 load_font_from_data_dir(data);
3247 /* reset dlen and vlen */
3248 dlen = datalen;
3249 vlen = valuelen;
3252 HeapFree(GetProcessHeap(), 0, data);
3253 HeapFree(GetProcessHeap(), 0, valueW);
3254 RegCloseKey(hkey);
3257 #ifdef SONAME_LIBFONTCONFIG
3258 load_fontconfig_fonts();
3259 #elif defined(HAVE_CARBON_CARBON_H)
3260 load_mac_fonts();
3261 #endif
3263 /* then look in any directories that we've specified in the config file */
3264 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3265 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3267 DWORD len;
3268 LPWSTR valueW;
3269 LPSTR valueA, ptr;
3271 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3273 len += sizeof(WCHAR);
3274 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3275 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3277 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3278 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3279 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3280 TRACE( "got font path %s\n", debugstr_a(valueA) );
3281 ptr = valueA;
3282 while (ptr)
3284 const char* home;
3285 LPSTR next = strchr( ptr, ':' );
3286 if (next) *next++ = 0;
3287 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3288 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3290 strcpy( unixname, home );
3291 strcat( unixname, ptr + 1 );
3292 ReadFontDir( unixname, TRUE );
3293 HeapFree( GetProcessHeap(), 0, unixname );
3295 else
3296 ReadFontDir( ptr, TRUE );
3297 ptr = next;
3299 HeapFree( GetProcessHeap(), 0, valueA );
3301 HeapFree( GetProcessHeap(), 0, valueW );
3303 RegCloseKey(hkey);
3307 static BOOL move_to_front(const WCHAR *name)
3309 Family *family, *cursor2;
3310 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3312 if(!strcmpiW(family->FamilyName, name))
3314 list_remove(&family->entry);
3315 list_add_head(&font_list, &family->entry);
3316 return TRUE;
3319 return FALSE;
3322 static BOOL set_default(const WCHAR **name_list)
3324 while (*name_list)
3326 if (move_to_front(*name_list)) return TRUE;
3327 name_list++;
3330 return FALSE;
3333 static void reorder_font_list(void)
3335 set_default( default_serif_list );
3336 set_default( default_fixed_list );
3337 set_default( default_sans_list );
3340 /*************************************************************
3341 * WineEngInit
3343 * Initialize FreeType library and create a list of available faces
3345 BOOL WineEngInit(void)
3347 HKEY hkey_font_cache;
3348 DWORD disposition;
3349 HANDLE font_mutex;
3351 /* update locale dependent font info in registry */
3352 update_font_info();
3354 if(!init_freetype()) return FALSE;
3356 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3358 ERR("Failed to create font mutex\n");
3359 return FALSE;
3361 WaitForSingleObject(font_mutex, INFINITE);
3363 create_font_cache_key(&hkey_font_cache, &disposition);
3365 if(disposition == REG_CREATED_NEW_KEY)
3366 init_font_list();
3367 else
3368 load_font_list_from_cache(hkey_font_cache);
3370 RegCloseKey(hkey_font_cache);
3372 reorder_font_list();
3374 DumpFontList();
3375 LoadSubstList();
3376 DumpSubstList();
3377 LoadReplaceList();
3379 if(disposition == REG_CREATED_NEW_KEY)
3380 update_reg_entries();
3382 init_system_links();
3384 ReleaseMutex(font_mutex);
3385 return TRUE;
3389 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3391 TT_OS2 *pOS2;
3392 TT_HoriHeader *pHori;
3394 LONG ppem;
3396 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3397 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3399 if(height == 0) height = 16;
3401 /* Calc. height of EM square:
3403 * For +ve lfHeight we have
3404 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3405 * Re-arranging gives:
3406 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3408 * For -ve lfHeight we have
3409 * |lfHeight| = ppem
3410 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3411 * with il = winAscent + winDescent - units_per_em]
3415 if(height > 0) {
3416 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3417 ppem = MulDiv(ft_face->units_per_EM, height,
3418 pHori->Ascender - pHori->Descender);
3419 else
3420 ppem = MulDiv(ft_face->units_per_EM, height,
3421 pOS2->usWinAscent + pOS2->usWinDescent);
3423 else
3424 ppem = -height;
3426 return ppem;
3429 static struct font_mapping *map_font_file( const char *name )
3431 struct font_mapping *mapping;
3432 struct stat st;
3433 int fd;
3435 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3436 if (fstat( fd, &st ) == -1) goto error;
3438 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3440 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3442 mapping->refcount++;
3443 close( fd );
3444 return mapping;
3447 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3448 goto error;
3450 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3451 close( fd );
3453 if (mapping->data == MAP_FAILED)
3455 HeapFree( GetProcessHeap(), 0, mapping );
3456 return NULL;
3458 mapping->refcount = 1;
3459 mapping->dev = st.st_dev;
3460 mapping->ino = st.st_ino;
3461 mapping->size = st.st_size;
3462 list_add_tail( &mappings_list, &mapping->entry );
3463 return mapping;
3465 error:
3466 close( fd );
3467 return NULL;
3470 static void unmap_font_file( struct font_mapping *mapping )
3472 if (!--mapping->refcount)
3474 list_remove( &mapping->entry );
3475 munmap( mapping->data, mapping->size );
3476 HeapFree( GetProcessHeap(), 0, mapping );
3480 static LONG load_VDMX(GdiFont*, LONG);
3482 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3484 FT_Error err;
3485 FT_Face ft_face;
3486 void *data_ptr;
3487 DWORD data_size;
3489 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3491 if (face->file)
3493 if (!(font->mapping = map_font_file( face->file )))
3495 WARN("failed to map %s\n", debugstr_a(face->file));
3496 return 0;
3498 data_ptr = font->mapping->data;
3499 data_size = font->mapping->size;
3501 else
3503 data_ptr = face->font_data_ptr;
3504 data_size = face->font_data_size;
3507 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3508 if(err) {
3509 ERR("FT_New_Face rets %d\n", err);
3510 return 0;
3513 /* set it here, as load_VDMX needs it */
3514 font->ft_face = ft_face;
3516 if(FT_IS_SCALABLE(ft_face)) {
3517 /* load the VDMX table if we have one */
3518 font->ppem = load_VDMX(font, height);
3519 if(font->ppem == 0)
3520 font->ppem = calc_ppem_for_height(ft_face, height);
3521 TRACE("height %d => ppem %d\n", height, font->ppem);
3523 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3524 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3525 } else {
3526 font->ppem = height;
3527 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3528 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3530 return ft_face;
3534 static int get_nearest_charset(Face *face, int *cp)
3536 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3537 a single face with the requested charset. The idea is to check if
3538 the selected font supports the current ANSI codepage, if it does
3539 return the corresponding charset, else return the first charset */
3541 CHARSETINFO csi;
3542 int acp = GetACP(), i;
3543 DWORD fs0;
3545 *cp = acp;
3546 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3547 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3548 return csi.ciCharset;
3550 for(i = 0; i < 32; i++) {
3551 fs0 = 1L << i;
3552 if(face->fs.fsCsb[0] & fs0) {
3553 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3554 *cp = csi.ciACP;
3555 return csi.ciCharset;
3557 else
3558 FIXME("TCI failing on %x\n", fs0);
3562 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3563 face->fs.fsCsb[0], face->file);
3564 *cp = acp;
3565 return DEFAULT_CHARSET;
3568 static GdiFont *alloc_font(void)
3570 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3571 ret->gmsize = 1;
3572 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3573 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3574 ret->potm = NULL;
3575 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3576 ret->total_kern_pairs = (DWORD)-1;
3577 ret->kern_pairs = NULL;
3578 list_init(&ret->hfontlist);
3579 list_init(&ret->child_fonts);
3580 return ret;
3583 static void free_font(GdiFont *font)
3585 struct list *cursor, *cursor2;
3586 DWORD i;
3588 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3590 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3591 list_remove(cursor);
3592 if(child->font)
3593 free_font(child->font);
3594 HeapFree(GetProcessHeap(), 0, child);
3597 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3599 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3600 DeleteObject(hfontlist->hfont);
3601 list_remove(&hfontlist->entry);
3602 HeapFree(GetProcessHeap(), 0, hfontlist);
3605 if (font->ft_face) pFT_Done_Face(font->ft_face);
3606 if (font->mapping) unmap_font_file( font->mapping );
3607 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3608 HeapFree(GetProcessHeap(), 0, font->potm);
3609 HeapFree(GetProcessHeap(), 0, font->name);
3610 for (i = 0; i < font->gmsize; i++)
3611 HeapFree(GetProcessHeap(),0,font->gm[i]);
3612 HeapFree(GetProcessHeap(), 0, font->gm);
3613 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3614 HeapFree(GetProcessHeap(), 0, font);
3618 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3620 FT_Face ft_face = font->ft_face;
3621 FT_ULong len;
3622 FT_Error err;
3624 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3626 if(!buf)
3627 len = 0;
3628 else
3629 len = cbData;
3631 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3633 /* make sure value of len is the value freetype says it needs */
3634 if (buf && len)
3636 FT_ULong needed = 0;
3637 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3638 if( !err && needed < len) len = needed;
3640 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3641 if (err)
3643 TRACE("Can't find table %c%c%c%c\n",
3644 /* bytes were reversed */
3645 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3646 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3647 return GDI_ERROR;
3649 return len;
3652 /*************************************************************
3653 * load_VDMX
3655 * load the vdmx entry for the specified height
3658 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3659 ( ( (FT_ULong)_x4 << 24 ) | \
3660 ( (FT_ULong)_x3 << 16 ) | \
3661 ( (FT_ULong)_x2 << 8 ) | \
3662 (FT_ULong)_x1 )
3664 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3666 typedef struct {
3667 BYTE bCharSet;
3668 BYTE xRatio;
3669 BYTE yStartRatio;
3670 BYTE yEndRatio;
3671 } Ratios;
3673 typedef struct {
3674 WORD recs;
3675 BYTE startsz;
3676 BYTE endsz;
3677 } VDMX_group;
3679 static LONG load_VDMX(GdiFont *font, LONG height)
3681 WORD hdr[3], tmp;
3682 VDMX_group group;
3683 BYTE devXRatio, devYRatio;
3684 USHORT numRecs, numRatios;
3685 DWORD result, offset = -1;
3686 LONG ppem = 0;
3687 int i;
3689 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3691 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3692 return ppem;
3694 /* FIXME: need the real device aspect ratio */
3695 devXRatio = 1;
3696 devYRatio = 1;
3698 numRecs = GET_BE_WORD(hdr[1]);
3699 numRatios = GET_BE_WORD(hdr[2]);
3701 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3702 for(i = 0; i < numRatios; i++) {
3703 Ratios ratio;
3705 offset = (3 * 2) + (i * sizeof(Ratios));
3706 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3707 offset = -1;
3709 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3711 if((ratio.xRatio == 0 &&
3712 ratio.yStartRatio == 0 &&
3713 ratio.yEndRatio == 0) ||
3714 (devXRatio == ratio.xRatio &&
3715 devYRatio >= ratio.yStartRatio &&
3716 devYRatio <= ratio.yEndRatio))
3718 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3719 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3720 offset = GET_BE_WORD(tmp);
3721 break;
3725 if(offset == -1) {
3726 FIXME("No suitable ratio found\n");
3727 return ppem;
3730 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3731 USHORT recs;
3732 BYTE startsz, endsz;
3733 WORD *vTable;
3735 recs = GET_BE_WORD(group.recs);
3736 startsz = group.startsz;
3737 endsz = group.endsz;
3739 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3741 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3742 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3743 if(result == GDI_ERROR) {
3744 FIXME("Failed to retrieve vTable\n");
3745 goto end;
3748 if(height > 0) {
3749 for(i = 0; i < recs; i++) {
3750 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3751 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3752 ppem = GET_BE_WORD(vTable[i * 3]);
3754 if(yMax + -yMin == height) {
3755 font->yMax = yMax;
3756 font->yMin = yMin;
3757 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3758 break;
3760 if(yMax + -yMin > height) {
3761 if(--i < 0) {
3762 ppem = 0;
3763 goto end; /* failed */
3765 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3766 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3767 ppem = GET_BE_WORD(vTable[i * 3]);
3768 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3769 break;
3772 if(!font->yMax) {
3773 ppem = 0;
3774 TRACE("ppem not found for height %d\n", height);
3777 end:
3778 HeapFree(GetProcessHeap(), 0, vTable);
3781 return ppem;
3784 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3786 if(font->font_desc.hash != fd->hash) return TRUE;
3787 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3788 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3789 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3790 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3793 static void calc_hash(FONT_DESC *pfd)
3795 DWORD hash = 0, *ptr, two_chars;
3796 WORD *pwc;
3797 unsigned int i;
3799 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3800 hash ^= *ptr;
3801 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3802 hash ^= *ptr;
3803 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3804 two_chars = *ptr;
3805 pwc = (WCHAR *)&two_chars;
3806 if(!*pwc) break;
3807 *pwc = toupperW(*pwc);
3808 pwc++;
3809 *pwc = toupperW(*pwc);
3810 hash ^= two_chars;
3811 if(!*pwc) break;
3813 hash ^= !pfd->can_use_bitmap;
3814 pfd->hash = hash;
3815 return;
3818 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3820 GdiFont *ret;
3821 FONT_DESC fd;
3822 HFONTLIST *hflist;
3823 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3825 fd.lf = *plf;
3826 fd.matrix = *pmat;
3827 fd.can_use_bitmap = can_use_bitmap;
3828 calc_hash(&fd);
3830 /* try the child list */
3831 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3832 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3833 if(!fontcmp(ret, &fd)) {
3834 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3835 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3836 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3837 if(hflist->hfont == hfont)
3838 return ret;
3843 /* try the in-use list */
3844 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3845 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3846 if(!fontcmp(ret, &fd)) {
3847 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3848 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3849 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3850 if(hflist->hfont == hfont)
3851 return ret;
3853 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3854 hflist->hfont = hfont;
3855 list_add_head(&ret->hfontlist, &hflist->entry);
3856 return ret;
3860 /* then the unused list */
3861 font_elem_ptr = list_head(&unused_gdi_font_list);
3862 while(font_elem_ptr) {
3863 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3864 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3865 if(!fontcmp(ret, &fd)) {
3866 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3867 assert(list_empty(&ret->hfontlist));
3868 TRACE("Found %p in unused list\n", ret);
3869 list_remove(&ret->entry);
3870 list_add_head(&gdi_font_list, &ret->entry);
3871 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3872 hflist->hfont = hfont;
3873 list_add_head(&ret->hfontlist, &hflist->entry);
3874 return ret;
3877 return NULL;
3880 static void add_to_cache(GdiFont *font)
3882 static DWORD cache_num = 1;
3884 font->cache_num = cache_num++;
3885 list_add_head(&gdi_font_list, &font->entry);
3888 /*************************************************************
3889 * create_child_font_list
3891 static BOOL create_child_font_list(GdiFont *font)
3893 BOOL ret = FALSE;
3894 SYSTEM_LINKS *font_link;
3895 CHILD_FONT *font_link_entry, *new_child;
3896 FontSubst *psub;
3897 WCHAR* font_name;
3899 psub = get_font_subst(&font_subst_list, font->name, -1);
3900 font_name = psub ? psub->to.name : font->name;
3901 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3903 if(!strcmpiW(font_link->font_name, font_name))
3905 TRACE("found entry in system list\n");
3906 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3908 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3909 new_child->face = font_link_entry->face;
3910 new_child->font = NULL;
3911 list_add_tail(&font->child_fonts, &new_child->entry);
3912 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3914 ret = TRUE;
3915 break;
3919 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3920 * Sans Serif. This is how asian windows get default fallbacks for fonts
3922 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3923 font->charset != OEM_CHARSET &&
3924 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3925 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3927 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3929 TRACE("found entry in default fallback list\n");
3930 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3932 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3933 new_child->face = font_link_entry->face;
3934 new_child->font = NULL;
3935 list_add_tail(&font->child_fonts, &new_child->entry);
3936 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3938 ret = TRUE;
3939 break;
3943 return ret;
3946 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3948 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3950 if (pFT_Set_Charmap)
3952 FT_Int i;
3953 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3955 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3957 for (i = 0; i < ft_face->num_charmaps; i++)
3959 if (ft_face->charmaps[i]->encoding == encoding)
3961 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3962 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3964 switch (ft_face->charmaps[i]->platform_id)
3966 default:
3967 cmap_def = ft_face->charmaps[i];
3968 break;
3969 case 0: /* Apple Unicode */
3970 cmap0 = ft_face->charmaps[i];
3971 break;
3972 case 1: /* Macintosh */
3973 cmap1 = ft_face->charmaps[i];
3974 break;
3975 case 2: /* ISO */
3976 cmap2 = ft_face->charmaps[i];
3977 break;
3978 case 3: /* Microsoft */
3979 cmap3 = ft_face->charmaps[i];
3980 break;
3984 if (cmap3) /* prefer Microsoft cmap table */
3985 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3986 else if (cmap1)
3987 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3988 else if (cmap2)
3989 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3990 else if (cmap0)
3991 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3992 else if (cmap_def)
3993 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3995 return ft_err == FT_Err_Ok;
3998 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4002 /*************************************************************
4003 * freetype_CreateDC
4005 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4006 LPCWSTR output, const DEVMODEW *devmode )
4008 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4010 if (!physdev) return FALSE;
4011 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4012 return TRUE;
4016 /*************************************************************
4017 * freetype_DeleteDC
4019 static BOOL freetype_DeleteDC( PHYSDEV dev )
4021 struct freetype_physdev *physdev = get_freetype_dev( dev );
4022 HeapFree( GetProcessHeap(), 0, physdev );
4023 return TRUE;
4027 /*************************************************************
4028 * freetype_SelectFont
4030 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
4032 struct freetype_physdev *physdev = get_freetype_dev( dev );
4033 GdiFont *ret;
4034 Face *face, *best, *best_bitmap;
4035 Family *family, *last_resort_family;
4036 struct list *family_elem_ptr, *face_elem_ptr;
4037 INT height, width = 0;
4038 unsigned int score = 0, new_score;
4039 signed int diff = 0, newdiff;
4040 BOOL bd, it, can_use_bitmap, want_vertical;
4041 LOGFONTW lf;
4042 CHARSETINFO csi;
4043 HFONTLIST *hflist;
4044 FMAT2 dcmat;
4045 FontSubst *psub = NULL;
4046 DC *dc = get_dc_ptr( dev->hdc );
4048 if (!hfont) /* notification that the font has been changed by another driver */
4050 dc->gdiFont = NULL;
4051 physdev->font = NULL;
4052 release_dc_ptr( dc );
4053 return 0;
4056 GetObjectW( hfont, sizeof(lf), &lf );
4057 lf.lfWidth = abs(lf.lfWidth);
4059 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4061 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4062 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4063 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4064 lf.lfEscapement);
4066 if(dc->GraphicsMode == GM_ADVANCED)
4068 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4069 /* Try to avoid not necessary glyph transformations */
4070 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4072 lf.lfHeight *= fabs(dcmat.eM11);
4073 lf.lfWidth *= fabs(dcmat.eM11);
4074 dcmat.eM11 = dcmat.eM22 = 1.0;
4077 else
4079 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4080 font scaling abilities. */
4081 dcmat.eM11 = dcmat.eM22 = 1.0;
4082 dcmat.eM21 = dcmat.eM12 = 0;
4083 if (dc->vport2WorldValid)
4085 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4086 lf.lfOrientation = -lf.lfOrientation;
4087 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4088 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4092 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4093 dcmat.eM21, dcmat.eM22);
4095 GDI_CheckNotLock();
4096 EnterCriticalSection( &freetype_cs );
4098 /* check the cache first */
4099 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4100 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4101 goto done;
4104 if(list_empty(&font_list)) /* No fonts installed */
4106 TRACE("No fonts installed\n");
4107 goto done;
4110 TRACE("not in cache\n");
4111 ret = alloc_font();
4113 ret->font_desc.matrix = dcmat;
4114 ret->font_desc.lf = lf;
4115 ret->font_desc.can_use_bitmap = can_use_bitmap;
4116 calc_hash(&ret->font_desc);
4117 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4118 hflist->hfont = hfont;
4119 list_add_head(&ret->hfontlist, &hflist->entry);
4121 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4122 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4123 original value lfCharSet. Note this is a special case for
4124 Symbol and doesn't happen at least for "Wingdings*" */
4126 if(!strcmpiW(lf.lfFaceName, SymbolW))
4127 lf.lfCharSet = SYMBOL_CHARSET;
4129 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4130 switch(lf.lfCharSet) {
4131 case DEFAULT_CHARSET:
4132 csi.fs.fsCsb[0] = 0;
4133 break;
4134 default:
4135 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4136 csi.fs.fsCsb[0] = 0;
4137 break;
4141 family = NULL;
4142 if(lf.lfFaceName[0] != '\0') {
4143 SYSTEM_LINKS *font_link;
4144 CHILD_FONT *font_link_entry;
4145 LPWSTR FaceName = lf.lfFaceName;
4147 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4149 if(psub) {
4150 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4151 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4152 if (psub->to.charset != -1)
4153 lf.lfCharSet = psub->to.charset;
4156 /* We want a match on name and charset or just name if
4157 charset was DEFAULT_CHARSET. If the latter then
4158 we fixup the returned charset later in get_nearest_charset
4159 where we'll either use the charset of the current ansi codepage
4160 or if that's unavailable the first charset that the font supports.
4162 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4163 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4164 if (!strcmpiW(family->FamilyName, FaceName) ||
4165 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4167 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4168 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4169 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4170 if(face->scalable || can_use_bitmap)
4171 goto found;
4176 /* Search by full face name. */
4177 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4178 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4179 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4180 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4181 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4182 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
4184 if(face->scalable || can_use_bitmap)
4185 goto found_face;
4191 * Try check the SystemLink list first for a replacement font.
4192 * We may find good replacements there.
4194 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4196 if(!strcmpiW(font_link->font_name, FaceName) ||
4197 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4199 TRACE("found entry in system list\n");
4200 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4202 face = font_link_entry->face;
4203 family = face->family;
4204 if(csi.fs.fsCsb[0] &
4205 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4207 if(face->scalable || can_use_bitmap)
4208 goto found;
4215 psub = NULL; /* substitution is no more relevant */
4217 /* If requested charset was DEFAULT_CHARSET then try using charset
4218 corresponding to the current ansi codepage */
4219 if (!csi.fs.fsCsb[0])
4221 INT acp = GetACP();
4222 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4223 FIXME("TCI failed on codepage %d\n", acp);
4224 csi.fs.fsCsb[0] = 0;
4225 } else
4226 lf.lfCharSet = csi.ciCharset;
4229 want_vertical = (lf.lfFaceName[0] == '@');
4231 /* Face families are in the top 4 bits of lfPitchAndFamily,
4232 so mask with 0xF0 before testing */
4234 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4235 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4236 strcpyW(lf.lfFaceName, defFixed);
4237 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4238 strcpyW(lf.lfFaceName, defSerif);
4239 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4240 strcpyW(lf.lfFaceName, defSans);
4241 else
4242 strcpyW(lf.lfFaceName, defSans);
4243 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4244 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4245 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4246 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4247 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4248 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4249 if(face->scalable || can_use_bitmap)
4250 goto found;
4255 last_resort_family = NULL;
4256 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4257 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4258 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4259 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4260 if(face->vertical == want_vertical &&
4261 (csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))) {
4262 if(face->scalable)
4263 goto found;
4264 if(can_use_bitmap && !last_resort_family)
4265 last_resort_family = family;
4270 if(last_resort_family) {
4271 family = last_resort_family;
4272 csi.fs.fsCsb[0] = 0;
4273 goto found;
4276 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4277 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4278 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4279 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4280 if(face->scalable && face->vertical == want_vertical) {
4281 csi.fs.fsCsb[0] = 0;
4282 WARN("just using first face for now\n");
4283 goto found;
4285 if(can_use_bitmap && !last_resort_family)
4286 last_resort_family = family;
4289 if(!last_resort_family) {
4290 FIXME("can't find a single appropriate font - bailing\n");
4291 free_font(ret);
4292 ret = NULL;
4293 goto done;
4296 WARN("could only find a bitmap font - this will probably look awful!\n");
4297 family = last_resort_family;
4298 csi.fs.fsCsb[0] = 0;
4300 found:
4301 it = lf.lfItalic ? 1 : 0;
4302 bd = lf.lfWeight > 550 ? 1 : 0;
4304 height = lf.lfHeight;
4306 face = best = best_bitmap = NULL;
4307 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4309 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4311 BOOL italic, bold;
4313 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4314 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4315 new_score = (italic ^ it) + (bold ^ bd);
4316 if(!best || new_score <= score)
4318 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4319 italic, bold, it, bd);
4320 score = new_score;
4321 best = face;
4322 if(best->scalable && score == 0) break;
4323 if(!best->scalable)
4325 if(height > 0)
4326 newdiff = height - (signed int)(best->size.height);
4327 else
4328 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4329 if(!best_bitmap || new_score < score ||
4330 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4332 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4333 diff = newdiff;
4334 best_bitmap = best;
4335 if(score == 0 && diff == 0) break;
4341 if(best)
4342 face = best->scalable ? best : best_bitmap;
4343 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4344 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4346 found_face:
4347 height = lf.lfHeight;
4349 ret->fs = face->fs;
4351 if(csi.fs.fsCsb[0]) {
4352 ret->charset = lf.lfCharSet;
4353 ret->codepage = csi.ciACP;
4355 else
4356 ret->charset = get_nearest_charset(face, &ret->codepage);
4358 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4359 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4361 ret->aveWidth = height ? lf.lfWidth : 0;
4363 if(!face->scalable) {
4364 /* Windows uses integer scaling factors for bitmap fonts */
4365 INT scale, scaled_height;
4366 GdiFont *cachedfont;
4368 /* FIXME: rotation of bitmap fonts is ignored */
4369 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4370 if (ret->aveWidth)
4371 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4372 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4373 dcmat.eM11 = dcmat.eM22 = 1.0;
4374 /* As we changed the matrix, we need to search the cache for the font again,
4375 * otherwise we might explode the cache. */
4376 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4377 TRACE("Found cached font after non-scalable matrix rescale!\n");
4378 free_font( ret );
4379 ret = cachedfont;
4380 goto done;
4382 calc_hash(&ret->font_desc);
4384 if (height != 0) height = diff;
4385 height += face->size.height;
4387 scale = (height + face->size.height - 1) / face->size.height;
4388 scaled_height = scale * face->size.height;
4389 /* Only jump to the next height if the difference <= 25% original height */
4390 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4391 /* The jump between unscaled and doubled is delayed by 1 */
4392 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4393 ret->scale_y = scale;
4395 width = face->size.x_ppem >> 6;
4396 height = face->size.y_ppem >> 6;
4398 else
4399 ret->scale_y = 1.0;
4400 TRACE("font scale y: %f\n", ret->scale_y);
4402 ret->ft_face = OpenFontFace(ret, face, width, height);
4404 if (!ret->ft_face)
4406 free_font( ret );
4407 ret = NULL;
4408 goto done;
4411 ret->ntmFlags = face->ntmFlags;
4413 if (ret->charset == SYMBOL_CHARSET &&
4414 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4415 /* No ops */
4417 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4418 /* No ops */
4420 else {
4421 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4424 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4425 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4426 ret->underline = lf.lfUnderline ? 0xff : 0;
4427 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4428 create_child_font_list(ret);
4430 if (face->vertical) /* We need to try to load the GSUB table */
4432 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4433 if (length != GDI_ERROR)
4435 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4436 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4437 TRACE("Loaded GSUB table of %i bytes\n",length);
4441 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4443 add_to_cache(ret);
4444 done:
4445 if (ret)
4447 dc->gdiFont = ret;
4448 physdev->font = ret;
4450 LeaveCriticalSection( &freetype_cs );
4451 release_dc_ptr( dc );
4452 return ret ? hfont : 0;
4455 static void dump_gdi_font_list(void)
4457 GdiFont *gdiFont;
4458 struct list *elem_ptr;
4460 TRACE("---------- gdiFont Cache ----------\n");
4461 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4462 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4463 TRACE("gdiFont=%p %s %d\n",
4464 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4467 TRACE("---------- Unused gdiFont Cache ----------\n");
4468 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4469 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4470 TRACE("gdiFont=%p %s %d\n",
4471 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4474 TRACE("---------- Child gdiFont Cache ----------\n");
4475 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4476 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4477 TRACE("gdiFont=%p %s %d\n",
4478 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4482 /*************************************************************
4483 * WineEngDestroyFontInstance
4485 * free the gdiFont associated with this handle
4488 BOOL WineEngDestroyFontInstance(HFONT handle)
4490 GdiFont *gdiFont;
4491 HFONTLIST *hflist;
4492 BOOL ret = FALSE;
4493 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4494 int i = 0;
4496 GDI_CheckNotLock();
4497 EnterCriticalSection( &freetype_cs );
4499 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4501 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4502 while(hfontlist_elem_ptr) {
4503 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4504 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4505 if(hflist->hfont == handle) {
4506 TRACE("removing child font %p from child list\n", gdiFont);
4507 list_remove(&gdiFont->entry);
4508 LeaveCriticalSection( &freetype_cs );
4509 return TRUE;
4514 TRACE("destroying hfont=%p\n", handle);
4515 if(TRACE_ON(font))
4516 dump_gdi_font_list();
4518 font_elem_ptr = list_head(&gdi_font_list);
4519 while(font_elem_ptr) {
4520 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4521 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4523 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4524 while(hfontlist_elem_ptr) {
4525 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4526 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4527 if(hflist->hfont == handle) {
4528 list_remove(&hflist->entry);
4529 HeapFree(GetProcessHeap(), 0, hflist);
4530 ret = TRUE;
4533 if(list_empty(&gdiFont->hfontlist)) {
4534 TRACE("Moving to Unused list\n");
4535 list_remove(&gdiFont->entry);
4536 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4541 font_elem_ptr = list_head(&unused_gdi_font_list);
4542 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4543 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4544 while(font_elem_ptr) {
4545 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4546 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4547 TRACE("freeing %p\n", gdiFont);
4548 list_remove(&gdiFont->entry);
4549 free_font(gdiFont);
4551 LeaveCriticalSection( &freetype_cs );
4552 return ret;
4555 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4557 HRSRC rsrc;
4558 HGLOBAL hMem;
4559 WCHAR *p;
4560 int i;
4562 id += IDS_FIRST_SCRIPT;
4563 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4564 if (!rsrc) return 0;
4565 hMem = LoadResource( gdi32_module, rsrc );
4566 if (!hMem) return 0;
4568 p = LockResource( hMem );
4569 id &= 0x000f;
4570 while (id--) p += *p + 1;
4572 i = min(LF_FACESIZE - 1, *p);
4573 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4574 buffer[i] = 0;
4575 return i;
4579 /***************************************************
4580 * create_enum_charset_list
4582 * This function creates charset enumeration list because in DEFAULT_CHARSET
4583 * case, the ANSI codepage's charset takes precedence over other charsets.
4584 * This function works as a filter other than DEFAULT_CHARSET case.
4586 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4588 CHARSETINFO csi;
4589 DWORD n = 0;
4591 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4592 csi.fs.fsCsb[0] != 0) {
4593 list->element[n].mask = csi.fs.fsCsb[0];
4594 list->element[n].charset = csi.ciCharset;
4595 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4596 n++;
4598 else { /* charset is DEFAULT_CHARSET or invalid. */
4599 INT acp, i;
4601 /* Set the current codepage's charset as the first element. */
4602 acp = GetACP();
4603 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4604 csi.fs.fsCsb[0] != 0) {
4605 list->element[n].mask = csi.fs.fsCsb[0];
4606 list->element[n].charset = csi.ciCharset;
4607 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4608 n++;
4611 /* Fill out left elements. */
4612 for (i = 0; i < 32; i++) {
4613 FONTSIGNATURE fs;
4614 fs.fsCsb[0] = 1L << i;
4615 fs.fsCsb[1] = 0;
4616 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4617 continue; /* skip, already added. */
4618 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4619 continue; /* skip, this is an invalid fsCsb bit. */
4621 list->element[n].mask = fs.fsCsb[0];
4622 list->element[n].charset = csi.ciCharset;
4623 load_script_name( i, list->element[n].name );
4624 n++;
4627 list->total = n;
4629 return n;
4632 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4633 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4635 GdiFont *font;
4636 LONG width, height;
4638 if (face->cached_enum_data)
4640 TRACE("Cached\n");
4641 *pelf = face->cached_enum_data->elf;
4642 *pntm = face->cached_enum_data->ntm;
4643 *ptype = face->cached_enum_data->type;
4644 return;
4647 font = alloc_font();
4649 if(face->scalable) {
4650 height = -2048; /* 2048 is the most common em size */
4651 width = 0;
4652 } else {
4653 height = face->size.y_ppem >> 6;
4654 width = face->size.x_ppem >> 6;
4656 font->scale_y = 1.0;
4658 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4660 free_font(font);
4661 return;
4664 font->name = strdupW(face->family->FamilyName);
4665 font->ntmFlags = face->ntmFlags;
4667 if (get_outline_text_metrics(font))
4669 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4671 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4673 lstrcpynW(pelf->elfLogFont.lfFaceName,
4674 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4675 LF_FACESIZE);
4676 lstrcpynW(pelf->elfFullName,
4677 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4678 LF_FULLFACESIZE);
4679 lstrcpynW(pelf->elfStyle,
4680 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4681 LF_FACESIZE);
4683 else
4685 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4687 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4689 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4690 if (face->FullName)
4691 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4692 else
4693 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4694 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4697 pntm->ntmTm.ntmFlags = face->ntmFlags;
4698 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4699 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4700 pntm->ntmFontSig = face->fs;
4702 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4704 pelf->elfLogFont.lfEscapement = 0;
4705 pelf->elfLogFont.lfOrientation = 0;
4706 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4707 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4708 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4709 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4710 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4711 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4712 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4713 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4714 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4715 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4716 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4718 *ptype = 0;
4719 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4720 *ptype |= TRUETYPE_FONTTYPE;
4721 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4722 *ptype |= DEVICE_FONTTYPE;
4723 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4724 *ptype |= RASTER_FONTTYPE;
4726 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4727 if (face->cached_enum_data)
4729 face->cached_enum_data->elf = *pelf;
4730 face->cached_enum_data->ntm = *pntm;
4731 face->cached_enum_data->type = *ptype;
4734 free_font(font);
4737 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4739 struct list *face_elem_ptr;
4741 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4743 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4745 static const WCHAR spaceW[] = { ' ',0 };
4746 WCHAR full_family_name[LF_FULLFACESIZE];
4747 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4749 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4751 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4752 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4753 continue;
4756 strcpyW(full_family_name, family->FamilyName);
4757 strcatW(full_family_name, spaceW);
4758 strcatW(full_family_name, face->StyleName);
4759 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4762 return FALSE;
4765 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4767 static const WCHAR spaceW[] = { ' ',0 };
4768 WCHAR full_family_name[LF_FULLFACESIZE];
4770 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4772 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4774 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4775 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4776 return FALSE;
4779 strcpyW(full_family_name, face->family->FamilyName);
4780 strcatW(full_family_name, spaceW);
4781 strcatW(full_family_name, face->StyleName);
4782 return !strcmpiW(lf->lfFaceName, full_family_name);
4785 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4786 FONTENUMPROCW proc, LPARAM lparam)
4788 ENUMLOGFONTEXW elf;
4789 NEWTEXTMETRICEXW ntm;
4790 DWORD type = 0;
4791 int i;
4793 GetEnumStructs(face, &elf, &ntm, &type);
4794 for(i = 0; i < list->total; i++) {
4795 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4796 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4797 load_script_name( IDS_OEM_DOS, elf.elfScript );
4798 i = list->total; /* break out of loop after enumeration */
4799 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4800 continue;
4801 else {
4802 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4803 strcpyW(elf.elfScript, list->element[i].name);
4804 if (!elf.elfScript[0])
4805 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4807 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4808 debugstr_w(elf.elfLogFont.lfFaceName),
4809 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4810 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4811 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4812 ntm.ntmTm.ntmFlags);
4813 /* release section before callback (FIXME) */
4814 LeaveCriticalSection( &freetype_cs );
4815 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4816 EnterCriticalSection( &freetype_cs );
4818 return TRUE;
4821 /*************************************************************
4822 * freetype_EnumFonts
4824 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4826 Family *family;
4827 Face *face;
4828 struct list *family_elem_ptr, *face_elem_ptr;
4829 LOGFONTW lf;
4830 struct enum_charset_list enum_charsets;
4832 if (!plf)
4834 lf.lfCharSet = DEFAULT_CHARSET;
4835 lf.lfPitchAndFamily = 0;
4836 lf.lfFaceName[0] = 0;
4837 plf = &lf;
4840 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4842 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4844 GDI_CheckNotLock();
4845 EnterCriticalSection( &freetype_cs );
4846 if(plf->lfFaceName[0]) {
4847 FontSubst *psub;
4848 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4850 if(psub) {
4851 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4852 debugstr_w(psub->to.name));
4853 lf = *plf;
4854 strcpyW(lf.lfFaceName, psub->to.name);
4855 plf = &lf;
4858 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4859 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4860 if(family_matches(family, plf)) {
4861 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4862 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4863 if (!face_matches(face, plf)) continue;
4864 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4868 } else {
4869 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4870 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4871 face_elem_ptr = list_head(&family->faces);
4872 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4873 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4876 LeaveCriticalSection( &freetype_cs );
4877 return TRUE;
4880 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4882 pt->x.value = vec->x >> 6;
4883 pt->x.fract = (vec->x & 0x3f) << 10;
4884 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4885 pt->y.value = vec->y >> 6;
4886 pt->y.fract = (vec->y & 0x3f) << 10;
4887 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4888 return;
4891 /***************************************************
4892 * According to the MSDN documentation on WideCharToMultiByte,
4893 * certain codepages cannot set the default_used parameter.
4894 * This returns TRUE if the codepage can set that parameter, false else
4895 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4897 static BOOL codepage_sets_default_used(UINT codepage)
4899 switch (codepage)
4901 case CP_UTF7:
4902 case CP_UTF8:
4903 case CP_SYMBOL:
4904 return FALSE;
4905 default:
4906 return TRUE;
4911 * GSUB Table handling functions
4914 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4916 const GSUB_CoverageFormat1* cf1;
4918 cf1 = table;
4920 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4922 int count = GET_BE_WORD(cf1->GlyphCount);
4923 int i;
4924 TRACE("Coverage Format 1, %i glyphs\n",count);
4925 for (i = 0; i < count; i++)
4926 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4927 return i;
4928 return -1;
4930 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4932 const GSUB_CoverageFormat2* cf2;
4933 int i;
4934 int count;
4935 cf2 = (const GSUB_CoverageFormat2*)cf1;
4937 count = GET_BE_WORD(cf2->RangeCount);
4938 TRACE("Coverage Format 2, %i ranges\n",count);
4939 for (i = 0; i < count; i++)
4941 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4942 return -1;
4943 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4944 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4946 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4947 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4950 return -1;
4952 else
4953 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4955 return -1;
4958 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4960 const GSUB_ScriptList *script;
4961 const GSUB_Script *deflt = NULL;
4962 int i;
4963 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4965 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4966 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4968 const GSUB_Script *scr;
4969 int offset;
4971 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4972 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4974 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4975 return scr;
4976 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4977 deflt = scr;
4979 return deflt;
4982 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4984 int i;
4985 int offset;
4986 const GSUB_LangSys *Lang;
4988 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4990 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4992 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4993 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4995 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4996 return Lang;
4998 offset = GET_BE_WORD(script->DefaultLangSys);
4999 if (offset)
5001 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5002 return Lang;
5004 return NULL;
5007 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5009 int i;
5010 const GSUB_FeatureList *feature;
5011 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5013 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5014 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5016 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5017 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5019 const GSUB_Feature *feat;
5020 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5021 return feat;
5024 return NULL;
5027 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5029 int i;
5030 int offset;
5031 const GSUB_LookupList *lookup;
5032 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5034 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5035 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5037 const GSUB_LookupTable *look;
5038 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5039 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5040 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5041 if (GET_BE_WORD(look->LookupType) != 1)
5042 FIXME("We only handle SubType 1\n");
5043 else
5045 int j;
5047 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5049 const GSUB_SingleSubstFormat1 *ssf1;
5050 offset = GET_BE_WORD(look->SubTable[j]);
5051 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5052 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5054 int offset = GET_BE_WORD(ssf1->Coverage);
5055 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5056 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5058 TRACE(" Glyph 0x%x ->",glyph);
5059 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5060 TRACE(" 0x%x\n",glyph);
5063 else
5065 const GSUB_SingleSubstFormat2 *ssf2;
5066 INT index;
5067 INT offset;
5069 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5070 offset = GET_BE_WORD(ssf1->Coverage);
5071 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5072 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5073 TRACE(" Coverage index %i\n",index);
5074 if (index != -1)
5076 TRACE(" Glyph is 0x%x ->",glyph);
5077 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5078 TRACE("0x%x\n",glyph);
5084 return glyph;
5087 static const char* get_opentype_script(const GdiFont *font)
5090 * I am not sure if this is the correct way to generate our script tag
5093 switch (font->charset)
5095 case ANSI_CHARSET: return "latn";
5096 case BALTIC_CHARSET: return "latn"; /* ?? */
5097 case CHINESEBIG5_CHARSET: return "hani";
5098 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5099 case GB2312_CHARSET: return "hani";
5100 case GREEK_CHARSET: return "grek";
5101 case HANGUL_CHARSET: return "hang";
5102 case RUSSIAN_CHARSET: return "cyrl";
5103 case SHIFTJIS_CHARSET: return "kana";
5104 case TURKISH_CHARSET: return "latn"; /* ?? */
5105 case VIETNAMESE_CHARSET: return "latn";
5106 case JOHAB_CHARSET: return "latn"; /* ?? */
5107 case ARABIC_CHARSET: return "arab";
5108 case HEBREW_CHARSET: return "hebr";
5109 case THAI_CHARSET: return "thai";
5110 default: return "latn";
5114 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5116 const GSUB_Header *header;
5117 const GSUB_Script *script;
5118 const GSUB_LangSys *language;
5119 const GSUB_Feature *feature;
5121 if (!font->GSUB_Table)
5122 return glyph;
5124 header = font->GSUB_Table;
5126 script = GSUB_get_script_table(header, get_opentype_script(font));
5127 if (!script)
5129 TRACE("Script not found\n");
5130 return glyph;
5132 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5133 if (!language)
5135 TRACE("Language not found\n");
5136 return glyph;
5138 feature = GSUB_get_feature(header, language, "vrt2");
5139 if (!feature)
5140 feature = GSUB_get_feature(header, language, "vert");
5141 if (!feature)
5143 TRACE("vrt2/vert feature not found\n");
5144 return glyph;
5146 return GSUB_apply_feature(header, feature, glyph);
5149 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5151 FT_UInt glyphId;
5153 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5154 WCHAR wc = (WCHAR)glyph;
5155 BOOL default_used;
5156 BOOL *default_used_pointer;
5157 FT_UInt ret;
5158 char buf;
5159 default_used_pointer = NULL;
5160 default_used = FALSE;
5161 if (codepage_sets_default_used(font->codepage))
5162 default_used_pointer = &default_used;
5163 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5164 ret = 0;
5165 else
5166 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5167 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5168 return ret;
5171 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5173 if (glyph < 0x100) glyph += 0xf000;
5174 /* there is a number of old pre-Unicode "broken" TTFs, which
5175 do have symbols at U+00XX instead of U+f0XX */
5176 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5177 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5179 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5181 return glyphId;
5184 /*************************************************************
5185 * freetype_GetGlyphIndices
5187 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5189 struct freetype_physdev *physdev = get_freetype_dev( dev );
5190 int i;
5191 WORD default_char;
5192 BOOL got_default = FALSE;
5194 if (!physdev->font)
5196 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5197 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5200 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5202 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5203 got_default = TRUE;
5206 GDI_CheckNotLock();
5207 EnterCriticalSection( &freetype_cs );
5209 for(i = 0; i < count; i++)
5211 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5212 if (pgi[i] == 0)
5214 if (!got_default)
5216 if (FT_IS_SFNT(physdev->font->ft_face))
5218 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5219 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5221 else
5223 TEXTMETRICW textm;
5224 get_text_metrics(physdev->font, &textm);
5225 default_char = textm.tmDefaultChar;
5227 got_default = TRUE;
5229 pgi[i] = default_char;
5232 LeaveCriticalSection( &freetype_cs );
5233 return count;
5236 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5238 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5239 return !memcmp(matrix, &identity, sizeof(FMAT2));
5242 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5244 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5245 return !memcmp(matrix, &identity, sizeof(MAT2));
5248 static inline BYTE get_max_level( UINT format )
5250 switch( format )
5252 case GGO_GRAY2_BITMAP: return 4;
5253 case GGO_GRAY4_BITMAP: return 16;
5254 case GGO_GRAY8_BITMAP: return 64;
5256 return 255;
5259 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5261 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5262 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5263 const MAT2* lpmat)
5265 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5266 FT_Face ft_face = incoming_font->ft_face;
5267 GdiFont *font = incoming_font;
5268 FT_UInt glyph_index;
5269 DWORD width, height, pitch, needed = 0;
5270 FT_Bitmap ft_bitmap;
5271 FT_Error err;
5272 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5273 FT_Angle angle = 0;
5274 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5275 double widthRatio = 1.0;
5276 FT_Matrix transMat = identityMat;
5277 FT_Matrix transMatUnrotated;
5278 BOOL needsTransform = FALSE;
5279 BOOL tategaki = (font->GSUB_Table != NULL);
5280 UINT original_index;
5282 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5283 buflen, buf, lpmat);
5285 TRACE("font transform %f %f %f %f\n",
5286 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5287 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5289 if(format & GGO_GLYPH_INDEX) {
5290 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5291 original_index = glyph;
5292 format &= ~GGO_GLYPH_INDEX;
5293 } else {
5294 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5295 ft_face = font->ft_face;
5296 original_index = glyph_index;
5299 if(format & GGO_UNHINTED) {
5300 load_flags |= FT_LOAD_NO_HINTING;
5301 format &= ~GGO_UNHINTED;
5304 /* tategaki never appears to happen to lower glyph index */
5305 if (glyph_index < TATEGAKI_LOWER_BOUND )
5306 tategaki = FALSE;
5308 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5309 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5310 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5311 font->gmsize * sizeof(GM*));
5312 } else {
5313 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5314 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5316 *lpgm = FONT_GM(font,original_index)->gm;
5317 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5318 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5319 lpgm->gmCellIncX, lpgm->gmCellIncY);
5320 return 1; /* FIXME */
5324 if (!font->gm[original_index / GM_BLOCK_SIZE])
5325 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5327 /* Scaling factor */
5328 if (font->aveWidth)
5330 TEXTMETRICW tm;
5332 get_text_metrics(font, &tm);
5334 widthRatio = (double)font->aveWidth;
5335 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5337 else
5338 widthRatio = font->scale_y;
5340 /* Scaling transform */
5341 if (widthRatio != 1.0 || font->scale_y != 1.0)
5343 FT_Matrix scaleMat;
5344 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5345 scaleMat.xy = 0;
5346 scaleMat.yx = 0;
5347 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5349 pFT_Matrix_Multiply(&scaleMat, &transMat);
5350 needsTransform = TRUE;
5353 /* Slant transform */
5354 if (font->fake_italic) {
5355 FT_Matrix slantMat;
5357 slantMat.xx = (1 << 16);
5358 slantMat.xy = ((1 << 16) >> 2);
5359 slantMat.yx = 0;
5360 slantMat.yy = (1 << 16);
5361 pFT_Matrix_Multiply(&slantMat, &transMat);
5362 needsTransform = TRUE;
5365 /* Rotation transform */
5366 transMatUnrotated = transMat;
5367 if(font->orientation && !tategaki) {
5368 FT_Matrix rotationMat;
5369 FT_Vector vecAngle;
5370 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5371 pFT_Vector_Unit(&vecAngle, angle);
5372 rotationMat.xx = vecAngle.x;
5373 rotationMat.xy = -vecAngle.y;
5374 rotationMat.yx = -rotationMat.xy;
5375 rotationMat.yy = rotationMat.xx;
5377 pFT_Matrix_Multiply(&rotationMat, &transMat);
5378 needsTransform = TRUE;
5381 /* World transform */
5382 if (!is_identity_FMAT2(&font->font_desc.matrix))
5384 FT_Matrix worldMat;
5385 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5386 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5387 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5388 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5389 pFT_Matrix_Multiply(&worldMat, &transMat);
5390 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5391 needsTransform = TRUE;
5394 /* Extra transformation specified by caller */
5395 if (!is_identity_MAT2(lpmat))
5397 FT_Matrix extraMat;
5398 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5399 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5400 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5401 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5402 pFT_Matrix_Multiply(&extraMat, &transMat);
5403 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5404 needsTransform = TRUE;
5407 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5408 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5409 format == GGO_GRAY8_BITMAP))
5411 load_flags |= FT_LOAD_NO_BITMAP;
5414 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5416 if(err) {
5417 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5418 return GDI_ERROR;
5421 if(!needsTransform) {
5422 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5423 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5424 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5426 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5427 bottom = (ft_face->glyph->metrics.horiBearingY -
5428 ft_face->glyph->metrics.height) & -64;
5429 lpgm->gmCellIncX = adv;
5430 lpgm->gmCellIncY = 0;
5431 } else {
5432 INT xc, yc;
5433 FT_Vector vec;
5435 left = right = 0;
5437 for(xc = 0; xc < 2; xc++) {
5438 for(yc = 0; yc < 2; yc++) {
5439 vec.x = (ft_face->glyph->metrics.horiBearingX +
5440 xc * ft_face->glyph->metrics.width);
5441 vec.y = ft_face->glyph->metrics.horiBearingY -
5442 yc * ft_face->glyph->metrics.height;
5443 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5444 pFT_Vector_Transform(&vec, &transMat);
5445 if(xc == 0 && yc == 0) {
5446 left = right = vec.x;
5447 top = bottom = vec.y;
5448 } else {
5449 if(vec.x < left) left = vec.x;
5450 else if(vec.x > right) right = vec.x;
5451 if(vec.y < bottom) bottom = vec.y;
5452 else if(vec.y > top) top = vec.y;
5456 left = left & -64;
5457 right = (right + 63) & -64;
5458 bottom = bottom & -64;
5459 top = (top + 63) & -64;
5461 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5462 vec.x = ft_face->glyph->metrics.horiAdvance;
5463 vec.y = 0;
5464 pFT_Vector_Transform(&vec, &transMat);
5465 lpgm->gmCellIncX = (vec.x+63) >> 6;
5466 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5468 vec.x = ft_face->glyph->metrics.horiAdvance;
5469 vec.y = 0;
5470 pFT_Vector_Transform(&vec, &transMatUnrotated);
5471 adv = (vec.x+63) >> 6;
5474 lsb = left >> 6;
5475 bbx = (right - left) >> 6;
5476 lpgm->gmBlackBoxX = (right - left) >> 6;
5477 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5478 lpgm->gmptGlyphOrigin.x = left >> 6;
5479 lpgm->gmptGlyphOrigin.y = top >> 6;
5481 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5482 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5483 lpgm->gmCellIncX, lpgm->gmCellIncY);
5485 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5486 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5488 FONT_GM(font,original_index)->gm = *lpgm;
5489 FONT_GM(font,original_index)->adv = adv;
5490 FONT_GM(font,original_index)->lsb = lsb;
5491 FONT_GM(font,original_index)->bbx = bbx;
5492 FONT_GM(font,original_index)->init = TRUE;
5495 if(format == GGO_METRICS)
5497 return 1; /* FIXME */
5500 if(ft_face->glyph->format != ft_glyph_format_outline &&
5501 (format == GGO_NATIVE || format == GGO_BEZIER))
5503 TRACE("loaded a bitmap\n");
5504 return GDI_ERROR;
5507 switch(format) {
5508 case GGO_BITMAP:
5509 width = lpgm->gmBlackBoxX;
5510 height = lpgm->gmBlackBoxY;
5511 pitch = ((width + 31) >> 5) << 2;
5512 needed = pitch * height;
5514 if(!buf || !buflen) break;
5516 switch(ft_face->glyph->format) {
5517 case ft_glyph_format_bitmap:
5519 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5520 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5521 INT h = ft_face->glyph->bitmap.rows;
5522 while(h--) {
5523 memcpy(dst, src, w);
5524 src += ft_face->glyph->bitmap.pitch;
5525 dst += pitch;
5527 break;
5530 case ft_glyph_format_outline:
5531 ft_bitmap.width = width;
5532 ft_bitmap.rows = height;
5533 ft_bitmap.pitch = pitch;
5534 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5535 ft_bitmap.buffer = buf;
5537 if(needsTransform)
5538 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5540 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5542 /* Note: FreeType will only set 'black' bits for us. */
5543 memset(buf, 0, needed);
5544 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5545 break;
5547 default:
5548 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5549 return GDI_ERROR;
5551 break;
5553 case GGO_GRAY2_BITMAP:
5554 case GGO_GRAY4_BITMAP:
5555 case GGO_GRAY8_BITMAP:
5556 case WINE_GGO_GRAY16_BITMAP:
5558 unsigned int max_level, row, col;
5559 BYTE *start, *ptr;
5561 width = lpgm->gmBlackBoxX;
5562 height = lpgm->gmBlackBoxY;
5563 pitch = (width + 3) / 4 * 4;
5564 needed = pitch * height;
5566 if(!buf || !buflen) break;
5568 max_level = get_max_level( format );
5570 switch(ft_face->glyph->format) {
5571 case ft_glyph_format_bitmap:
5573 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5574 INT h = ft_face->glyph->bitmap.rows;
5575 INT x;
5576 memset( buf, 0, needed );
5577 while(h--) {
5578 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5579 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5580 src += ft_face->glyph->bitmap.pitch;
5581 dst += pitch;
5583 return needed;
5585 case ft_glyph_format_outline:
5587 ft_bitmap.width = width;
5588 ft_bitmap.rows = height;
5589 ft_bitmap.pitch = pitch;
5590 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5591 ft_bitmap.buffer = buf;
5593 if(needsTransform)
5594 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5596 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5598 memset(ft_bitmap.buffer, 0, buflen);
5600 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5602 if (max_level != 255)
5604 for (row = 0, start = buf; row < height; row++)
5606 for (col = 0, ptr = start; col < width; col++, ptr++)
5607 *ptr = (((int)*ptr) * max_level + 128) / 256;
5608 start += pitch;
5611 return needed;
5614 default:
5615 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5616 return GDI_ERROR;
5618 break;
5621 case WINE_GGO_HRGB_BITMAP:
5622 case WINE_GGO_HBGR_BITMAP:
5623 case WINE_GGO_VRGB_BITMAP:
5624 case WINE_GGO_VBGR_BITMAP:
5625 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5627 switch (ft_face->glyph->format)
5629 case FT_GLYPH_FORMAT_BITMAP:
5631 BYTE *src, *dst;
5632 INT src_pitch, x;
5634 width = lpgm->gmBlackBoxX;
5635 height = lpgm->gmBlackBoxY;
5636 pitch = width * 4;
5637 needed = pitch * height;
5639 if (!buf || !buflen) break;
5641 memset(buf, 0, buflen);
5642 dst = buf;
5643 src = ft_face->glyph->bitmap.buffer;
5644 src_pitch = ft_face->glyph->bitmap.pitch;
5646 height = min( height, ft_face->glyph->bitmap.rows );
5647 while ( height-- )
5649 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5651 if ( src[x / 8] & masks[x % 8] )
5652 ((unsigned int *)dst)[x] = ~0u;
5654 src += src_pitch;
5655 dst += pitch;
5658 break;
5661 case FT_GLYPH_FORMAT_OUTLINE:
5663 unsigned int *dst;
5664 BYTE *src;
5665 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5666 INT x_shift, y_shift;
5667 BOOL rgb;
5668 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5669 FT_Render_Mode render_mode =
5670 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5671 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5673 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5675 if ( render_mode == FT_RENDER_MODE_LCD)
5677 lpgm->gmBlackBoxX += 2;
5678 lpgm->gmptGlyphOrigin.x -= 1;
5680 else
5682 lpgm->gmBlackBoxY += 2;
5683 lpgm->gmptGlyphOrigin.y += 1;
5687 width = lpgm->gmBlackBoxX;
5688 height = lpgm->gmBlackBoxY;
5689 pitch = width * 4;
5690 needed = pitch * height;
5692 if (!buf || !buflen) break;
5694 memset(buf, 0, buflen);
5695 dst = buf;
5696 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5698 if ( needsTransform )
5699 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5701 if ( pFT_Library_SetLcdFilter )
5702 pFT_Library_SetLcdFilter( library, lcdfilter );
5703 pFT_Render_Glyph (ft_face->glyph, render_mode);
5705 src = ft_face->glyph->bitmap.buffer;
5706 src_pitch = ft_face->glyph->bitmap.pitch;
5707 src_width = ft_face->glyph->bitmap.width;
5708 src_height = ft_face->glyph->bitmap.rows;
5710 if ( render_mode == FT_RENDER_MODE_LCD)
5712 rgb_interval = 1;
5713 hmul = 3;
5714 vmul = 1;
5716 else
5718 rgb_interval = src_pitch;
5719 hmul = 1;
5720 vmul = 3;
5723 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5724 if ( x_shift < 0 ) x_shift = 0;
5725 if ( x_shift + (src_width / hmul) > width )
5726 x_shift = width - (src_width / hmul);
5728 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5729 if ( y_shift < 0 ) y_shift = 0;
5730 if ( y_shift + (src_height / vmul) > height )
5731 y_shift = height - (src_height / vmul);
5733 dst += x_shift + y_shift * ( pitch / 4 );
5734 while ( src_height )
5736 for ( x = 0; x < src_width / hmul; x++ )
5738 if ( rgb )
5740 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5741 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5742 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5743 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5745 else
5747 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5748 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5749 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5750 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5753 src += src_pitch * vmul;
5754 dst += pitch / 4;
5755 src_height -= vmul;
5758 break;
5761 default:
5762 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5763 return GDI_ERROR;
5766 break;
5768 #else
5769 return GDI_ERROR;
5770 #endif
5772 case GGO_NATIVE:
5774 int contour, point = 0, first_pt;
5775 FT_Outline *outline = &ft_face->glyph->outline;
5776 TTPOLYGONHEADER *pph;
5777 TTPOLYCURVE *ppc;
5778 DWORD pph_start, cpfx, type;
5780 if(buflen == 0) buf = NULL;
5782 if (needsTransform && buf) {
5783 pFT_Outline_Transform(outline, &transMat);
5786 for(contour = 0; contour < outline->n_contours; contour++) {
5787 pph_start = needed;
5788 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5789 first_pt = point;
5790 if(buf) {
5791 pph->dwType = TT_POLYGON_TYPE;
5792 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5794 needed += sizeof(*pph);
5795 point++;
5796 while(point <= outline->contours[contour]) {
5797 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5798 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5799 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5800 cpfx = 0;
5801 do {
5802 if(buf)
5803 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5804 cpfx++;
5805 point++;
5806 } while(point <= outline->contours[contour] &&
5807 (outline->tags[point] & FT_Curve_Tag_On) ==
5808 (outline->tags[point-1] & FT_Curve_Tag_On));
5809 /* At the end of a contour Windows adds the start point, but
5810 only for Beziers */
5811 if(point > outline->contours[contour] &&
5812 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5813 if(buf)
5814 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5815 cpfx++;
5816 } else if(point <= outline->contours[contour] &&
5817 outline->tags[point] & FT_Curve_Tag_On) {
5818 /* add closing pt for bezier */
5819 if(buf)
5820 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5821 cpfx++;
5822 point++;
5824 if(buf) {
5825 ppc->wType = type;
5826 ppc->cpfx = cpfx;
5828 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5830 if(buf)
5831 pph->cb = needed - pph_start;
5833 break;
5835 case GGO_BEZIER:
5837 /* Convert the quadratic Beziers to cubic Beziers.
5838 The parametric eqn for a cubic Bezier is, from PLRM:
5839 r(t) = at^3 + bt^2 + ct + r0
5840 with the control points:
5841 r1 = r0 + c/3
5842 r2 = r1 + (c + b)/3
5843 r3 = r0 + c + b + a
5845 A quadratic Bezier has the form:
5846 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5848 So equating powers of t leads to:
5849 r1 = 2/3 p1 + 1/3 p0
5850 r2 = 2/3 p1 + 1/3 p2
5851 and of course r0 = p0, r3 = p2
5854 int contour, point = 0, first_pt;
5855 FT_Outline *outline = &ft_face->glyph->outline;
5856 TTPOLYGONHEADER *pph;
5857 TTPOLYCURVE *ppc;
5858 DWORD pph_start, cpfx, type;
5859 FT_Vector cubic_control[4];
5860 if(buflen == 0) buf = NULL;
5862 if (needsTransform && buf) {
5863 pFT_Outline_Transform(outline, &transMat);
5866 for(contour = 0; contour < outline->n_contours; contour++) {
5867 pph_start = needed;
5868 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5869 first_pt = point;
5870 if(buf) {
5871 pph->dwType = TT_POLYGON_TYPE;
5872 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5874 needed += sizeof(*pph);
5875 point++;
5876 while(point <= outline->contours[contour]) {
5877 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5878 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5879 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5880 cpfx = 0;
5881 do {
5882 if(type == TT_PRIM_LINE) {
5883 if(buf)
5884 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5885 cpfx++;
5886 point++;
5887 } else {
5888 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5889 so cpfx = 3n */
5891 /* FIXME: Possible optimization in endpoint calculation
5892 if there are two consecutive curves */
5893 cubic_control[0] = outline->points[point-1];
5894 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5895 cubic_control[0].x += outline->points[point].x + 1;
5896 cubic_control[0].y += outline->points[point].y + 1;
5897 cubic_control[0].x >>= 1;
5898 cubic_control[0].y >>= 1;
5900 if(point+1 > outline->contours[contour])
5901 cubic_control[3] = outline->points[first_pt];
5902 else {
5903 cubic_control[3] = outline->points[point+1];
5904 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5905 cubic_control[3].x += outline->points[point].x + 1;
5906 cubic_control[3].y += outline->points[point].y + 1;
5907 cubic_control[3].x >>= 1;
5908 cubic_control[3].y >>= 1;
5911 /* r1 = 1/3 p0 + 2/3 p1
5912 r2 = 1/3 p2 + 2/3 p1 */
5913 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5914 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5915 cubic_control[2] = cubic_control[1];
5916 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5917 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5918 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5919 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5920 if(buf) {
5921 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5922 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5923 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5925 cpfx += 3;
5926 point++;
5928 } while(point <= outline->contours[contour] &&
5929 (outline->tags[point] & FT_Curve_Tag_On) ==
5930 (outline->tags[point-1] & FT_Curve_Tag_On));
5931 /* At the end of a contour Windows adds the start point,
5932 but only for Beziers and we've already done that.
5934 if(point <= outline->contours[contour] &&
5935 outline->tags[point] & FT_Curve_Tag_On) {
5936 /* This is the closing pt of a bezier, but we've already
5937 added it, so just inc point and carry on */
5938 point++;
5940 if(buf) {
5941 ppc->wType = type;
5942 ppc->cpfx = cpfx;
5944 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5946 if(buf)
5947 pph->cb = needed - pph_start;
5949 break;
5952 default:
5953 FIXME("Unsupported format %d\n", format);
5954 return GDI_ERROR;
5956 return needed;
5959 static BOOL get_bitmap_text_metrics(GdiFont *font)
5961 FT_Face ft_face = font->ft_face;
5962 FT_WinFNT_HeaderRec winfnt_header;
5963 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5964 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5965 font->potm->otmSize = size;
5967 #define TM font->potm->otmTextMetrics
5968 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5970 TM.tmHeight = winfnt_header.pixel_height;
5971 TM.tmAscent = winfnt_header.ascent;
5972 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5973 TM.tmInternalLeading = winfnt_header.internal_leading;
5974 TM.tmExternalLeading = winfnt_header.external_leading;
5975 TM.tmAveCharWidth = winfnt_header.avg_width;
5976 TM.tmMaxCharWidth = winfnt_header.max_width;
5977 TM.tmWeight = winfnt_header.weight;
5978 TM.tmOverhang = 0;
5979 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5980 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5981 TM.tmFirstChar = winfnt_header.first_char;
5982 TM.tmLastChar = winfnt_header.last_char;
5983 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5984 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5985 TM.tmItalic = winfnt_header.italic;
5986 TM.tmUnderlined = font->underline;
5987 TM.tmStruckOut = font->strikeout;
5988 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5989 TM.tmCharSet = winfnt_header.charset;
5991 else
5993 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5994 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5995 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5996 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5997 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5998 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5999 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6000 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6001 TM.tmOverhang = 0;
6002 TM.tmDigitizedAspectX = 96; /* FIXME */
6003 TM.tmDigitizedAspectY = 96; /* FIXME */
6004 TM.tmFirstChar = 1;
6005 TM.tmLastChar = 255;
6006 TM.tmDefaultChar = 32;
6007 TM.tmBreakChar = 32;
6008 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6009 TM.tmUnderlined = font->underline;
6010 TM.tmStruckOut = font->strikeout;
6011 /* NB inverted meaning of TMPF_FIXED_PITCH */
6012 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6013 TM.tmCharSet = font->charset;
6015 #undef TM
6017 return TRUE;
6021 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6023 double scale_x, scale_y;
6025 if (font->aveWidth)
6027 scale_x = (double)font->aveWidth;
6028 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6030 else
6031 scale_x = font->scale_y;
6033 scale_x *= fabs(font->font_desc.matrix.eM11);
6034 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6036 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6037 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6039 SCALE_Y(ptm->tmHeight);
6040 SCALE_Y(ptm->tmAscent);
6041 SCALE_Y(ptm->tmDescent);
6042 SCALE_Y(ptm->tmInternalLeading);
6043 SCALE_Y(ptm->tmExternalLeading);
6044 SCALE_Y(ptm->tmOverhang);
6046 SCALE_X(ptm->tmAveCharWidth);
6047 SCALE_X(ptm->tmMaxCharWidth);
6049 #undef SCALE_X
6050 #undef SCALE_Y
6053 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6055 double scale_x, scale_y;
6057 if (font->aveWidth)
6059 scale_x = (double)font->aveWidth;
6060 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6062 else
6063 scale_x = font->scale_y;
6065 scale_x *= fabs(font->font_desc.matrix.eM11);
6066 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6068 scale_font_metrics(font, &potm->otmTextMetrics);
6070 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6071 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6073 SCALE_Y(potm->otmAscent);
6074 SCALE_Y(potm->otmDescent);
6075 SCALE_Y(potm->otmLineGap);
6076 SCALE_Y(potm->otmsCapEmHeight);
6077 SCALE_Y(potm->otmsXHeight);
6078 SCALE_Y(potm->otmrcFontBox.top);
6079 SCALE_Y(potm->otmrcFontBox.bottom);
6080 SCALE_X(potm->otmrcFontBox.left);
6081 SCALE_X(potm->otmrcFontBox.right);
6082 SCALE_Y(potm->otmMacAscent);
6083 SCALE_Y(potm->otmMacDescent);
6084 SCALE_Y(potm->otmMacLineGap);
6085 SCALE_X(potm->otmptSubscriptSize.x);
6086 SCALE_Y(potm->otmptSubscriptSize.y);
6087 SCALE_X(potm->otmptSubscriptOffset.x);
6088 SCALE_Y(potm->otmptSubscriptOffset.y);
6089 SCALE_X(potm->otmptSuperscriptSize.x);
6090 SCALE_Y(potm->otmptSuperscriptSize.y);
6091 SCALE_X(potm->otmptSuperscriptOffset.x);
6092 SCALE_Y(potm->otmptSuperscriptOffset.y);
6093 SCALE_Y(potm->otmsStrikeoutSize);
6094 SCALE_Y(potm->otmsStrikeoutPosition);
6095 SCALE_Y(potm->otmsUnderscoreSize);
6096 SCALE_Y(potm->otmsUnderscorePosition);
6098 #undef SCALE_X
6099 #undef SCALE_Y
6102 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6104 if(!font->potm)
6106 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6108 /* Make sure that the font has sane width/height ratio */
6109 if (font->aveWidth)
6111 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6113 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6114 font->aveWidth = 0;
6118 *ptm = font->potm->otmTextMetrics;
6119 scale_font_metrics(font, ptm);
6120 return TRUE;
6123 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6125 int i;
6127 for(i = 0; i < ft_face->num_charmaps; i++)
6129 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6130 return TRUE;
6132 return FALSE;
6135 static BOOL get_outline_text_metrics(GdiFont *font)
6137 BOOL ret = FALSE;
6138 FT_Face ft_face = font->ft_face;
6139 UINT needed, lenfam, lensty;
6140 TT_OS2 *pOS2;
6141 TT_HoriHeader *pHori;
6142 TT_Postscript *pPost;
6143 FT_Fixed x_scale, y_scale;
6144 WCHAR *family_nameW, *style_nameW;
6145 static const WCHAR spaceW[] = {' ', '\0'};
6146 char *cp;
6147 INT ascent, descent;
6149 TRACE("font=%p\n", font);
6151 if(!FT_IS_SCALABLE(ft_face))
6152 return FALSE;
6154 needed = sizeof(*font->potm);
6156 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6157 family_nameW = strdupW(font->name);
6159 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6160 * sizeof(WCHAR);
6161 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6162 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6163 style_nameW, lensty/sizeof(WCHAR));
6165 /* These names should be read from the TT name table */
6167 /* length of otmpFamilyName */
6168 needed += lenfam;
6170 /* length of otmpFaceName */
6171 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6172 needed += lenfam; /* just the family name */
6173 } else {
6174 needed += lenfam + lensty; /* family + " " + style */
6177 /* length of otmpStyleName */
6178 needed += lensty;
6180 /* length of otmpFullName */
6181 needed += lenfam + lensty;
6184 x_scale = ft_face->size->metrics.x_scale;
6185 y_scale = ft_face->size->metrics.y_scale;
6187 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6188 if(!pOS2) {
6189 FIXME("Can't find OS/2 table - not TT font?\n");
6190 goto end;
6193 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6194 if(!pHori) {
6195 FIXME("Can't find HHEA table - not TT font?\n");
6196 goto end;
6199 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6201 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",
6202 pOS2->usWinAscent, pOS2->usWinDescent,
6203 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6204 ft_face->ascender, ft_face->descender, ft_face->height,
6205 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6206 ft_face->bbox.yMax, ft_face->bbox.yMin);
6208 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6209 font->potm->otmSize = needed;
6211 #define TM font->potm->otmTextMetrics
6213 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6214 ascent = pHori->Ascender;
6215 descent = -pHori->Descender;
6216 } else {
6217 ascent = pOS2->usWinAscent;
6218 descent = pOS2->usWinDescent;
6221 if(font->yMax) {
6222 TM.tmAscent = font->yMax;
6223 TM.tmDescent = -font->yMin;
6224 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6225 } else {
6226 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6227 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6228 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6229 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6232 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6234 /* MSDN says:
6235 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6237 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6238 ((ascent + descent) -
6239 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6241 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6242 if (TM.tmAveCharWidth == 0) {
6243 TM.tmAveCharWidth = 1;
6245 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6246 TM.tmWeight = FW_REGULAR;
6247 if (font->fake_bold)
6248 TM.tmWeight = FW_BOLD;
6249 else
6251 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6253 if (pOS2->usWeightClass > FW_MEDIUM)
6254 TM.tmWeight = pOS2->usWeightClass;
6256 else if (pOS2->usWeightClass <= FW_MEDIUM)
6257 TM.tmWeight = pOS2->usWeightClass;
6259 TM.tmOverhang = 0;
6260 TM.tmDigitizedAspectX = 300;
6261 TM.tmDigitizedAspectY = 300;
6262 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6263 * symbol range to 0 - f0ff
6266 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6268 TM.tmFirstChar = 0;
6269 switch(GetACP())
6271 case 1257: /* Baltic */
6272 TM.tmLastChar = 0xf8fd;
6273 break;
6274 default:
6275 TM.tmLastChar = 0xf0ff;
6277 TM.tmBreakChar = 0x20;
6278 TM.tmDefaultChar = 0x1f;
6280 else
6282 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6283 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6285 if(pOS2->usFirstCharIndex <= 1)
6286 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6287 else if (pOS2->usFirstCharIndex > 0xff)
6288 TM.tmBreakChar = 0x20;
6289 else
6290 TM.tmBreakChar = pOS2->usFirstCharIndex;
6291 TM.tmDefaultChar = TM.tmBreakChar - 1;
6293 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6294 TM.tmUnderlined = font->underline;
6295 TM.tmStruckOut = font->strikeout;
6297 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6298 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6299 (pOS2->version == 0xFFFFU ||
6300 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6301 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6302 else
6303 TM.tmPitchAndFamily = 0;
6305 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6307 case PAN_FAMILY_SCRIPT:
6308 TM.tmPitchAndFamily |= FF_SCRIPT;
6309 break;
6311 case PAN_FAMILY_DECORATIVE:
6312 TM.tmPitchAndFamily |= FF_DECORATIVE;
6313 break;
6315 case PAN_ANY:
6316 case PAN_NO_FIT:
6317 case PAN_FAMILY_TEXT_DISPLAY:
6318 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6319 /* which is clearly not what the panose spec says. */
6320 default:
6321 if(TM.tmPitchAndFamily == 0 || /* fixed */
6322 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6323 TM.tmPitchAndFamily = FF_MODERN;
6324 else
6326 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6328 case PAN_ANY:
6329 case PAN_NO_FIT:
6330 default:
6331 TM.tmPitchAndFamily |= FF_DONTCARE;
6332 break;
6334 case PAN_SERIF_COVE:
6335 case PAN_SERIF_OBTUSE_COVE:
6336 case PAN_SERIF_SQUARE_COVE:
6337 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6338 case PAN_SERIF_SQUARE:
6339 case PAN_SERIF_THIN:
6340 case PAN_SERIF_BONE:
6341 case PAN_SERIF_EXAGGERATED:
6342 case PAN_SERIF_TRIANGLE:
6343 TM.tmPitchAndFamily |= FF_ROMAN;
6344 break;
6346 case PAN_SERIF_NORMAL_SANS:
6347 case PAN_SERIF_OBTUSE_SANS:
6348 case PAN_SERIF_PERP_SANS:
6349 case PAN_SERIF_FLARED:
6350 case PAN_SERIF_ROUNDED:
6351 TM.tmPitchAndFamily |= FF_SWISS;
6352 break;
6355 break;
6358 if(FT_IS_SCALABLE(ft_face))
6359 TM.tmPitchAndFamily |= TMPF_VECTOR;
6361 if(FT_IS_SFNT(ft_face))
6363 if (font->ntmFlags & NTM_PS_OPENTYPE)
6364 TM.tmPitchAndFamily |= TMPF_DEVICE;
6365 else
6366 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6369 TM.tmCharSet = font->charset;
6371 font->potm->otmFiller = 0;
6372 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6373 font->potm->otmfsSelection = pOS2->fsSelection;
6374 font->potm->otmfsType = pOS2->fsType;
6375 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6376 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6377 font->potm->otmItalicAngle = 0; /* POST table */
6378 font->potm->otmEMSquare = ft_face->units_per_EM;
6379 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6380 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6381 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6382 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6383 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6384 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6385 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6386 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6387 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6388 font->potm->otmMacAscent = TM.tmAscent;
6389 font->potm->otmMacDescent = -TM.tmDescent;
6390 font->potm->otmMacLineGap = font->potm->otmLineGap;
6391 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6392 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6393 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6394 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6395 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6396 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6397 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6398 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6399 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6400 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6401 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6402 if(!pPost) {
6403 font->potm->otmsUnderscoreSize = 0;
6404 font->potm->otmsUnderscorePosition = 0;
6405 } else {
6406 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6407 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6409 #undef TM
6411 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6412 cp = (char*)font->potm + sizeof(*font->potm);
6413 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6414 strcpyW((WCHAR*)cp, family_nameW);
6415 cp += lenfam;
6416 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6417 strcpyW((WCHAR*)cp, style_nameW);
6418 cp += lensty;
6419 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6420 strcpyW((WCHAR*)cp, family_nameW);
6421 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6422 strcatW((WCHAR*)cp, spaceW);
6423 strcatW((WCHAR*)cp, style_nameW);
6424 cp += lenfam + lensty;
6425 } else
6426 cp += lenfam;
6427 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6428 strcpyW((WCHAR*)cp, family_nameW);
6429 strcatW((WCHAR*)cp, spaceW);
6430 strcatW((WCHAR*)cp, style_nameW);
6431 ret = TRUE;
6433 end:
6434 HeapFree(GetProcessHeap(), 0, style_nameW);
6435 HeapFree(GetProcessHeap(), 0, family_nameW);
6436 return ret;
6439 /*************************************************************
6440 * freetype_GetGlyphOutline
6442 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6443 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6445 struct freetype_physdev *physdev = get_freetype_dev( dev );
6446 DWORD ret;
6448 if (!physdev->font)
6450 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6451 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6454 GDI_CheckNotLock();
6455 EnterCriticalSection( &freetype_cs );
6456 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6457 LeaveCriticalSection( &freetype_cs );
6458 return ret;
6461 /*************************************************************
6462 * freetype_GetTextMetrics
6464 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6466 struct freetype_physdev *physdev = get_freetype_dev( dev );
6467 BOOL ret;
6469 if (!physdev->font)
6471 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6472 return dev->funcs->pGetTextMetrics( dev, metrics );
6475 GDI_CheckNotLock();
6476 EnterCriticalSection( &freetype_cs );
6477 ret = get_text_metrics( physdev->font, metrics );
6478 LeaveCriticalSection( &freetype_cs );
6479 return ret;
6482 /*************************************************************
6483 * freetype_GetOutlineTextMetrics
6485 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6487 struct freetype_physdev *physdev = get_freetype_dev( dev );
6488 UINT ret = 0;
6490 if (!physdev->font)
6492 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6493 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6496 TRACE("font=%p\n", physdev->font);
6498 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6500 GDI_CheckNotLock();
6501 EnterCriticalSection( &freetype_cs );
6503 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6505 if(cbSize >= physdev->font->potm->otmSize)
6507 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6508 scale_outline_font_metrics(physdev->font, potm);
6510 ret = physdev->font->potm->otmSize;
6512 LeaveCriticalSection( &freetype_cs );
6513 return ret;
6516 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6518 HFONTLIST *hfontlist;
6519 child->font = alloc_font();
6520 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6521 if(!child->font->ft_face)
6523 free_font(child->font);
6524 child->font = NULL;
6525 return FALSE;
6528 child->font->font_desc = font->font_desc;
6529 child->font->ntmFlags = child->face->ntmFlags;
6530 child->font->orientation = font->orientation;
6531 child->font->scale_y = font->scale_y;
6532 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6533 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6534 child->font->name = strdupW(child->face->family->FamilyName);
6535 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6536 child->font->base_font = font;
6537 list_add_head(&child_font_list, &child->font->entry);
6538 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6539 return TRUE;
6542 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6544 FT_UInt g;
6545 CHILD_FONT *child_font;
6547 if(font->base_font)
6548 font = font->base_font;
6550 *linked_font = font;
6552 if((*glyph = get_glyph_index(font, c)))
6554 *glyph = get_GSUB_vert_glyph(font, *glyph);
6555 return TRUE;
6558 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6560 if(!child_font->font)
6561 if(!load_child_font(font, child_font))
6562 continue;
6564 if(!child_font->font->ft_face)
6565 continue;
6566 g = get_glyph_index(child_font->font, c);
6567 g = get_GSUB_vert_glyph(child_font->font, g);
6568 if(g)
6570 *glyph = g;
6571 *linked_font = child_font->font;
6572 return TRUE;
6575 return FALSE;
6578 /*************************************************************
6579 * freetype_GetCharWidth
6581 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6583 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6584 UINT c;
6585 GLYPHMETRICS gm;
6586 FT_UInt glyph_index;
6587 GdiFont *linked_font;
6588 struct freetype_physdev *physdev = get_freetype_dev( dev );
6590 if (!physdev->font)
6592 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6593 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6596 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6598 GDI_CheckNotLock();
6599 EnterCriticalSection( &freetype_cs );
6600 for(c = firstChar; c <= lastChar; c++) {
6601 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6602 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6603 &gm, 0, NULL, &identity);
6604 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6606 LeaveCriticalSection( &freetype_cs );
6607 return TRUE;
6610 /*************************************************************
6611 * freetype_GetCharABCWidths
6613 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6615 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6616 UINT c;
6617 GLYPHMETRICS gm;
6618 FT_UInt glyph_index;
6619 GdiFont *linked_font;
6620 struct freetype_physdev *physdev = get_freetype_dev( dev );
6622 if (!physdev->font)
6624 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6625 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6628 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6630 GDI_CheckNotLock();
6631 EnterCriticalSection( &freetype_cs );
6633 for(c = firstChar; c <= lastChar; c++) {
6634 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6635 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6636 &gm, 0, NULL, &identity);
6637 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6638 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6639 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6640 FONT_GM(linked_font,glyph_index)->bbx;
6642 LeaveCriticalSection( &freetype_cs );
6643 return TRUE;
6646 /*************************************************************
6647 * freetype_GetCharABCWidthsI
6649 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6651 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6652 UINT c;
6653 GLYPHMETRICS gm;
6654 FT_UInt glyph_index;
6655 GdiFont *linked_font;
6656 struct freetype_physdev *physdev = get_freetype_dev( dev );
6658 if (!physdev->font)
6660 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6661 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6664 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6665 return FALSE;
6667 GDI_CheckNotLock();
6668 EnterCriticalSection( &freetype_cs );
6670 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6671 if (!pgi)
6672 for(c = firstChar; c < firstChar+count; c++) {
6673 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6674 &gm, 0, NULL, &identity);
6675 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6676 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6677 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6678 - FONT_GM(linked_font,c)->bbx;
6680 else
6681 for(c = 0; c < count; c++) {
6682 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6683 &gm, 0, NULL, &identity);
6684 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6685 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6686 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6687 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6690 LeaveCriticalSection( &freetype_cs );
6691 return TRUE;
6694 /*************************************************************
6695 * freetype_GetTextExtentExPoint
6697 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6698 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6700 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6701 INT idx;
6702 INT nfit = 0, ext;
6703 GLYPHMETRICS gm;
6704 TEXTMETRICW tm;
6705 FT_UInt glyph_index;
6706 GdiFont *linked_font;
6707 struct freetype_physdev *physdev = get_freetype_dev( dev );
6709 if (!physdev->font)
6711 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6712 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6715 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6717 GDI_CheckNotLock();
6718 EnterCriticalSection( &freetype_cs );
6720 size->cx = 0;
6721 get_text_metrics( physdev->font, &tm );
6722 size->cy = tm.tmHeight;
6724 for(idx = 0; idx < count; idx++) {
6725 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6726 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6727 &gm, 0, NULL, &identity);
6728 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6729 ext = size->cx;
6730 if (! pnfit || ext <= max_ext) {
6731 ++nfit;
6732 if (dxs)
6733 dxs[idx] = ext;
6737 if (pnfit)
6738 *pnfit = nfit;
6740 LeaveCriticalSection( &freetype_cs );
6741 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6742 return TRUE;
6745 /*************************************************************
6746 * freetype_GetTextExtentExPointI
6748 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6749 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6751 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6752 INT idx;
6753 INT nfit = 0, ext;
6754 GLYPHMETRICS gm;
6755 TEXTMETRICW tm;
6756 struct freetype_physdev *physdev = get_freetype_dev( dev );
6758 if (!physdev->font)
6760 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6761 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6764 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6766 GDI_CheckNotLock();
6767 EnterCriticalSection( &freetype_cs );
6769 size->cx = 0;
6770 get_text_metrics(physdev->font, &tm);
6771 size->cy = tm.tmHeight;
6773 for(idx = 0; idx < count; idx++) {
6774 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6775 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6776 ext = size->cx;
6777 if (! pnfit || ext <= max_ext) {
6778 ++nfit;
6779 if (dxs)
6780 dxs[idx] = ext;
6784 if (pnfit)
6785 *pnfit = nfit;
6787 LeaveCriticalSection( &freetype_cs );
6788 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6789 return TRUE;
6792 /*************************************************************
6793 * freetype_GetFontData
6795 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6797 struct freetype_physdev *physdev = get_freetype_dev( dev );
6799 if (!physdev->font)
6801 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6802 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6805 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6806 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6807 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6809 return get_font_data( physdev->font, table, offset, buf, cbData );
6812 /*************************************************************
6813 * freetype_GetTextFace
6815 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6817 INT n;
6818 struct freetype_physdev *physdev = get_freetype_dev( dev );
6820 if (!physdev->font)
6822 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6823 return dev->funcs->pGetTextFace( dev, count, str );
6826 n = strlenW(physdev->font->name) + 1;
6827 if (str)
6829 lstrcpynW(str, physdev->font->name, count);
6830 n = min(count, n);
6832 return n;
6835 /*************************************************************
6836 * freetype_GetTextCharsetInfo
6838 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6840 struct freetype_physdev *physdev = get_freetype_dev( dev );
6842 if (!physdev->font)
6844 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6845 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6847 if (fs) *fs = physdev->font->fs;
6848 return physdev->font->charset;
6851 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6853 GdiFont *font = dc->gdiFont, *linked_font;
6854 struct list *first_hfont;
6855 BOOL ret;
6857 GDI_CheckNotLock();
6858 EnterCriticalSection( &freetype_cs );
6859 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6860 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6861 if(font == linked_font)
6862 *new_hfont = dc->hFont;
6863 else
6865 first_hfont = list_head(&linked_font->hfontlist);
6866 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6868 LeaveCriticalSection( &freetype_cs );
6869 return ret;
6872 /* Retrieve a list of supported Unicode ranges for a given font.
6873 * Can be called with NULL gs to calculate the buffer size. Returns
6874 * the number of ranges found.
6876 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6878 DWORD num_ranges = 0;
6880 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6882 FT_UInt glyph_code;
6883 FT_ULong char_code, char_code_prev;
6885 glyph_code = 0;
6886 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6888 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6889 face->num_glyphs, glyph_code, char_code);
6891 if (!glyph_code) return 0;
6893 if (gs)
6895 gs->ranges[0].wcLow = (USHORT)char_code;
6896 gs->ranges[0].cGlyphs = 0;
6897 gs->cGlyphsSupported = 0;
6900 num_ranges = 1;
6901 while (glyph_code)
6903 if (char_code < char_code_prev)
6905 ERR("expected increasing char code from FT_Get_Next_Char\n");
6906 return 0;
6908 if (char_code - char_code_prev > 1)
6910 num_ranges++;
6911 if (gs)
6913 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6914 gs->ranges[num_ranges - 1].cGlyphs = 1;
6915 gs->cGlyphsSupported++;
6918 else if (gs)
6920 gs->ranges[num_ranges - 1].cGlyphs++;
6921 gs->cGlyphsSupported++;
6923 char_code_prev = char_code;
6924 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6927 else
6928 FIXME("encoding %u not supported\n", face->charmap->encoding);
6930 return num_ranges;
6933 /*************************************************************
6934 * freetype_GetFontUnicodeRanges
6936 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6938 struct freetype_physdev *physdev = get_freetype_dev( dev );
6939 DWORD size, num_ranges;
6941 if (!physdev->font)
6943 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6944 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6947 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6948 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6949 if (glyphset)
6951 glyphset->cbThis = size;
6952 glyphset->cRanges = num_ranges;
6953 glyphset->flAccel = 0;
6955 return size;
6958 /*************************************************************
6959 * freetype_FontIsLinked
6961 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6963 struct freetype_physdev *physdev = get_freetype_dev( dev );
6964 BOOL ret;
6966 if (!physdev->font)
6968 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6969 return dev->funcs->pFontIsLinked( dev );
6972 GDI_CheckNotLock();
6973 EnterCriticalSection( &freetype_cs );
6974 ret = !list_empty(&physdev->font->child_fonts);
6975 LeaveCriticalSection( &freetype_cs );
6976 return ret;
6979 static BOOL is_hinting_enabled(void)
6981 /* Use the >= 2.2.0 function if available */
6982 if(pFT_Get_TrueType_Engine_Type)
6984 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6985 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6987 #ifdef FT_DRIVER_HAS_HINTER
6988 else
6990 FT_Module mod;
6992 /* otherwise if we've been compiled with < 2.2.0 headers
6993 use the internal macro */
6994 mod = pFT_Get_Module(library, "truetype");
6995 if(mod && FT_DRIVER_HAS_HINTER(mod))
6996 return TRUE;
6998 #endif
7000 return FALSE;
7003 static BOOL is_subpixel_rendering_enabled( void )
7005 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7006 return pFT_Library_SetLcdFilter &&
7007 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
7008 #else
7009 return FALSE;
7010 #endif
7013 /*************************************************************************
7014 * GetRasterizerCaps (GDI32.@)
7016 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7018 static int hinting = -1;
7019 static int subpixel = -1;
7021 if(hinting == -1)
7023 hinting = is_hinting_enabled();
7024 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7027 if ( subpixel == -1 )
7029 subpixel = is_subpixel_rendering_enabled();
7030 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7033 lprs->nSize = sizeof(RASTERIZER_STATUS);
7034 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7035 if ( subpixel )
7036 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7037 lprs->nLanguageID = 0;
7038 return TRUE;
7041 /*************************************************************
7042 * freetype_GdiRealizationInfo
7044 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7046 struct freetype_physdev *physdev = get_freetype_dev( dev );
7047 realization_info_t *info = ptr;
7049 if (!physdev->font)
7051 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7052 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7055 FIXME("(%p, %p): stub!\n", physdev->font, info);
7057 info->flags = 1;
7058 if(FT_IS_SCALABLE(physdev->font->ft_face))
7059 info->flags |= 2;
7061 info->cache_num = physdev->font->cache_num;
7062 info->unknown2 = -1;
7063 return TRUE;
7066 /*************************************************************************
7067 * Kerning support for TrueType fonts
7069 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7071 struct TT_kern_table
7073 USHORT version;
7074 USHORT nTables;
7077 struct TT_kern_subtable
7079 USHORT version;
7080 USHORT length;
7081 union
7083 USHORT word;
7084 struct
7086 USHORT horizontal : 1;
7087 USHORT minimum : 1;
7088 USHORT cross_stream: 1;
7089 USHORT override : 1;
7090 USHORT reserved1 : 4;
7091 USHORT format : 8;
7092 } bits;
7093 } coverage;
7096 struct TT_format0_kern_subtable
7098 USHORT nPairs;
7099 USHORT searchRange;
7100 USHORT entrySelector;
7101 USHORT rangeShift;
7104 struct TT_kern_pair
7106 USHORT left;
7107 USHORT right;
7108 short value;
7111 static DWORD parse_format0_kern_subtable(GdiFont *font,
7112 const struct TT_format0_kern_subtable *tt_f0_ks,
7113 const USHORT *glyph_to_char,
7114 KERNINGPAIR *kern_pair, DWORD cPairs)
7116 USHORT i, nPairs;
7117 const struct TT_kern_pair *tt_kern_pair;
7119 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7121 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7123 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7124 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7125 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7127 if (!kern_pair || !cPairs)
7128 return nPairs;
7130 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7132 nPairs = min(nPairs, cPairs);
7134 for (i = 0; i < nPairs; i++)
7136 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7137 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7138 /* this algorithm appears to better match what Windows does */
7139 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7140 if (kern_pair->iKernAmount < 0)
7142 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7143 kern_pair->iKernAmount -= font->ppem;
7145 else if (kern_pair->iKernAmount > 0)
7147 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7148 kern_pair->iKernAmount += font->ppem;
7150 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7152 TRACE("left %u right %u value %d\n",
7153 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7155 kern_pair++;
7157 TRACE("copied %u entries\n", nPairs);
7158 return nPairs;
7161 /*************************************************************
7162 * freetype_GetKerningPairs
7164 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7166 DWORD length;
7167 void *buf;
7168 const struct TT_kern_table *tt_kern_table;
7169 const struct TT_kern_subtable *tt_kern_subtable;
7170 USHORT i, nTables;
7171 USHORT *glyph_to_char;
7172 GdiFont *font;
7173 struct freetype_physdev *physdev = get_freetype_dev( dev );
7175 if (!(font = physdev->font))
7177 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7178 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7181 GDI_CheckNotLock();
7182 EnterCriticalSection( &freetype_cs );
7183 if (font->total_kern_pairs != (DWORD)-1)
7185 if (cPairs && kern_pair)
7187 cPairs = min(cPairs, font->total_kern_pairs);
7188 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7190 else cPairs = font->total_kern_pairs;
7192 LeaveCriticalSection( &freetype_cs );
7193 return cPairs;
7196 font->total_kern_pairs = 0;
7198 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7200 if (length == GDI_ERROR)
7202 TRACE("no kerning data in the font\n");
7203 LeaveCriticalSection( &freetype_cs );
7204 return 0;
7207 buf = HeapAlloc(GetProcessHeap(), 0, length);
7208 if (!buf)
7210 WARN("Out of memory\n");
7211 LeaveCriticalSection( &freetype_cs );
7212 return 0;
7215 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7217 /* build a glyph index to char code map */
7218 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7219 if (!glyph_to_char)
7221 WARN("Out of memory allocating a glyph index to char code map\n");
7222 HeapFree(GetProcessHeap(), 0, buf);
7223 LeaveCriticalSection( &freetype_cs );
7224 return 0;
7227 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7229 FT_UInt glyph_code;
7230 FT_ULong char_code;
7232 glyph_code = 0;
7233 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7235 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7236 font->ft_face->num_glyphs, glyph_code, char_code);
7238 while (glyph_code)
7240 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7242 /* FIXME: This doesn't match what Windows does: it does some fancy
7243 * things with duplicate glyph index to char code mappings, while
7244 * we just avoid overriding existing entries.
7246 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7247 glyph_to_char[glyph_code] = (USHORT)char_code;
7249 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7252 else
7254 ULONG n;
7256 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7257 for (n = 0; n <= 65535; n++)
7258 glyph_to_char[n] = (USHORT)n;
7261 tt_kern_table = buf;
7262 nTables = GET_BE_WORD(tt_kern_table->nTables);
7263 TRACE("version %u, nTables %u\n",
7264 GET_BE_WORD(tt_kern_table->version), nTables);
7266 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7268 for (i = 0; i < nTables; i++)
7270 struct TT_kern_subtable tt_kern_subtable_copy;
7272 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7273 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7274 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7276 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7277 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7278 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7280 /* According to the TrueType specification this is the only format
7281 * that will be properly interpreted by Windows and OS/2
7283 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7285 DWORD new_chunk, old_total = font->total_kern_pairs;
7287 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7288 glyph_to_char, NULL, 0);
7289 font->total_kern_pairs += new_chunk;
7291 if (!font->kern_pairs)
7292 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7293 font->total_kern_pairs * sizeof(*font->kern_pairs));
7294 else
7295 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7296 font->total_kern_pairs * sizeof(*font->kern_pairs));
7298 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7299 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7301 else
7302 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7304 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7307 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7308 HeapFree(GetProcessHeap(), 0, buf);
7310 if (cPairs && kern_pair)
7312 cPairs = min(cPairs, font->total_kern_pairs);
7313 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7315 else cPairs = font->total_kern_pairs;
7317 LeaveCriticalSection( &freetype_cs );
7318 return cPairs;
7321 static const struct gdi_dc_funcs freetype_funcs =
7323 NULL, /* pAbortDoc */
7324 NULL, /* pAbortPath */
7325 NULL, /* pAlphaBlend */
7326 NULL, /* pAngleArc */
7327 NULL, /* pArc */
7328 NULL, /* pArcTo */
7329 NULL, /* pBeginPath */
7330 NULL, /* pBlendImage */
7331 NULL, /* pChoosePixelFormat */
7332 NULL, /* pChord */
7333 NULL, /* pCloseFigure */
7334 NULL, /* pCopyBitmap */
7335 NULL, /* pCreateBitmap */
7336 NULL, /* pCreateCompatibleDC */
7337 freetype_CreateDC, /* pCreateDC */
7338 NULL, /* pDeleteBitmap */
7339 freetype_DeleteDC, /* pDeleteDC */
7340 NULL, /* pDeleteObject */
7341 NULL, /* pDescribePixelFormat */
7342 NULL, /* pDeviceCapabilities */
7343 NULL, /* pEllipse */
7344 NULL, /* pEndDoc */
7345 NULL, /* pEndPage */
7346 NULL, /* pEndPath */
7347 freetype_EnumFonts, /* pEnumFonts */
7348 NULL, /* pEnumICMProfiles */
7349 NULL, /* pExcludeClipRect */
7350 NULL, /* pExtDeviceMode */
7351 NULL, /* pExtEscape */
7352 NULL, /* pExtFloodFill */
7353 NULL, /* pExtSelectClipRgn */
7354 NULL, /* pExtTextOut */
7355 NULL, /* pFillPath */
7356 NULL, /* pFillRgn */
7357 NULL, /* pFlattenPath */
7358 freetype_FontIsLinked, /* pFontIsLinked */
7359 NULL, /* pFrameRgn */
7360 NULL, /* pGdiComment */
7361 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7362 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7363 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7364 freetype_GetCharWidth, /* pGetCharWidth */
7365 NULL, /* pGetDeviceCaps */
7366 NULL, /* pGetDeviceGammaRamp */
7367 freetype_GetFontData, /* pGetFontData */
7368 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7369 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7370 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7371 NULL, /* pGetICMProfile */
7372 NULL, /* pGetImage */
7373 freetype_GetKerningPairs, /* pGetKerningPairs */
7374 NULL, /* pGetNearestColor */
7375 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7376 NULL, /* pGetPixel */
7377 NULL, /* pGetPixelFormat */
7378 NULL, /* pGetSystemPaletteEntries */
7379 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7380 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7381 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7382 freetype_GetTextFace, /* pGetTextFace */
7383 freetype_GetTextMetrics, /* pGetTextMetrics */
7384 NULL, /* pGradientFill */
7385 NULL, /* pIntersectClipRect */
7386 NULL, /* pInvertRgn */
7387 NULL, /* pLineTo */
7388 NULL, /* pModifyWorldTransform */
7389 NULL, /* pMoveTo */
7390 NULL, /* pOffsetClipRgn */
7391 NULL, /* pOffsetViewportOrg */
7392 NULL, /* pOffsetWindowOrg */
7393 NULL, /* pPaintRgn */
7394 NULL, /* pPatBlt */
7395 NULL, /* pPie */
7396 NULL, /* pPolyBezier */
7397 NULL, /* pPolyBezierTo */
7398 NULL, /* pPolyDraw */
7399 NULL, /* pPolyPolygon */
7400 NULL, /* pPolyPolyline */
7401 NULL, /* pPolygon */
7402 NULL, /* pPolyline */
7403 NULL, /* pPolylineTo */
7404 NULL, /* pPutImage */
7405 NULL, /* pRealizeDefaultPalette */
7406 NULL, /* pRealizePalette */
7407 NULL, /* pRectangle */
7408 NULL, /* pResetDC */
7409 NULL, /* pRestoreDC */
7410 NULL, /* pRoundRect */
7411 NULL, /* pSaveDC */
7412 NULL, /* pScaleViewportExt */
7413 NULL, /* pScaleWindowExt */
7414 NULL, /* pSelectBitmap */
7415 NULL, /* pSelectBrush */
7416 NULL, /* pSelectClipPath */
7417 freetype_SelectFont, /* pSelectFont */
7418 NULL, /* pSelectPalette */
7419 NULL, /* pSelectPen */
7420 NULL, /* pSetArcDirection */
7421 NULL, /* pSetBkColor */
7422 NULL, /* pSetBkMode */
7423 NULL, /* pSetDCBrushColor */
7424 NULL, /* pSetDCPenColor */
7425 NULL, /* pSetDIBColorTable */
7426 NULL, /* pSetDIBitsToDevice */
7427 NULL, /* pSetDeviceClipping */
7428 NULL, /* pSetDeviceGammaRamp */
7429 NULL, /* pSetLayout */
7430 NULL, /* pSetMapMode */
7431 NULL, /* pSetMapperFlags */
7432 NULL, /* pSetPixel */
7433 NULL, /* pSetPixelFormat */
7434 NULL, /* pSetPolyFillMode */
7435 NULL, /* pSetROP2 */
7436 NULL, /* pSetRelAbs */
7437 NULL, /* pSetStretchBltMode */
7438 NULL, /* pSetTextAlign */
7439 NULL, /* pSetTextCharacterExtra */
7440 NULL, /* pSetTextColor */
7441 NULL, /* pSetTextJustification */
7442 NULL, /* pSetViewportExt */
7443 NULL, /* pSetViewportOrg */
7444 NULL, /* pSetWindowExt */
7445 NULL, /* pSetWindowOrg */
7446 NULL, /* pSetWorldTransform */
7447 NULL, /* pStartDoc */
7448 NULL, /* pStartPage */
7449 NULL, /* pStretchBlt */
7450 NULL, /* pStretchDIBits */
7451 NULL, /* pStrokeAndFillPath */
7452 NULL, /* pStrokePath */
7453 NULL, /* pSwapBuffers */
7454 NULL, /* pUnrealizePalette */
7455 NULL, /* pWidenPath */
7456 /* OpenGL not supported */
7459 #else /* HAVE_FREETYPE */
7461 /*************************************************************************/
7463 BOOL WineEngInit(void)
7465 return FALSE;
7467 BOOL WineEngDestroyFontInstance(HFONT hfont)
7469 return FALSE;
7472 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7474 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7475 return 1;
7478 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7480 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7481 return TRUE;
7484 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7486 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7487 return NULL;
7490 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7492 return FALSE;
7495 /*************************************************************************
7496 * GetRasterizerCaps (GDI32.@)
7498 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7500 lprs->nSize = sizeof(RASTERIZER_STATUS);
7501 lprs->wFlags = 0;
7502 lprs->nLanguageID = 0;
7503 return TRUE;
7506 #endif /* HAVE_FREETYPE */