gdi32: Restore the vertical font flag from the cache.
[wine/wine-gecko.git] / dlls / gdi32 / freetype.c
blob2a997428ff5993fe0d8c9aea693130ff62ea46f9
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 void DumpSubstList(void)
942 FontSubst *psub;
944 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
946 if(psub->from.charset != -1 || psub->to.charset != -1)
947 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
948 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
949 else
950 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
951 debugstr_w(psub->to.name));
953 return;
956 static LPWSTR strdupW(LPCWSTR p)
958 LPWSTR ret;
959 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
960 ret = HeapAlloc(GetProcessHeap(), 0, len);
961 memcpy(ret, p, len);
962 return ret;
965 static LPSTR strdupA(LPCSTR p)
967 LPSTR ret;
968 DWORD len = (strlen(p) + 1);
969 ret = HeapAlloc(GetProcessHeap(), 0, len);
970 memcpy(ret, p, len);
971 return ret;
974 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
975 INT from_charset)
977 FontSubst *element;
979 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
981 if(!strcmpiW(element->from.name, from_name) &&
982 (element->from.charset == from_charset ||
983 element->from.charset == -1))
984 return element;
987 return NULL;
990 #define ADD_FONT_SUBST_FORCE 1
992 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
994 FontSubst *from_exist, *to_exist;
996 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
998 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1000 list_remove(&from_exist->entry);
1001 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1002 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1003 HeapFree(GetProcessHeap(), 0, from_exist);
1004 from_exist = NULL;
1007 if(!from_exist)
1009 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1011 if(to_exist)
1013 HeapFree(GetProcessHeap(), 0, subst->to.name);
1014 subst->to.name = strdupW(to_exist->to.name);
1017 list_add_tail(subst_list, &subst->entry);
1019 return TRUE;
1022 HeapFree(GetProcessHeap(), 0, subst->from.name);
1023 HeapFree(GetProcessHeap(), 0, subst->to.name);
1024 HeapFree(GetProcessHeap(), 0, subst);
1025 return FALSE;
1028 static WCHAR *towstr(UINT cp, const char *str)
1030 int len;
1031 WCHAR *wstr;
1033 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1034 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1035 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1036 return wstr;
1039 static void split_subst_info(NameCs *nc, LPSTR str)
1041 CHAR *p = strrchr(str, ',');
1043 nc->charset = -1;
1044 if(p && *(p+1)) {
1045 nc->charset = strtol(p+1, NULL, 10);
1046 *p = '\0';
1048 nc->name = towstr(CP_ACP, str);
1051 static void LoadSubstList(void)
1053 FontSubst *psub;
1054 HKEY hkey;
1055 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1056 LPSTR value;
1057 LPVOID data;
1059 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1060 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1061 &hkey) == ERROR_SUCCESS) {
1063 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1064 &valuelen, &datalen, NULL, NULL);
1066 valuelen++; /* returned value doesn't include room for '\0' */
1067 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1068 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1070 dlen = datalen;
1071 vlen = valuelen;
1072 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1073 &dlen) == ERROR_SUCCESS) {
1074 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1076 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1077 split_subst_info(&psub->from, value);
1078 split_subst_info(&psub->to, data);
1080 /* Win 2000 doesn't allow mapping between different charsets
1081 or mapping of DEFAULT_CHARSET */
1082 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1083 psub->to.charset == DEFAULT_CHARSET) {
1084 HeapFree(GetProcessHeap(), 0, psub->to.name);
1085 HeapFree(GetProcessHeap(), 0, psub->from.name);
1086 HeapFree(GetProcessHeap(), 0, psub);
1087 } else {
1088 add_font_subst(&font_subst_list, psub, 0);
1090 /* reset dlen and vlen */
1091 dlen = datalen;
1092 vlen = valuelen;
1094 HeapFree(GetProcessHeap(), 0, data);
1095 HeapFree(GetProcessHeap(), 0, value);
1096 RegCloseKey(hkey);
1101 /*****************************************************************
1102 * get_name_table_entry
1104 * Supply the platform, encoding, language and name ids in req
1105 * and if the name exists the function will fill in the string
1106 * and string_len members. The string is owned by FreeType so
1107 * don't free it. Returns TRUE if the name is found else FALSE.
1109 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1111 FT_SfntName name;
1112 FT_UInt num_names, name_index;
1114 if(FT_IS_SFNT(ft_face))
1116 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1118 for(name_index = 0; name_index < num_names; name_index++)
1120 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1122 if((name.platform_id == req->platform_id) &&
1123 (name.encoding_id == req->encoding_id) &&
1124 (name.language_id == req->language_id) &&
1125 (name.name_id == req->name_id))
1127 req->string = name.string;
1128 req->string_len = name.string_len;
1129 return TRUE;
1134 req->string = NULL;
1135 req->string_len = 0;
1136 return FALSE;
1139 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1141 WCHAR *ret = NULL;
1142 FT_SfntName name;
1144 name.platform_id = TT_PLATFORM_MICROSOFT;
1145 name.encoding_id = TT_MS_ID_UNICODE_CS;
1146 name.language_id = language_id;
1147 name.name_id = name_id;
1149 if(get_name_table_entry(ft_face, &name))
1151 FT_UInt i;
1153 /* String is not nul terminated and string_len is a byte length. */
1154 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1155 for(i = 0; i < name.string_len / 2; i++)
1157 WORD *tmp = (WORD *)&name.string[i * 2];
1158 ret[i] = GET_BE_WORD(*tmp);
1160 ret[i] = 0;
1161 TRACE("Got localised name %s\n", debugstr_w(ret));
1164 return ret;
1167 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1169 DWORD type, needed;
1170 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1171 if(r != ERROR_SUCCESS) return r;
1172 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1173 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1176 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1178 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1181 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1183 DWORD needed;
1184 DWORD num_strikes, max_strike_key_len;
1186 /* If we have a File Name key then this is a real font, not just the parent
1187 key of a bunch of non-scalable strikes */
1188 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1190 DWORD italic, bold;
1191 Face *face;
1192 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1193 face->cached_enum_data = NULL;
1195 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1196 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1198 face->StyleName = strdupW(face_name);
1199 face->family = family;
1200 face->vertical = (family->FamilyName[0] == '@');
1202 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1204 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1205 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1206 face->FullName = fullName;
1208 else
1209 face->FullName = NULL;
1211 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1212 reg_load_dword(hkey_face, face_italic_value, &italic);
1213 reg_load_dword(hkey_face, face_bold_value, &bold);
1214 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1215 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1217 needed = sizeof(face->fs);
1218 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1219 memset(&face->fs_links, 0, sizeof(face->fs_links));
1221 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1223 face->scalable = TRUE;
1224 memset(&face->size, 0, sizeof(face->size));
1226 else
1228 face->scalable = FALSE;
1229 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1230 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1231 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1232 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1233 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1235 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1236 face->size.height, face->size.width, face->size.size >> 6,
1237 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1240 face->ntmFlags = 0;
1241 if (italic) face->ntmFlags |= NTM_ITALIC;
1242 if (bold) face->ntmFlags |= NTM_BOLD;
1243 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1245 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1246 face->fs.fsCsb[0], face->fs.fsCsb[1],
1247 face->fs.fsUsb[0], face->fs.fsUsb[1],
1248 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1250 if(!italic && !bold)
1251 list_add_head(&family->faces, &face->entry);
1252 else
1253 list_add_tail(&family->faces, &face->entry);
1255 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1258 /* do we have any bitmap strikes? */
1259 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1260 NULL, NULL, NULL, NULL);
1261 if(num_strikes != 0)
1263 WCHAR strike_name[10];
1264 DWORD strike_index = 0;
1266 needed = sizeof(strike_name) / sizeof(WCHAR);
1267 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1268 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1270 HKEY hkey_strike;
1271 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1272 load_face(hkey_strike, face_name, family);
1273 RegCloseKey(hkey_strike);
1274 needed = sizeof(strike_name) / sizeof(WCHAR);
1279 static void load_font_list_from_cache(HKEY hkey_font_cache)
1281 DWORD max_family_key_len, size;
1282 WCHAR *family_name;
1283 DWORD family_index = 0;
1284 Family *family;
1285 HKEY hkey_family;
1287 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1288 NULL, NULL, NULL, NULL);
1289 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1291 size = max_family_key_len + 1;
1292 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1293 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1295 WCHAR *english_family = NULL;
1296 DWORD face_index = 0;
1297 WCHAR *face_name;
1298 DWORD max_face_key_len;
1300 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1301 TRACE("opened family key %s\n", debugstr_w(family_name));
1302 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1304 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1305 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1308 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1309 family->FamilyName = strdupW(family_name);
1310 family->EnglishName = english_family;
1311 list_init(&family->faces);
1312 list_add_tail(&font_list, &family->entry);
1314 if(english_family)
1316 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1317 subst->from.name = strdupW(english_family);
1318 subst->from.charset = -1;
1319 subst->to.name = strdupW(family_name);
1320 subst->to.charset = -1;
1321 add_font_subst(&font_subst_list, subst, 0);
1324 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1325 NULL, NULL, NULL, NULL);
1327 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1328 size = max_face_key_len + 1;
1329 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1330 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1332 HKEY hkey_face;
1334 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1335 load_face(hkey_face, face_name, family);
1336 RegCloseKey(hkey_face);
1337 size = max_face_key_len + 1;
1339 HeapFree(GetProcessHeap(), 0, face_name);
1340 RegCloseKey(hkey_family);
1341 size = max_family_key_len + 1;
1344 HeapFree(GetProcessHeap(), 0, family_name);
1347 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1349 LONG ret;
1350 HKEY hkey_wine_fonts;
1352 /* We don't want to create the fonts key as volatile, so open this first */
1353 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1354 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1355 if(ret != ERROR_SUCCESS)
1357 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1358 return ret;
1361 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1362 KEY_ALL_ACCESS, NULL, hkey, disposition);
1363 RegCloseKey(hkey_wine_fonts);
1364 return ret;
1367 static void add_face_to_cache(Face *face)
1369 HKEY hkey_font_cache, hkey_family, hkey_face;
1370 WCHAR *face_key_name;
1372 create_font_cache_key(&hkey_font_cache, NULL);
1374 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1375 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1376 if(face->family->EnglishName)
1377 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1378 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1380 if(face->scalable)
1381 face_key_name = face->StyleName;
1382 else
1384 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1385 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1386 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1388 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1389 &hkey_face, NULL);
1390 if(!face->scalable)
1391 HeapFree(GetProcessHeap(), 0, face_key_name);
1393 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1394 if (face->FullName)
1395 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1396 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1398 reg_save_dword(hkey_face, face_index_value, face->face_index);
1399 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1400 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1401 reg_save_dword(hkey_face, face_version_value, face->font_version);
1402 reg_save_dword(hkey_face, face_external_value, face->external);
1404 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1406 if(!face->scalable)
1408 reg_save_dword(hkey_face, face_height_value, face->size.height);
1409 reg_save_dword(hkey_face, face_width_value, face->size.width);
1410 reg_save_dword(hkey_face, face_size_value, face->size.size);
1411 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1412 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1413 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1415 RegCloseKey(hkey_face);
1416 RegCloseKey(hkey_family);
1417 RegCloseKey(hkey_font_cache);
1420 static inline int TestStyles(DWORD flags, DWORD styles)
1422 return (flags & styles) == styles;
1425 static int StyleOrdering(Face *face)
1427 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1428 return 3;
1429 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1430 return 2;
1431 if (TestStyles(face->ntmFlags, NTM_BOLD))
1432 return 1;
1433 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1434 return 0;
1436 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1437 debugstr_w(face->family->FamilyName),
1438 debugstr_w(face->StyleName),
1439 face->ntmFlags);
1441 return 9999;
1444 /* Add a style of face to a font family using an ordering of the list such
1445 that regular fonts come before bold and italic, and single styles come
1446 before compound styles. */
1447 static void AddFaceToFamily(Face *face, Family *family)
1449 struct list *entry;
1451 LIST_FOR_EACH( entry, &family->faces )
1453 Face *ent = LIST_ENTRY(entry, Face, entry);
1454 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1456 list_add_before( entry, &face->entry );
1459 static WCHAR *prepend_at(WCHAR *family)
1461 WCHAR *str;
1463 if (!family)
1464 return NULL;
1466 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1467 str[0] = '@';
1468 strcpyW(str + 1, family);
1469 HeapFree(GetProcessHeap(), 0, family);
1470 return str;
1473 #define ADDFONT_EXTERNAL_FONT 0x01
1474 #define ADDFONT_FORCE_BITMAP 0x02
1475 #define ADDFONT_ADD_TO_CACHE 0x04
1477 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)
1479 int bitmap_num = 0;
1480 Family *family;
1481 WCHAR *StyleW;
1483 do {
1484 TT_OS2 *pOS2;
1485 TT_Header *pHeader;
1486 WCHAR *english_family, *localised_family;
1487 Face *face;
1488 struct list *face_elem_ptr;
1489 FT_WinFNT_HeaderRec winfnt_header;
1490 int internal_leading;
1491 FONTSIGNATURE fs;
1492 My_FT_Bitmap_Size *size = NULL;
1493 FT_ULong tmp_size;
1495 if(!FT_IS_SCALABLE(ft_face))
1496 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1498 if (fake_family)
1500 english_family = towstr(CP_ACP, fake_family);
1501 localised_family = NULL;
1503 else
1505 english_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1506 if (!english_family)
1507 english_family = towstr(CP_ACP, ft_face->family_name);
1509 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1510 if (localised_family && !strcmpiW(localised_family, english_family))
1512 HeapFree(GetProcessHeap(), 0, localised_family);
1513 localised_family = NULL;
1517 if (vertical)
1519 english_family = prepend_at(english_family);
1520 localised_family = prepend_at(localised_family);
1523 family = find_family_from_name(localised_family ? localised_family : english_family);
1524 if(!family) {
1525 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1526 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1527 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1528 list_init(&family->faces);
1529 list_add_tail(&font_list, &family->entry);
1531 if(localised_family) {
1532 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1533 subst->from.name = strdupW(english_family);
1534 subst->from.charset = -1;
1535 subst->to.name = strdupW(localised_family);
1536 subst->to.charset = -1;
1537 add_font_subst(&font_subst_list, subst, 0);
1540 HeapFree(GetProcessHeap(), 0, localised_family);
1541 HeapFree(GetProcessHeap(), 0, english_family);
1543 StyleW = towstr(CP_ACP, ft_face->style_name);
1545 internal_leading = 0;
1546 memset(&fs, 0, sizeof(fs));
1548 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1549 if(pOS2) {
1550 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1551 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1552 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1553 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1554 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1555 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1556 if(pOS2->version == 0) {
1557 FT_UInt dummy;
1559 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1560 fs.fsCsb[0] |= FS_LATIN1;
1561 else
1562 fs.fsCsb[0] |= FS_SYMBOL;
1565 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1566 CHARSETINFO csi;
1567 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1568 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1569 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1570 fs = csi.fs;
1571 internal_leading = winfnt_header.internal_leading;
1574 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1575 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1576 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1577 if(!strcmpiW(face->StyleName, StyleW) &&
1578 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1579 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1580 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1581 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1583 if(fake_family) {
1584 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1585 HeapFree(GetProcessHeap(), 0, StyleW);
1586 return;
1588 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1589 TRACE("Original font is newer so skipping this one\n");
1590 HeapFree(GetProcessHeap(), 0, StyleW);
1591 return;
1592 } else {
1593 TRACE("Replacing original with this one\n");
1594 list_remove(&face->entry);
1595 HeapFree(GetProcessHeap(), 0, face->file);
1596 HeapFree(GetProcessHeap(), 0, face->StyleName);
1597 HeapFree(GetProcessHeap(), 0, face->FullName);
1598 HeapFree(GetProcessHeap(), 0, face);
1599 break;
1603 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1604 face->cached_enum_data = NULL;
1605 face->StyleName = StyleW;
1606 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1607 if (file)
1609 face->file = strdupA(file);
1610 face->font_data_ptr = NULL;
1611 face->font_data_size = 0;
1613 else
1615 face->file = NULL;
1616 face->font_data_ptr = font_data_ptr;
1617 face->font_data_size = font_data_size;
1619 face->face_index = face_index;
1620 face->ntmFlags = 0;
1621 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1622 face->ntmFlags |= NTM_ITALIC;
1623 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1624 face->ntmFlags |= NTM_BOLD;
1625 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1626 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1627 face->family = family;
1628 face->vertical = vertical;
1629 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1630 face->fs = fs;
1631 memset(&face->fs_links, 0, sizeof(face->fs_links));
1633 if(FT_IS_SCALABLE(ft_face)) {
1634 memset(&face->size, 0, sizeof(face->size));
1635 face->scalable = TRUE;
1636 } else {
1637 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1638 size->height, size->width, size->size >> 6,
1639 size->x_ppem >> 6, size->y_ppem >> 6);
1640 face->size.height = size->height;
1641 face->size.width = size->width;
1642 face->size.size = size->size;
1643 face->size.x_ppem = size->x_ppem;
1644 face->size.y_ppem = size->y_ppem;
1645 face->size.internal_leading = internal_leading;
1646 face->scalable = FALSE;
1649 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1650 tmp_size = 0;
1651 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1653 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1654 face->ntmFlags |= NTM_PS_OPENTYPE;
1657 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1658 face->fs.fsCsb[0], face->fs.fsCsb[1],
1659 face->fs.fsUsb[0], face->fs.fsUsb[1],
1660 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1662 if(face->fs.fsCsb[0] == 0)
1664 int i;
1666 /* let's see if we can find any interesting cmaps */
1667 for(i = 0; i < ft_face->num_charmaps; i++) {
1668 switch(ft_face->charmaps[i]->encoding) {
1669 case FT_ENCODING_UNICODE:
1670 case FT_ENCODING_APPLE_ROMAN:
1671 face->fs.fsCsb[0] |= FS_LATIN1;
1672 break;
1673 case FT_ENCODING_MS_SYMBOL:
1674 face->fs.fsCsb[0] |= FS_SYMBOL;
1675 break;
1676 default:
1677 break;
1682 if(flags & ADDFONT_ADD_TO_CACHE)
1683 add_face_to_cache(face);
1685 AddFaceToFamily(face, family);
1687 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1689 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1690 debugstr_w(StyleW));
1693 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1695 FT_Face ft_face;
1696 TT_OS2 *pOS2;
1697 TT_Header *pHeader = NULL;
1698 WCHAR *localised_family;
1699 FT_Error err;
1700 FT_Long face_index = 0, num_faces;
1701 INT ret = 0;
1703 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1704 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1706 #ifdef HAVE_CARBON_CARBON_H
1707 if(file && !fake_family)
1709 char **mac_list = expand_mac_font(file);
1710 if(mac_list)
1712 BOOL had_one = FALSE;
1713 char **cursor;
1714 for(cursor = mac_list; *cursor; cursor++)
1716 had_one = TRUE;
1717 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1718 HeapFree(GetProcessHeap(), 0, *cursor);
1720 HeapFree(GetProcessHeap(), 0, mac_list);
1721 if(had_one)
1722 return 1;
1725 #endif /* HAVE_CARBON_CARBON_H */
1727 do {
1728 if (file)
1730 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1731 err = pFT_New_Face(library, file, face_index, &ft_face);
1732 } else
1734 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1735 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1738 if(err != 0) {
1739 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1740 return 0;
1743 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*/
1744 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1745 pFT_Done_Face(ft_face);
1746 return 0;
1749 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1750 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1751 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1752 pFT_Done_Face(ft_face);
1753 return 0;
1756 if(FT_IS_SFNT(ft_face))
1758 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1759 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1760 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1762 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1763 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1764 pFT_Done_Face(ft_face);
1765 return 0;
1768 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1769 we don't want to load these. */
1770 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1772 FT_ULong len = 0;
1774 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1776 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1777 pFT_Done_Face(ft_face);
1778 return 0;
1783 if(!ft_face->family_name || !ft_face->style_name) {
1784 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1785 pFT_Done_Face(ft_face);
1786 return 0;
1789 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1791 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1792 pFT_Done_Face(ft_face);
1793 return 0;
1796 if (target_family)
1798 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1799 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1801 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1802 HeapFree(GetProcessHeap(), 0, localised_family);
1803 num_faces = ft_face->num_faces;
1804 pFT_Done_Face(ft_face);
1805 continue;
1807 HeapFree(GetProcessHeap(), 0, localised_family);
1810 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1811 ++ret;
1813 if (FT_HAS_VERTICAL(ft_face))
1815 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1816 ++ret;
1819 num_faces = ft_face->num_faces;
1820 pFT_Done_Face(ft_face);
1821 } while(num_faces > ++face_index);
1822 return ret;
1825 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1827 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1830 static void DumpFontList(void)
1832 Family *family;
1833 Face *face;
1834 struct list *family_elem_ptr, *face_elem_ptr;
1836 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1837 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1838 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1839 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1840 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1841 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1842 if(!face->scalable)
1843 TRACE(" %d", face->size.height);
1844 TRACE("\n");
1847 return;
1850 /***********************************************************
1851 * The replacement list is a way to map an entire font
1852 * family onto another family. For example adding
1854 * [HKCU\Software\Wine\Fonts\Replacements]
1855 * "Wingdings"="Winedings"
1857 * would enumerate the Winedings font both as Winedings and
1858 * Wingdings. However if a real Wingdings font is present the
1859 * replacement does not take place.
1862 static void LoadReplaceList(void)
1864 HKEY hkey;
1865 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1866 LPWSTR value;
1867 LPVOID data;
1868 Family *family;
1869 Face *face;
1870 struct list *family_elem_ptr, *face_elem_ptr;
1871 CHAR familyA[400];
1873 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1874 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1876 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1877 &valuelen, &datalen, NULL, NULL);
1879 valuelen++; /* returned value doesn't include room for '\0' */
1880 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1881 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1883 dlen = datalen;
1884 vlen = valuelen;
1885 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1886 &dlen) == ERROR_SUCCESS) {
1887 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1888 /* "NewName"="Oldname" */
1889 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1891 if(!find_family_from_name(value))
1893 /* Find the old family and hence all of the font files
1894 in that family */
1895 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1896 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1897 if(!strcmpiW(family->FamilyName, data)) {
1898 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1899 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1900 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1901 debugstr_w(face->StyleName), familyA);
1902 /* Now add a new entry with the new family name */
1903 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1904 familyA, family->FamilyName,
1905 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1907 break;
1911 /* reset dlen and vlen */
1912 dlen = datalen;
1913 vlen = valuelen;
1915 HeapFree(GetProcessHeap(), 0, data);
1916 HeapFree(GetProcessHeap(), 0, value);
1917 RegCloseKey(hkey);
1921 /*************************************************************
1922 * init_system_links
1924 static BOOL init_system_links(void)
1926 HKEY hkey;
1927 BOOL ret = FALSE;
1928 DWORD type, max_val, max_data, val_len, data_len, index;
1929 WCHAR *value, *data;
1930 WCHAR *entry, *next;
1931 SYSTEM_LINKS *font_link, *system_font_link;
1932 CHILD_FONT *child_font;
1933 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1934 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1935 FONTSIGNATURE fs;
1936 Family *family;
1937 Face *face;
1938 FontSubst *psub;
1940 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1942 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1943 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1944 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1945 val_len = max_val + 1;
1946 data_len = max_data;
1947 index = 0;
1948 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1950 memset(&fs, 0, sizeof(fs));
1951 psub = get_font_subst(&font_subst_list, value, -1);
1952 /* Don't store fonts that are only substitutes for other fonts */
1953 if(psub)
1955 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1956 goto next;
1958 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1959 font_link->font_name = strdupW(value);
1960 list_init(&font_link->links);
1961 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1963 WCHAR *face_name;
1964 CHILD_FONT *child_font;
1966 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1968 next = entry + strlenW(entry) + 1;
1970 face_name = strchrW(entry, ',');
1971 if(face_name)
1973 *face_name++ = 0;
1974 while(isspaceW(*face_name))
1975 face_name++;
1977 psub = get_font_subst(&font_subst_list, face_name, -1);
1978 if(psub)
1979 face_name = psub->to.name;
1981 face = find_face_from_filename(entry, face_name);
1982 if(!face)
1984 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1985 continue;
1988 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1989 child_font->face = face;
1990 child_font->font = NULL;
1991 fs.fsCsb[0] |= face->fs.fsCsb[0];
1992 fs.fsCsb[1] |= face->fs.fsCsb[1];
1993 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1994 list_add_tail(&font_link->links, &child_font->entry);
1996 family = find_family_from_name(font_link->font_name);
1997 if(family)
1999 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2001 face->fs_links = fs;
2004 list_add_tail(&system_links, &font_link->entry);
2005 next:
2006 val_len = max_val + 1;
2007 data_len = max_data;
2010 HeapFree(GetProcessHeap(), 0, value);
2011 HeapFree(GetProcessHeap(), 0, data);
2012 RegCloseKey(hkey);
2015 if(RegOpenKeyW(HKEY_CURRENT_USER, internal_system_link, &hkey) == ERROR_SUCCESS)
2017 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2018 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2019 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2020 val_len = max_val + 1;
2021 data_len = max_data;
2022 index = 0;
2023 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2025 BOOL existing = FALSE;
2026 memset(&fs, 0, sizeof(fs));
2027 psub = get_font_subst(&font_subst_list, value, -1);
2028 /* Don't store fonts that are only substitutes for other fonts */
2029 if(psub)
2031 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2032 goto next_internal;
2035 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2037 if(!strcmpiW(font_link->font_name, value))
2039 existing = TRUE;
2040 break;
2044 if (!existing)
2046 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2047 font_link->font_name = strdupW(value);
2048 list_init(&font_link->links);
2051 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2053 WCHAR *face_name;
2054 CHILD_FONT *child_font;
2056 TRACE("Internal entry %s: %s\n", debugstr_w(value), debugstr_w(entry));
2058 next = entry + strlenW(entry) + 1;
2060 face_name = strchrW(entry, ',');
2061 if(face_name)
2063 *face_name++ = 0;
2064 while(isspaceW(*face_name))
2065 face_name++;
2067 psub = get_font_subst(&font_subst_list, face_name, -1);
2068 if(psub)
2069 face_name = psub->to.name;
2071 face = find_face_from_filename(entry, face_name);
2072 if(!face)
2074 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2075 continue;
2078 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2079 child_font->face = face;
2080 child_font->font = NULL;
2081 fs.fsCsb[0] |= face->fs.fsCsb[0];
2082 fs.fsCsb[1] |= face->fs.fsCsb[1];
2083 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2084 list_add_tail(&font_link->links, &child_font->entry);
2086 family = find_family_from_name(font_link->font_name);
2087 if(family)
2089 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2091 face->fs_links = fs;
2094 if (!existing)
2095 list_add_tail(&system_links, &font_link->entry);
2096 next_internal:
2097 val_len = max_val + 1;
2098 data_len = max_data;
2101 HeapFree(GetProcessHeap(), 0, value);
2102 HeapFree(GetProcessHeap(), 0, data);
2103 RegCloseKey(hkey);
2106 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2107 that Tahoma has */
2109 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2110 system_font_link->font_name = strdupW(System);
2111 list_init(&system_font_link->links);
2113 face = find_face_from_filename(tahoma_ttf, Tahoma);
2114 if(face)
2116 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2117 child_font->face = face;
2118 child_font->font = NULL;
2119 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2120 list_add_tail(&system_font_link->links, &child_font->entry);
2122 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2124 if(!strcmpiW(font_link->font_name, Tahoma))
2126 CHILD_FONT *font_link_entry;
2127 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2129 CHILD_FONT *new_child;
2130 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2131 new_child->face = font_link_entry->face;
2132 new_child->font = NULL;
2133 list_add_tail(&system_font_link->links, &new_child->entry);
2135 break;
2138 list_add_tail(&system_links, &system_font_link->entry);
2139 return ret;
2142 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2144 DIR *dir;
2145 struct dirent *dent;
2146 char path[MAX_PATH];
2148 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2150 dir = opendir(dirname);
2151 if(!dir) {
2152 WARN("Can't open directory %s\n", debugstr_a(dirname));
2153 return FALSE;
2155 while((dent = readdir(dir)) != NULL) {
2156 struct stat statbuf;
2158 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2159 continue;
2161 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2163 sprintf(path, "%s/%s", dirname, dent->d_name);
2165 if(stat(path, &statbuf) == -1)
2167 WARN("Can't stat %s\n", debugstr_a(path));
2168 continue;
2170 if(S_ISDIR(statbuf.st_mode))
2171 ReadFontDir(path, external_fonts);
2172 else
2174 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2175 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2176 AddFontFileToList(path, NULL, NULL, addfont_flags);
2179 closedir(dir);
2180 return TRUE;
2183 static void load_fontconfig_fonts(void)
2185 #ifdef SONAME_LIBFONTCONFIG
2186 void *fc_handle = NULL;
2187 FcConfig *config;
2188 FcPattern *pat;
2189 FcObjectSet *os;
2190 FcFontSet *fontset;
2191 int i, len;
2192 char *file;
2193 const char *ext;
2195 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2196 if(!fc_handle) {
2197 TRACE("Wine cannot find the fontconfig library (%s).\n",
2198 SONAME_LIBFONTCONFIG);
2199 return;
2201 #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;}
2202 LOAD_FUNCPTR(FcConfigGetCurrent);
2203 LOAD_FUNCPTR(FcFontList);
2204 LOAD_FUNCPTR(FcFontSetDestroy);
2205 LOAD_FUNCPTR(FcInit);
2206 LOAD_FUNCPTR(FcObjectSetAdd);
2207 LOAD_FUNCPTR(FcObjectSetCreate);
2208 LOAD_FUNCPTR(FcObjectSetDestroy);
2209 LOAD_FUNCPTR(FcPatternCreate);
2210 LOAD_FUNCPTR(FcPatternDestroy);
2211 LOAD_FUNCPTR(FcPatternGetBool);
2212 LOAD_FUNCPTR(FcPatternGetString);
2213 #undef LOAD_FUNCPTR
2215 if(!pFcInit()) return;
2217 config = pFcConfigGetCurrent();
2218 pat = pFcPatternCreate();
2219 os = pFcObjectSetCreate();
2220 pFcObjectSetAdd(os, FC_FILE);
2221 pFcObjectSetAdd(os, FC_SCALABLE);
2222 fontset = pFcFontList(config, pat, os);
2223 if(!fontset) return;
2224 for(i = 0; i < fontset->nfont; i++) {
2225 FcBool scalable;
2227 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2228 continue;
2229 TRACE("fontconfig: %s\n", file);
2231 /* We're just interested in OT/TT fonts for now, so this hack just
2232 picks up the scalable fonts without extensions .pf[ab] to save time
2233 loading every other font */
2235 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2237 TRACE("not scalable\n");
2238 continue;
2241 len = strlen( file );
2242 if(len < 4) continue;
2243 ext = &file[ len - 3 ];
2244 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2245 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2247 pFcFontSetDestroy(fontset);
2248 pFcObjectSetDestroy(os);
2249 pFcPatternDestroy(pat);
2250 sym_not_found:
2251 #endif
2252 return;
2255 static BOOL load_font_from_data_dir(LPCWSTR file)
2257 BOOL ret = FALSE;
2258 const char *data_dir = wine_get_data_dir();
2260 if (!data_dir) data_dir = wine_get_build_dir();
2262 if (data_dir)
2264 INT len;
2265 char *unix_name;
2267 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2269 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2271 strcpy(unix_name, data_dir);
2272 strcat(unix_name, "/fonts/");
2274 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2276 EnterCriticalSection( &freetype_cs );
2277 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2278 LeaveCriticalSection( &freetype_cs );
2279 HeapFree(GetProcessHeap(), 0, unix_name);
2281 return ret;
2284 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2286 static const WCHAR slashW[] = {'\\','\0'};
2287 BOOL ret = FALSE;
2288 WCHAR windowsdir[MAX_PATH];
2289 char *unixname;
2291 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2292 strcatW(windowsdir, fontsW);
2293 strcatW(windowsdir, slashW);
2294 strcatW(windowsdir, file);
2295 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2296 EnterCriticalSection( &freetype_cs );
2297 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2298 LeaveCriticalSection( &freetype_cs );
2299 HeapFree(GetProcessHeap(), 0, unixname);
2301 return ret;
2304 static void load_system_fonts(void)
2306 HKEY hkey;
2307 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2308 const WCHAR * const *value;
2309 DWORD dlen, type;
2310 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2311 char *unixname;
2313 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2314 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2315 strcatW(windowsdir, fontsW);
2316 for(value = SystemFontValues; *value; value++) {
2317 dlen = sizeof(data);
2318 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2319 type == REG_SZ) {
2320 BOOL added = FALSE;
2322 sprintfW(pathW, fmtW, windowsdir, data);
2323 if((unixname = wine_get_unix_file_name(pathW))) {
2324 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2325 HeapFree(GetProcessHeap(), 0, unixname);
2327 if (!added)
2328 load_font_from_data_dir(data);
2331 RegCloseKey(hkey);
2335 /*************************************************************
2337 * This adds registry entries for any externally loaded fonts
2338 * (fonts from fontconfig or FontDirs). It also deletes entries
2339 * of no longer existing fonts.
2342 static void update_reg_entries(void)
2344 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2345 LPWSTR valueW;
2346 DWORD len, len_fam;
2347 Family *family;
2348 Face *face;
2349 struct list *family_elem_ptr, *face_elem_ptr;
2350 WCHAR *file;
2351 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2352 static const WCHAR spaceW[] = {' ', '\0'};
2353 char *path;
2355 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2356 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2357 ERR("Can't create Windows font reg key\n");
2358 goto end;
2361 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2362 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2363 ERR("Can't create Windows font reg key\n");
2364 goto end;
2367 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2368 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2369 ERR("Can't create external font reg key\n");
2370 goto end;
2373 /* enumerate the fonts and add external ones to the two keys */
2375 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2376 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2377 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2378 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2379 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2380 if(!face->external) continue;
2381 len = len_fam;
2382 if (!(face->ntmFlags & NTM_REGULAR))
2383 len = len_fam + strlenW(face->StyleName) + 1;
2384 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2385 strcpyW(valueW, family->FamilyName);
2386 if(len != len_fam) {
2387 strcatW(valueW, spaceW);
2388 strcatW(valueW, face->StyleName);
2390 strcatW(valueW, TrueType);
2392 file = wine_get_dos_file_name(face->file);
2393 if(file)
2394 len = strlenW(file) + 1;
2395 else
2397 if((path = strrchr(face->file, '/')) == NULL)
2398 path = face->file;
2399 else
2400 path++;
2401 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2403 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2404 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2406 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2407 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2408 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2410 HeapFree(GetProcessHeap(), 0, file);
2411 HeapFree(GetProcessHeap(), 0, valueW);
2414 end:
2415 if(external_key) RegCloseKey(external_key);
2416 if(win9x_key) RegCloseKey(win9x_key);
2417 if(winnt_key) RegCloseKey(winnt_key);
2418 return;
2421 static void delete_external_font_keys(void)
2423 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2424 DWORD dlen, vlen, datalen, valuelen, i, type;
2425 LPWSTR valueW;
2426 LPVOID data;
2428 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2429 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2430 ERR("Can't create Windows font reg key\n");
2431 goto end;
2434 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2435 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2436 ERR("Can't create Windows font reg key\n");
2437 goto end;
2440 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2441 ERR("Can't create external font reg key\n");
2442 goto end;
2445 /* Delete all external fonts added last time */
2447 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2448 &valuelen, &datalen, NULL, NULL);
2449 valuelen++; /* returned value doesn't include room for '\0' */
2450 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2451 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2453 dlen = datalen * sizeof(WCHAR);
2454 vlen = valuelen;
2455 i = 0;
2456 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2457 &dlen) == ERROR_SUCCESS) {
2459 RegDeleteValueW(winnt_key, valueW);
2460 RegDeleteValueW(win9x_key, valueW);
2461 /* reset dlen and vlen */
2462 dlen = datalen;
2463 vlen = valuelen;
2465 HeapFree(GetProcessHeap(), 0, data);
2466 HeapFree(GetProcessHeap(), 0, valueW);
2468 /* Delete the old external fonts key */
2469 RegCloseKey(external_key);
2470 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2472 end:
2473 if(win9x_key) RegCloseKey(win9x_key);
2474 if(winnt_key) RegCloseKey(winnt_key);
2477 /*************************************************************
2478 * WineEngAddFontResourceEx
2481 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2483 INT ret = 0;
2485 GDI_CheckNotLock();
2487 if (ft_handle) /* do it only if we have freetype up and running */
2489 char *unixname;
2491 if(flags)
2492 FIXME("Ignoring flags %x\n", flags);
2494 if((unixname = wine_get_unix_file_name(file)))
2496 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2498 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2499 EnterCriticalSection( &freetype_cs );
2500 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2501 LeaveCriticalSection( &freetype_cs );
2502 HeapFree(GetProcessHeap(), 0, unixname);
2504 if (!ret && !strchrW(file, '\\')) {
2505 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2506 ret = load_font_from_winfonts_dir(file);
2507 if (!ret) {
2508 /* Try in datadir/fonts (or builddir/fonts),
2509 * needed for Magic the Gathering Online
2511 ret = load_font_from_data_dir(file);
2515 return ret;
2518 /*************************************************************
2519 * WineEngAddFontMemResourceEx
2522 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2524 GDI_CheckNotLock();
2526 if (ft_handle) /* do it only if we have freetype up and running */
2528 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2530 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2531 memcpy(pFontCopy, pbFont, cbFont);
2533 EnterCriticalSection( &freetype_cs );
2534 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2535 LeaveCriticalSection( &freetype_cs );
2537 if (*pcFonts == 0)
2539 TRACE("AddFontToList failed\n");
2540 HeapFree(GetProcessHeap(), 0, pFontCopy);
2541 return 0;
2543 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2544 * For now return something unique but quite random
2546 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2547 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2550 *pcFonts = 0;
2551 return 0;
2554 /*************************************************************
2555 * WineEngRemoveFontResourceEx
2558 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2560 GDI_CheckNotLock();
2561 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2562 return TRUE;
2565 static const struct nls_update_font_list
2567 UINT ansi_cp, oem_cp;
2568 const char *oem, *fixed, *system;
2569 const char *courier, *serif, *small, *sserif;
2570 /* these are for font substitutes */
2571 const char *shelldlg, *tmsrmn;
2572 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2573 *helv_0, *tmsrmn_0;
2574 const struct subst
2576 const char *from, *to;
2577 } arial_0, courier_new_0, times_new_roman_0;
2578 } nls_update_font_list[] =
2580 /* Latin 1 (United States) */
2581 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2582 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2583 "Tahoma","Times New Roman",
2584 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2585 { 0 }, { 0 }, { 0 }
2587 /* Latin 1 (Multilingual) */
2588 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2589 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2590 "Tahoma","Times New Roman", /* FIXME unverified */
2591 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2592 { 0 }, { 0 }, { 0 }
2594 /* Eastern Europe */
2595 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2596 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2597 "Tahoma","Times New Roman", /* FIXME unverified */
2598 "Fixedsys,238", "System,238",
2599 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2600 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2601 { "Arial CE,0", "Arial,238" },
2602 { "Courier New CE,0", "Courier New,238" },
2603 { "Times New Roman CE,0", "Times New Roman,238" }
2605 /* Cyrillic */
2606 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2607 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2608 "Tahoma","Times New Roman", /* FIXME unverified */
2609 "Fixedsys,204", "System,204",
2610 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2611 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2612 { "Arial Cyr,0", "Arial,204" },
2613 { "Courier New Cyr,0", "Courier New,204" },
2614 { "Times New Roman Cyr,0", "Times New Roman,204" }
2616 /* Greek */
2617 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2618 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2619 "Tahoma","Times New Roman", /* FIXME unverified */
2620 "Fixedsys,161", "System,161",
2621 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2622 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2623 { "Arial Greek,0", "Arial,161" },
2624 { "Courier New Greek,0", "Courier New,161" },
2625 { "Times New Roman Greek,0", "Times New Roman,161" }
2627 /* Turkish */
2628 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2629 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2630 "Tahoma","Times New Roman", /* FIXME unverified */
2631 "Fixedsys,162", "System,162",
2632 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2633 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2634 { "Arial Tur,0", "Arial,162" },
2635 { "Courier New Tur,0", "Courier New,162" },
2636 { "Times New Roman Tur,0", "Times New Roman,162" }
2638 /* Hebrew */
2639 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2640 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2641 "Tahoma","Times New Roman", /* FIXME unverified */
2642 "Fixedsys,177", "System,177",
2643 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2644 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2645 { 0 }, { 0 }, { 0 }
2647 /* Arabic */
2648 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2649 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2650 "Tahoma","Times New Roman", /* FIXME unverified */
2651 "Fixedsys,178", "System,178",
2652 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2653 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2654 { 0 }, { 0 }, { 0 }
2656 /* Baltic */
2657 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2658 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2659 "Tahoma","Times New Roman", /* FIXME unverified */
2660 "Fixedsys,186", "System,186",
2661 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2662 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2663 { "Arial Baltic,0", "Arial,186" },
2664 { "Courier New Baltic,0", "Courier New,186" },
2665 { "Times New Roman Baltic,0", "Times New Roman,186" }
2667 /* Vietnamese */
2668 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2669 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2670 "Tahoma","Times New Roman", /* FIXME unverified */
2671 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2672 { 0 }, { 0 }, { 0 }
2674 /* Thai */
2675 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2676 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2677 "Tahoma","Times New Roman", /* FIXME unverified */
2678 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2679 { 0 }, { 0 }, { 0 }
2681 /* Japanese */
2682 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2683 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2684 "MS UI Gothic","MS Serif",
2685 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2686 { 0 }, { 0 }, { 0 }
2688 /* Chinese Simplified */
2689 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2690 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2691 "SimSun", "NSimSun",
2692 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2693 { 0 }, { 0 }, { 0 }
2695 /* Korean */
2696 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2697 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2698 "Gulim", "Batang",
2699 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2700 { 0 }, { 0 }, { 0 }
2702 /* Chinese Traditional */
2703 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2704 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2705 "PMingLiU", "MingLiU",
2706 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2707 { 0 }, { 0 }, { 0 }
2711 static const WCHAR *font_links_list[] =
2713 Lucida_Sans_Unicode,
2714 Microsoft_Sans_Serif,
2715 Tahoma
2718 static const struct font_links_defaults_list
2720 /* Keyed off substitution for "MS Shell Dlg" */
2721 const WCHAR *shelldlg;
2722 /* Maximum of four substitutes, plus terminating NULL pointer */
2723 const WCHAR *substitutes[5];
2724 } font_links_defaults_list[] =
2726 /* Non East-Asian */
2727 { Tahoma, /* FIXME unverified ordering */
2728 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2730 /* Below lists are courtesy of
2731 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2733 /* Japanese */
2734 { MS_UI_Gothic,
2735 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2737 /* Chinese Simplified */
2738 { SimSun,
2739 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2741 /* Korean */
2742 { Gulim,
2743 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2745 /* Chinese Traditional */
2746 { PMingLiU,
2747 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2751 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2753 return ( ansi_cp == 932 /* CP932 for Japanese */
2754 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2755 || ansi_cp == 949 /* CP949 for Korean */
2756 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2759 static inline HKEY create_fonts_NT_registry_key(void)
2761 HKEY hkey = 0;
2763 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2764 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2765 return hkey;
2768 static inline HKEY create_fonts_9x_registry_key(void)
2770 HKEY hkey = 0;
2772 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2773 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2774 return hkey;
2777 static inline HKEY create_config_fonts_registry_key(void)
2779 HKEY hkey = 0;
2781 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2782 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2783 return hkey;
2786 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2788 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2789 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2790 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2791 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2794 static void set_value_key(HKEY hkey, const char *name, const char *value)
2796 if (value)
2797 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2798 else if (name)
2799 RegDeleteValueA(hkey, name);
2802 static void update_font_info(void)
2804 char buf[40], cpbuf[40];
2805 DWORD len, type;
2806 HKEY hkey = 0;
2807 UINT i, ansi_cp = 0, oem_cp = 0;
2808 BOOL done = FALSE;
2810 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2811 return;
2813 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2814 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2815 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2816 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2817 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2819 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2820 if (is_dbcs_ansi_cp(ansi_cp))
2821 use_default_fallback = TRUE;
2823 len = sizeof(buf);
2824 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2826 if (!strcmp( buf, cpbuf )) /* already set correctly */
2828 RegCloseKey(hkey);
2829 return;
2831 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2833 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2835 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2836 RegCloseKey(hkey);
2838 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2840 HKEY hkey;
2842 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2843 nls_update_font_list[i].oem_cp == oem_cp)
2845 hkey = create_config_fonts_registry_key();
2846 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2847 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2848 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2849 RegCloseKey(hkey);
2851 hkey = create_fonts_NT_registry_key();
2852 add_font_list(hkey, &nls_update_font_list[i]);
2853 RegCloseKey(hkey);
2855 hkey = create_fonts_9x_registry_key();
2856 add_font_list(hkey, &nls_update_font_list[i]);
2857 RegCloseKey(hkey);
2859 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2861 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2862 strlen(nls_update_font_list[i].shelldlg)+1);
2863 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2864 strlen(nls_update_font_list[i].tmsrmn)+1);
2866 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2867 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2868 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2869 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2870 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2871 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2872 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2873 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2875 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2876 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2877 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2879 RegCloseKey(hkey);
2881 done = TRUE;
2883 else
2885 /* Delete the FontSubstitutes from other locales */
2886 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2888 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2889 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2890 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2891 RegCloseKey(hkey);
2895 if (!done)
2896 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2899 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2901 const WCHAR *value;
2902 int i;
2903 FontSubst *psub;
2904 Family *family;
2905 Face *face;
2906 const char *file;
2907 WCHAR *fileW;
2908 WCHAR buff[MAX_PATH];
2909 WCHAR *data;
2910 int entryLen;
2912 static const WCHAR comma[] = {',',0};
2914 RegDeleteValueW(hkey, name);
2915 if (values)
2917 data = buff;
2918 data[0] = '\0';
2919 for (i = 0; values[i] != NULL; i++)
2921 value = values[i];
2922 if (!strcmpiW(name,value))
2923 continue;
2924 psub = get_font_subst(&font_subst_list, value, -1);
2925 if(psub)
2926 value = psub->to.name;
2927 family = find_family_from_name(value);
2928 if (!family)
2929 continue;
2930 file = NULL;
2931 /* Use first extant filename for this Family */
2932 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2934 if (!face->file)
2935 continue;
2936 file = strrchr(face->file, '/');
2937 if (!file)
2938 file = face->file;
2939 else
2940 file++;
2941 break;
2943 if (!file)
2944 continue;
2945 fileW = towstr(CP_UNIXCP, file);
2946 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2947 if (sizeof(buff)-(data-buff) < entryLen + 1)
2949 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2950 HeapFree(GetProcessHeap(), 0, fileW);
2951 break;
2953 strcpyW(data, fileW);
2954 strcatW(data, comma);
2955 strcatW(data, value);
2956 data += entryLen;
2957 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2958 HeapFree(GetProcessHeap(), 0, fileW);
2960 if (data != buff)
2962 *data='\0';
2963 data++;
2964 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2965 } else
2966 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2967 } else
2968 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2971 static void update_system_links(void)
2973 HKEY hkey = 0;
2974 UINT i, j;
2975 BOOL done = FALSE;
2976 DWORD disposition;
2977 FontSubst *psub;
2979 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2981 if (!RegCreateKeyExW(HKEY_CURRENT_USER, internal_system_link, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2983 if (disposition == REG_OPENED_EXISTING_KEY)
2985 TRACE("SystemLink key already exists, doing nothing\n");
2986 RegCloseKey(hkey);
2987 return;
2990 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2991 if (!psub) {
2992 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2993 RegCloseKey(hkey);
2994 return;
2997 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2999 const FontSubst *psub2;
3000 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
3002 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
3004 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
3005 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
3007 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
3008 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
3009 done = TRUE;
3011 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
3013 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
3016 RegCloseKey(hkey);
3017 if (!done)
3018 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
3019 } else
3020 WARN("failed to create Internal SystemLink key\n");
3024 static BOOL init_freetype(void)
3026 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3027 if(!ft_handle) {
3028 WINE_MESSAGE(
3029 "Wine cannot find the FreeType font library. To enable Wine to\n"
3030 "use TrueType fonts please install a version of FreeType greater than\n"
3031 "or equal to 2.0.5.\n"
3032 "http://www.freetype.org\n");
3033 return FALSE;
3036 #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;}
3038 LOAD_FUNCPTR(FT_Done_Face)
3039 LOAD_FUNCPTR(FT_Get_Char_Index)
3040 LOAD_FUNCPTR(FT_Get_First_Char)
3041 LOAD_FUNCPTR(FT_Get_Module)
3042 LOAD_FUNCPTR(FT_Get_Next_Char)
3043 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3044 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3045 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3046 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3047 LOAD_FUNCPTR(FT_Init_FreeType)
3048 LOAD_FUNCPTR(FT_Library_Version)
3049 LOAD_FUNCPTR(FT_Load_Glyph)
3050 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3051 LOAD_FUNCPTR(FT_Matrix_Multiply)
3052 #ifndef FT_MULFIX_INLINED
3053 LOAD_FUNCPTR(FT_MulFix)
3054 #endif
3055 LOAD_FUNCPTR(FT_New_Face)
3056 LOAD_FUNCPTR(FT_New_Memory_Face)
3057 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3058 LOAD_FUNCPTR(FT_Outline_Transform)
3059 LOAD_FUNCPTR(FT_Outline_Translate)
3060 LOAD_FUNCPTR(FT_Render_Glyph)
3061 LOAD_FUNCPTR(FT_Select_Charmap)
3062 LOAD_FUNCPTR(FT_Set_Charmap)
3063 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3064 LOAD_FUNCPTR(FT_Vector_Transform)
3065 LOAD_FUNCPTR(FT_Vector_Unit)
3066 #undef LOAD_FUNCPTR
3067 /* Don't warn if these ones are missing */
3068 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3069 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3070 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3071 #endif
3073 if(pFT_Init_FreeType(&library) != 0) {
3074 ERR("Can't init FreeType library\n");
3075 wine_dlclose(ft_handle, NULL, 0);
3076 ft_handle = NULL;
3077 return FALSE;
3079 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3081 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3082 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3083 ((FT_Version.minor << 8) & 0x00ff00) |
3084 ((FT_Version.patch ) & 0x0000ff);
3086 font_driver = &freetype_funcs;
3087 return TRUE;
3089 sym_not_found:
3090 WINE_MESSAGE(
3091 "Wine cannot find certain functions that it needs inside the FreeType\n"
3092 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3093 "FreeType to at least version 2.1.4.\n"
3094 "http://www.freetype.org\n");
3095 wine_dlclose(ft_handle, NULL, 0);
3096 ft_handle = NULL;
3097 return FALSE;
3100 static void init_font_list(void)
3102 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3103 static const WCHAR pathW[] = {'P','a','t','h',0};
3104 HKEY hkey;
3105 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3106 WCHAR windowsdir[MAX_PATH];
3107 char *unixname;
3108 const char *data_dir;
3110 delete_external_font_keys();
3112 /* load the system bitmap fonts */
3113 load_system_fonts();
3115 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3116 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3117 strcatW(windowsdir, fontsW);
3118 if((unixname = wine_get_unix_file_name(windowsdir)))
3120 ReadFontDir(unixname, FALSE);
3121 HeapFree(GetProcessHeap(), 0, unixname);
3124 /* load the system truetype fonts */
3125 data_dir = wine_get_data_dir();
3126 if (!data_dir) data_dir = wine_get_build_dir();
3127 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3129 strcpy(unixname, data_dir);
3130 strcat(unixname, "/fonts/");
3131 ReadFontDir(unixname, TRUE);
3132 HeapFree(GetProcessHeap(), 0, unixname);
3135 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3136 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3137 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3138 will skip these. */
3139 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3140 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3141 &hkey) == ERROR_SUCCESS)
3143 LPWSTR data, valueW;
3144 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3145 &valuelen, &datalen, NULL, NULL);
3147 valuelen++; /* returned value doesn't include room for '\0' */
3148 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3149 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3150 if (valueW && data)
3152 dlen = datalen * sizeof(WCHAR);
3153 vlen = valuelen;
3154 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3155 &dlen) == ERROR_SUCCESS)
3157 if(data[0] && (data[1] == ':'))
3159 if((unixname = wine_get_unix_file_name(data)))
3161 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3162 HeapFree(GetProcessHeap(), 0, unixname);
3165 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3167 WCHAR pathW[MAX_PATH];
3168 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3169 BOOL added = FALSE;
3171 sprintfW(pathW, fmtW, windowsdir, data);
3172 if((unixname = wine_get_unix_file_name(pathW)))
3174 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3175 HeapFree(GetProcessHeap(), 0, unixname);
3177 if (!added)
3178 load_font_from_data_dir(data);
3180 /* reset dlen and vlen */
3181 dlen = datalen;
3182 vlen = valuelen;
3185 HeapFree(GetProcessHeap(), 0, data);
3186 HeapFree(GetProcessHeap(), 0, valueW);
3187 RegCloseKey(hkey);
3190 load_fontconfig_fonts();
3192 /* then look in any directories that we've specified in the config file */
3193 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3194 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3196 DWORD len;
3197 LPWSTR valueW;
3198 LPSTR valueA, ptr;
3200 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3202 len += sizeof(WCHAR);
3203 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3204 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3206 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3207 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3208 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3209 TRACE( "got font path %s\n", debugstr_a(valueA) );
3210 ptr = valueA;
3211 while (ptr)
3213 const char* home;
3214 LPSTR next = strchr( ptr, ':' );
3215 if (next) *next++ = 0;
3216 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3217 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3219 strcpy( unixname, home );
3220 strcat( unixname, ptr + 1 );
3221 ReadFontDir( unixname, TRUE );
3222 HeapFree( GetProcessHeap(), 0, unixname );
3224 else
3225 ReadFontDir( ptr, TRUE );
3226 ptr = next;
3228 HeapFree( GetProcessHeap(), 0, valueA );
3230 HeapFree( GetProcessHeap(), 0, valueW );
3232 RegCloseKey(hkey);
3236 static BOOL move_to_front(const WCHAR *name)
3238 Family *family, *cursor2;
3239 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3241 if(!strcmpiW(family->FamilyName, name))
3243 list_remove(&family->entry);
3244 list_add_head(&font_list, &family->entry);
3245 return TRUE;
3248 return FALSE;
3251 static BOOL set_default(const WCHAR **name_list)
3253 while (*name_list)
3255 if (move_to_front(*name_list)) return TRUE;
3256 name_list++;
3259 return FALSE;
3262 static void reorder_font_list(void)
3264 set_default( default_serif_list );
3265 set_default( default_fixed_list );
3266 set_default( default_sans_list );
3269 /*************************************************************
3270 * WineEngInit
3272 * Initialize FreeType library and create a list of available faces
3274 BOOL WineEngInit(void)
3276 HKEY hkey_font_cache;
3277 DWORD disposition;
3278 HANDLE font_mutex;
3280 /* update locale dependent font info in registry */
3281 update_font_info();
3283 if(!init_freetype()) return FALSE;
3285 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3287 ERR("Failed to create font mutex\n");
3288 return FALSE;
3290 WaitForSingleObject(font_mutex, INFINITE);
3292 create_font_cache_key(&hkey_font_cache, &disposition);
3294 if(disposition == REG_CREATED_NEW_KEY)
3295 init_font_list();
3296 else
3297 load_font_list_from_cache(hkey_font_cache);
3299 RegCloseKey(hkey_font_cache);
3301 reorder_font_list();
3303 DumpFontList();
3304 LoadSubstList();
3305 DumpSubstList();
3306 LoadReplaceList();
3308 if(disposition == REG_CREATED_NEW_KEY)
3309 update_reg_entries();
3311 update_system_links();
3312 init_system_links();
3314 ReleaseMutex(font_mutex);
3315 return TRUE;
3319 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3321 TT_OS2 *pOS2;
3322 TT_HoriHeader *pHori;
3324 LONG ppem;
3326 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3327 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3329 if(height == 0) height = 16;
3331 /* Calc. height of EM square:
3333 * For +ve lfHeight we have
3334 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3335 * Re-arranging gives:
3336 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3338 * For -ve lfHeight we have
3339 * |lfHeight| = ppem
3340 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3341 * with il = winAscent + winDescent - units_per_em]
3345 if(height > 0) {
3346 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3347 ppem = MulDiv(ft_face->units_per_EM, height,
3348 pHori->Ascender - pHori->Descender);
3349 else
3350 ppem = MulDiv(ft_face->units_per_EM, height,
3351 pOS2->usWinAscent + pOS2->usWinDescent);
3353 else
3354 ppem = -height;
3356 return ppem;
3359 static struct font_mapping *map_font_file( const char *name )
3361 struct font_mapping *mapping;
3362 struct stat st;
3363 int fd;
3365 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3366 if (fstat( fd, &st ) == -1) goto error;
3368 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3370 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3372 mapping->refcount++;
3373 close( fd );
3374 return mapping;
3377 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3378 goto error;
3380 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3381 close( fd );
3383 if (mapping->data == MAP_FAILED)
3385 HeapFree( GetProcessHeap(), 0, mapping );
3386 return NULL;
3388 mapping->refcount = 1;
3389 mapping->dev = st.st_dev;
3390 mapping->ino = st.st_ino;
3391 mapping->size = st.st_size;
3392 list_add_tail( &mappings_list, &mapping->entry );
3393 return mapping;
3395 error:
3396 close( fd );
3397 return NULL;
3400 static void unmap_font_file( struct font_mapping *mapping )
3402 if (!--mapping->refcount)
3404 list_remove( &mapping->entry );
3405 munmap( mapping->data, mapping->size );
3406 HeapFree( GetProcessHeap(), 0, mapping );
3410 static LONG load_VDMX(GdiFont*, LONG);
3412 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3414 FT_Error err;
3415 FT_Face ft_face;
3416 void *data_ptr;
3417 DWORD data_size;
3419 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3421 if (face->file)
3423 if (!(font->mapping = map_font_file( face->file )))
3425 WARN("failed to map %s\n", debugstr_a(face->file));
3426 return 0;
3428 data_ptr = font->mapping->data;
3429 data_size = font->mapping->size;
3431 else
3433 data_ptr = face->font_data_ptr;
3434 data_size = face->font_data_size;
3437 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3438 if(err) {
3439 ERR("FT_New_Face rets %d\n", err);
3440 return 0;
3443 /* set it here, as load_VDMX needs it */
3444 font->ft_face = ft_face;
3446 if(FT_IS_SCALABLE(ft_face)) {
3447 /* load the VDMX table if we have one */
3448 font->ppem = load_VDMX(font, height);
3449 if(font->ppem == 0)
3450 font->ppem = calc_ppem_for_height(ft_face, height);
3451 TRACE("height %d => ppem %d\n", height, font->ppem);
3453 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3454 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3455 } else {
3456 font->ppem = height;
3457 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3458 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3460 return ft_face;
3464 static int get_nearest_charset(Face *face, int *cp)
3466 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3467 a single face with the requested charset. The idea is to check if
3468 the selected font supports the current ANSI codepage, if it does
3469 return the corresponding charset, else return the first charset */
3471 CHARSETINFO csi;
3472 int acp = GetACP(), i;
3473 DWORD fs0;
3475 *cp = acp;
3476 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3477 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3478 return csi.ciCharset;
3480 for(i = 0; i < 32; i++) {
3481 fs0 = 1L << i;
3482 if(face->fs.fsCsb[0] & fs0) {
3483 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3484 *cp = csi.ciACP;
3485 return csi.ciCharset;
3487 else
3488 FIXME("TCI failing on %x\n", fs0);
3492 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3493 face->fs.fsCsb[0], face->file);
3494 *cp = acp;
3495 return DEFAULT_CHARSET;
3498 static GdiFont *alloc_font(void)
3500 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3501 ret->gmsize = 1;
3502 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3503 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3504 ret->potm = NULL;
3505 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3506 ret->total_kern_pairs = (DWORD)-1;
3507 ret->kern_pairs = NULL;
3508 list_init(&ret->hfontlist);
3509 list_init(&ret->child_fonts);
3510 return ret;
3513 static void free_font(GdiFont *font)
3515 struct list *cursor, *cursor2;
3516 DWORD i;
3518 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3520 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3521 list_remove(cursor);
3522 if(child->font)
3523 free_font(child->font);
3524 HeapFree(GetProcessHeap(), 0, child);
3527 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3529 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3530 DeleteObject(hfontlist->hfont);
3531 list_remove(&hfontlist->entry);
3532 HeapFree(GetProcessHeap(), 0, hfontlist);
3535 if (font->ft_face) pFT_Done_Face(font->ft_face);
3536 if (font->mapping) unmap_font_file( font->mapping );
3537 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3538 HeapFree(GetProcessHeap(), 0, font->potm);
3539 HeapFree(GetProcessHeap(), 0, font->name);
3540 for (i = 0; i < font->gmsize; i++)
3541 HeapFree(GetProcessHeap(),0,font->gm[i]);
3542 HeapFree(GetProcessHeap(), 0, font->gm);
3543 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3544 HeapFree(GetProcessHeap(), 0, font);
3548 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3550 FT_Face ft_face = font->ft_face;
3551 FT_ULong len;
3552 FT_Error err;
3554 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3556 if(!buf)
3557 len = 0;
3558 else
3559 len = cbData;
3561 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3563 /* make sure value of len is the value freetype says it needs */
3564 if (buf && len)
3566 FT_ULong needed = 0;
3567 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3568 if( !err && needed < len) len = needed;
3570 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3571 if (err)
3573 TRACE("Can't find table %c%c%c%c\n",
3574 /* bytes were reversed */
3575 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3576 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3577 return GDI_ERROR;
3579 return len;
3582 /*************************************************************
3583 * load_VDMX
3585 * load the vdmx entry for the specified height
3588 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3589 ( ( (FT_ULong)_x4 << 24 ) | \
3590 ( (FT_ULong)_x3 << 16 ) | \
3591 ( (FT_ULong)_x2 << 8 ) | \
3592 (FT_ULong)_x1 )
3594 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3596 typedef struct {
3597 BYTE bCharSet;
3598 BYTE xRatio;
3599 BYTE yStartRatio;
3600 BYTE yEndRatio;
3601 } Ratios;
3603 typedef struct {
3604 WORD recs;
3605 BYTE startsz;
3606 BYTE endsz;
3607 } VDMX_group;
3609 static LONG load_VDMX(GdiFont *font, LONG height)
3611 WORD hdr[3], tmp;
3612 VDMX_group group;
3613 BYTE devXRatio, devYRatio;
3614 USHORT numRecs, numRatios;
3615 DWORD result, offset = -1;
3616 LONG ppem = 0;
3617 int i;
3619 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3621 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3622 return ppem;
3624 /* FIXME: need the real device aspect ratio */
3625 devXRatio = 1;
3626 devYRatio = 1;
3628 numRecs = GET_BE_WORD(hdr[1]);
3629 numRatios = GET_BE_WORD(hdr[2]);
3631 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3632 for(i = 0; i < numRatios; i++) {
3633 Ratios ratio;
3635 offset = (3 * 2) + (i * sizeof(Ratios));
3636 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3637 offset = -1;
3639 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3641 if((ratio.xRatio == 0 &&
3642 ratio.yStartRatio == 0 &&
3643 ratio.yEndRatio == 0) ||
3644 (devXRatio == ratio.xRatio &&
3645 devYRatio >= ratio.yStartRatio &&
3646 devYRatio <= ratio.yEndRatio))
3648 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3649 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3650 offset = GET_BE_WORD(tmp);
3651 break;
3655 if(offset == -1) {
3656 FIXME("No suitable ratio found\n");
3657 return ppem;
3660 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3661 USHORT recs;
3662 BYTE startsz, endsz;
3663 WORD *vTable;
3665 recs = GET_BE_WORD(group.recs);
3666 startsz = group.startsz;
3667 endsz = group.endsz;
3669 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3671 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3672 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3673 if(result == GDI_ERROR) {
3674 FIXME("Failed to retrieve vTable\n");
3675 goto end;
3678 if(height > 0) {
3679 for(i = 0; i < recs; i++) {
3680 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3681 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3682 ppem = GET_BE_WORD(vTable[i * 3]);
3684 if(yMax + -yMin == height) {
3685 font->yMax = yMax;
3686 font->yMin = yMin;
3687 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3688 break;
3690 if(yMax + -yMin > height) {
3691 if(--i < 0) {
3692 ppem = 0;
3693 goto end; /* failed */
3695 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3696 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3697 ppem = GET_BE_WORD(vTable[i * 3]);
3698 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3699 break;
3702 if(!font->yMax) {
3703 ppem = 0;
3704 TRACE("ppem not found for height %d\n", height);
3707 end:
3708 HeapFree(GetProcessHeap(), 0, vTable);
3711 return ppem;
3714 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3716 if(font->font_desc.hash != fd->hash) return TRUE;
3717 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3718 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3719 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3720 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3723 static void calc_hash(FONT_DESC *pfd)
3725 DWORD hash = 0, *ptr, two_chars;
3726 WORD *pwc;
3727 unsigned int i;
3729 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3730 hash ^= *ptr;
3731 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3732 hash ^= *ptr;
3733 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3734 two_chars = *ptr;
3735 pwc = (WCHAR *)&two_chars;
3736 if(!*pwc) break;
3737 *pwc = toupperW(*pwc);
3738 pwc++;
3739 *pwc = toupperW(*pwc);
3740 hash ^= two_chars;
3741 if(!*pwc) break;
3743 hash ^= !pfd->can_use_bitmap;
3744 pfd->hash = hash;
3745 return;
3748 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3750 GdiFont *ret;
3751 FONT_DESC fd;
3752 HFONTLIST *hflist;
3753 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3755 fd.lf = *plf;
3756 fd.matrix = *pmat;
3757 fd.can_use_bitmap = can_use_bitmap;
3758 calc_hash(&fd);
3760 /* try the child list */
3761 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3762 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3763 if(!fontcmp(ret, &fd)) {
3764 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3765 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3766 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3767 if(hflist->hfont == hfont)
3768 return ret;
3773 /* try the in-use list */
3774 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3775 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3776 if(!fontcmp(ret, &fd)) {
3777 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3778 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3779 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3780 if(hflist->hfont == hfont)
3781 return ret;
3783 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3784 hflist->hfont = hfont;
3785 list_add_head(&ret->hfontlist, &hflist->entry);
3786 return ret;
3790 /* then the unused list */
3791 font_elem_ptr = list_head(&unused_gdi_font_list);
3792 while(font_elem_ptr) {
3793 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3794 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3795 if(!fontcmp(ret, &fd)) {
3796 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3797 assert(list_empty(&ret->hfontlist));
3798 TRACE("Found %p in unused list\n", ret);
3799 list_remove(&ret->entry);
3800 list_add_head(&gdi_font_list, &ret->entry);
3801 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3802 hflist->hfont = hfont;
3803 list_add_head(&ret->hfontlist, &hflist->entry);
3804 return ret;
3807 return NULL;
3810 static void add_to_cache(GdiFont *font)
3812 static DWORD cache_num = 1;
3814 font->cache_num = cache_num++;
3815 list_add_head(&gdi_font_list, &font->entry);
3818 /*************************************************************
3819 * create_child_font_list
3821 static BOOL create_child_font_list(GdiFont *font)
3823 BOOL ret = FALSE;
3824 SYSTEM_LINKS *font_link;
3825 CHILD_FONT *font_link_entry, *new_child;
3826 FontSubst *psub;
3827 WCHAR* font_name;
3829 psub = get_font_subst(&font_subst_list, font->name, -1);
3830 font_name = psub ? psub->to.name : font->name;
3831 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3833 if(!strcmpiW(font_link->font_name, font_name))
3835 TRACE("found entry in system list\n");
3836 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3838 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3839 new_child->face = font_link_entry->face;
3840 new_child->font = NULL;
3841 list_add_tail(&font->child_fonts, &new_child->entry);
3842 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3844 ret = TRUE;
3845 break;
3849 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3850 * Sans Serif. This is how asian windows get default fallbacks for fonts
3852 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3853 font->charset != OEM_CHARSET &&
3854 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3855 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3857 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3859 TRACE("found entry in default fallback list\n");
3860 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3862 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3863 new_child->face = font_link_entry->face;
3864 new_child->font = NULL;
3865 list_add_tail(&font->child_fonts, &new_child->entry);
3866 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3868 ret = TRUE;
3869 break;
3873 return ret;
3876 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3878 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3880 if (pFT_Set_Charmap)
3882 FT_Int i;
3883 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3885 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3887 for (i = 0; i < ft_face->num_charmaps; i++)
3889 if (ft_face->charmaps[i]->encoding == encoding)
3891 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3892 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3894 switch (ft_face->charmaps[i]->platform_id)
3896 default:
3897 cmap_def = ft_face->charmaps[i];
3898 break;
3899 case 0: /* Apple Unicode */
3900 cmap0 = ft_face->charmaps[i];
3901 break;
3902 case 1: /* Macintosh */
3903 cmap1 = ft_face->charmaps[i];
3904 break;
3905 case 2: /* ISO */
3906 cmap2 = ft_face->charmaps[i];
3907 break;
3908 case 3: /* Microsoft */
3909 cmap3 = ft_face->charmaps[i];
3910 break;
3914 if (cmap3) /* prefer Microsoft cmap table */
3915 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3916 else if (cmap1)
3917 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3918 else if (cmap2)
3919 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3920 else if (cmap0)
3921 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3922 else if (cmap_def)
3923 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3925 return ft_err == FT_Err_Ok;
3928 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3932 /*************************************************************
3933 * freetype_CreateDC
3935 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3936 LPCWSTR output, const DEVMODEW *devmode )
3938 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3940 if (!physdev) return FALSE;
3941 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3942 return TRUE;
3946 /*************************************************************
3947 * freetype_DeleteDC
3949 static BOOL freetype_DeleteDC( PHYSDEV dev )
3951 struct freetype_physdev *physdev = get_freetype_dev( dev );
3952 HeapFree( GetProcessHeap(), 0, physdev );
3953 return TRUE;
3957 /*************************************************************
3958 * freetype_SelectFont
3960 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3962 struct freetype_physdev *physdev = get_freetype_dev( dev );
3963 GdiFont *ret;
3964 Face *face, *best, *best_bitmap;
3965 Family *family, *last_resort_family;
3966 struct list *family_elem_ptr, *face_elem_ptr;
3967 INT height, width = 0;
3968 unsigned int score = 0, new_score;
3969 signed int diff = 0, newdiff;
3970 BOOL bd, it, can_use_bitmap;
3971 LOGFONTW lf;
3972 CHARSETINFO csi;
3973 HFONTLIST *hflist;
3974 FMAT2 dcmat;
3975 FontSubst *psub = NULL;
3976 DC *dc = get_dc_ptr( dev->hdc );
3978 if (!hfont) /* notification that the font has been changed by another driver */
3980 dc->gdiFont = NULL;
3981 physdev->font = NULL;
3982 release_dc_ptr( dc );
3983 return 0;
3986 GetObjectW( hfont, sizeof(lf), &lf );
3987 lf.lfWidth = abs(lf.lfWidth);
3989 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3991 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3992 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3993 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3994 lf.lfEscapement);
3996 if(dc->GraphicsMode == GM_ADVANCED)
3997 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3998 else
4000 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4001 font scaling abilities. */
4002 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
4003 dcmat.eM21 = dcmat.eM12 = 0;
4006 /* Try to avoid not necessary glyph transformations */
4007 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4009 lf.lfHeight *= fabs(dcmat.eM11);
4010 lf.lfWidth *= fabs(dcmat.eM11);
4011 dcmat.eM11 = dcmat.eM22 = 1.0;
4014 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4015 dcmat.eM21, dcmat.eM22);
4017 GDI_CheckNotLock();
4018 EnterCriticalSection( &freetype_cs );
4020 /* check the cache first */
4021 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4022 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4023 goto done;
4026 if(list_empty(&font_list)) /* No fonts installed */
4028 TRACE("No fonts installed\n");
4029 goto done;
4032 TRACE("not in cache\n");
4033 ret = alloc_font();
4035 ret->font_desc.matrix = dcmat;
4036 ret->font_desc.lf = lf;
4037 ret->font_desc.can_use_bitmap = can_use_bitmap;
4038 calc_hash(&ret->font_desc);
4039 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4040 hflist->hfont = hfont;
4041 list_add_head(&ret->hfontlist, &hflist->entry);
4043 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4044 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4045 original value lfCharSet. Note this is a special case for
4046 Symbol and doesn't happen at least for "Wingdings*" */
4048 if(!strcmpiW(lf.lfFaceName, SymbolW))
4049 lf.lfCharSet = SYMBOL_CHARSET;
4051 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4052 switch(lf.lfCharSet) {
4053 case DEFAULT_CHARSET:
4054 csi.fs.fsCsb[0] = 0;
4055 break;
4056 default:
4057 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4058 csi.fs.fsCsb[0] = 0;
4059 break;
4063 family = NULL;
4064 if(lf.lfFaceName[0] != '\0') {
4065 SYSTEM_LINKS *font_link;
4066 CHILD_FONT *font_link_entry;
4067 LPWSTR FaceName = lf.lfFaceName;
4069 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4071 if(psub) {
4072 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4073 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4074 if (psub->to.charset != -1)
4075 lf.lfCharSet = psub->to.charset;
4078 /* We want a match on name and charset or just name if
4079 charset was DEFAULT_CHARSET. If the latter then
4080 we fixup the returned charset later in get_nearest_charset
4081 where we'll either use the charset of the current ansi codepage
4082 or if that's unavailable the first charset that the font supports.
4084 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4085 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4086 if (!strcmpiW(family->FamilyName, FaceName) ||
4087 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4089 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4090 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4091 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4092 if(face->scalable || can_use_bitmap)
4093 goto found;
4098 /* Search by full face name. */
4099 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4100 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4101 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4102 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4103 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4104 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
4106 if(face->scalable || can_use_bitmap)
4107 goto found_face;
4113 * Try check the SystemLink list first for a replacement font.
4114 * We may find good replacements there.
4116 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4118 if(!strcmpiW(font_link->font_name, FaceName) ||
4119 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4121 TRACE("found entry in system list\n");
4122 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4124 face = font_link_entry->face;
4125 family = face->family;
4126 if(csi.fs.fsCsb[0] &
4127 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4129 if(face->scalable || can_use_bitmap)
4130 goto found;
4137 psub = NULL; /* substitution is no more relevant */
4139 /* If requested charset was DEFAULT_CHARSET then try using charset
4140 corresponding to the current ansi codepage */
4141 if (!csi.fs.fsCsb[0])
4143 INT acp = GetACP();
4144 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4145 FIXME("TCI failed on codepage %d\n", acp);
4146 csi.fs.fsCsb[0] = 0;
4147 } else
4148 lf.lfCharSet = csi.ciCharset;
4151 /* Face families are in the top 4 bits of lfPitchAndFamily,
4152 so mask with 0xF0 before testing */
4154 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4155 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4156 strcpyW(lf.lfFaceName, defFixed);
4157 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4158 strcpyW(lf.lfFaceName, defSerif);
4159 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4160 strcpyW(lf.lfFaceName, defSans);
4161 else
4162 strcpyW(lf.lfFaceName, defSans);
4163 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4164 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4165 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4166 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4167 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4168 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4169 if(face->scalable || can_use_bitmap)
4170 goto found;
4175 last_resort_family = NULL;
4176 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4177 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4178 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4179 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4180 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
4181 if(face->scalable)
4182 goto found;
4183 if(can_use_bitmap && !last_resort_family)
4184 last_resort_family = family;
4189 if(last_resort_family) {
4190 family = last_resort_family;
4191 csi.fs.fsCsb[0] = 0;
4192 goto found;
4195 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4196 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4197 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4198 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4199 if(face->scalable) {
4200 csi.fs.fsCsb[0] = 0;
4201 WARN("just using first face for now\n");
4202 goto found;
4204 if(can_use_bitmap && !last_resort_family)
4205 last_resort_family = family;
4208 if(!last_resort_family) {
4209 FIXME("can't find a single appropriate font - bailing\n");
4210 free_font(ret);
4211 ret = NULL;
4212 goto done;
4215 WARN("could only find a bitmap font - this will probably look awful!\n");
4216 family = last_resort_family;
4217 csi.fs.fsCsb[0] = 0;
4219 found:
4220 it = lf.lfItalic ? 1 : 0;
4221 bd = lf.lfWeight > 550 ? 1 : 0;
4223 height = lf.lfHeight;
4225 face = best = best_bitmap = NULL;
4226 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4228 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4230 BOOL italic, bold;
4232 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4233 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4234 new_score = (italic ^ it) + (bold ^ bd);
4235 if(!best || new_score <= score)
4237 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4238 italic, bold, it, bd);
4239 score = new_score;
4240 best = face;
4241 if(best->scalable && score == 0) break;
4242 if(!best->scalable)
4244 if(height > 0)
4245 newdiff = height - (signed int)(best->size.height);
4246 else
4247 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4248 if(!best_bitmap || new_score < score ||
4249 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4251 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4252 diff = newdiff;
4253 best_bitmap = best;
4254 if(score == 0 && diff == 0) break;
4260 if(best)
4261 face = best->scalable ? best : best_bitmap;
4262 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4263 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4265 found_face:
4266 height = lf.lfHeight;
4268 ret->fs = face->fs;
4270 if(csi.fs.fsCsb[0]) {
4271 ret->charset = lf.lfCharSet;
4272 ret->codepage = csi.ciACP;
4274 else
4275 ret->charset = get_nearest_charset(face, &ret->codepage);
4277 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4278 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4280 ret->aveWidth = height ? lf.lfWidth : 0;
4282 if(!face->scalable) {
4283 /* Windows uses integer scaling factors for bitmap fonts */
4284 INT scale, scaled_height;
4285 GdiFont *cachedfont;
4287 /* FIXME: rotation of bitmap fonts is ignored */
4288 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4289 if (ret->aveWidth)
4290 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4291 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4292 dcmat.eM11 = dcmat.eM22 = 1.0;
4293 /* As we changed the matrix, we need to search the cache for the font again,
4294 * otherwise we might explode the cache. */
4295 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4296 TRACE("Found cached font after non-scalable matrix rescale!\n");
4297 free_font( ret );
4298 ret = cachedfont;
4299 goto done;
4301 calc_hash(&ret->font_desc);
4303 if (height != 0) height = diff;
4304 height += face->size.height;
4306 scale = (height + face->size.height - 1) / face->size.height;
4307 scaled_height = scale * face->size.height;
4308 /* Only jump to the next height if the difference <= 25% original height */
4309 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4310 /* The jump between unscaled and doubled is delayed by 1 */
4311 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4312 ret->scale_y = scale;
4314 width = face->size.x_ppem >> 6;
4315 height = face->size.y_ppem >> 6;
4317 else
4318 ret->scale_y = 1.0;
4319 TRACE("font scale y: %f\n", ret->scale_y);
4321 ret->ft_face = OpenFontFace(ret, face, width, height);
4323 if (!ret->ft_face)
4325 free_font( ret );
4326 ret = NULL;
4327 goto done;
4330 ret->ntmFlags = face->ntmFlags;
4332 if (ret->charset == SYMBOL_CHARSET &&
4333 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4334 /* No ops */
4336 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4337 /* No ops */
4339 else {
4340 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4343 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4344 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4345 ret->underline = lf.lfUnderline ? 0xff : 0;
4346 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4347 create_child_font_list(ret);
4349 if (face->vertical) /* We need to try to load the GSUB table */
4351 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4352 if (length != GDI_ERROR)
4354 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4355 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4356 TRACE("Loaded GSUB table of %i bytes\n",length);
4360 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4362 add_to_cache(ret);
4363 done:
4364 if (ret)
4366 dc->gdiFont = ret;
4367 physdev->font = ret;
4369 LeaveCriticalSection( &freetype_cs );
4370 release_dc_ptr( dc );
4371 return ret ? hfont : 0;
4374 static void dump_gdi_font_list(void)
4376 GdiFont *gdiFont;
4377 struct list *elem_ptr;
4379 TRACE("---------- gdiFont Cache ----------\n");
4380 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4381 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4382 TRACE("gdiFont=%p %s %d\n",
4383 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4386 TRACE("---------- Unused gdiFont Cache ----------\n");
4387 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4388 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4389 TRACE("gdiFont=%p %s %d\n",
4390 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4393 TRACE("---------- Child gdiFont Cache ----------\n");
4394 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4395 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4396 TRACE("gdiFont=%p %s %d\n",
4397 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4401 /*************************************************************
4402 * WineEngDestroyFontInstance
4404 * free the gdiFont associated with this handle
4407 BOOL WineEngDestroyFontInstance(HFONT handle)
4409 GdiFont *gdiFont;
4410 HFONTLIST *hflist;
4411 BOOL ret = FALSE;
4412 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4413 int i = 0;
4415 GDI_CheckNotLock();
4416 EnterCriticalSection( &freetype_cs );
4418 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4420 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4421 while(hfontlist_elem_ptr) {
4422 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4423 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4424 if(hflist->hfont == handle) {
4425 TRACE("removing child font %p from child list\n", gdiFont);
4426 list_remove(&gdiFont->entry);
4427 LeaveCriticalSection( &freetype_cs );
4428 return TRUE;
4433 TRACE("destroying hfont=%p\n", handle);
4434 if(TRACE_ON(font))
4435 dump_gdi_font_list();
4437 font_elem_ptr = list_head(&gdi_font_list);
4438 while(font_elem_ptr) {
4439 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4440 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4442 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4443 while(hfontlist_elem_ptr) {
4444 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4445 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4446 if(hflist->hfont == handle) {
4447 list_remove(&hflist->entry);
4448 HeapFree(GetProcessHeap(), 0, hflist);
4449 ret = TRUE;
4452 if(list_empty(&gdiFont->hfontlist)) {
4453 TRACE("Moving to Unused list\n");
4454 list_remove(&gdiFont->entry);
4455 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4460 font_elem_ptr = list_head(&unused_gdi_font_list);
4461 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4462 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4463 while(font_elem_ptr) {
4464 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4465 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4466 TRACE("freeing %p\n", gdiFont);
4467 list_remove(&gdiFont->entry);
4468 free_font(gdiFont);
4470 LeaveCriticalSection( &freetype_cs );
4471 return ret;
4474 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4476 HRSRC rsrc;
4477 HGLOBAL hMem;
4478 WCHAR *p;
4479 int i;
4481 id += IDS_FIRST_SCRIPT;
4482 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4483 if (!rsrc) return 0;
4484 hMem = LoadResource( gdi32_module, rsrc );
4485 if (!hMem) return 0;
4487 p = LockResource( hMem );
4488 id &= 0x000f;
4489 while (id--) p += *p + 1;
4491 i = min(LF_FACESIZE - 1, *p);
4492 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4493 buffer[i] = 0;
4494 return i;
4498 /***************************************************
4499 * create_enum_charset_list
4501 * This function creates charset enumeration list because in DEFAULT_CHARSET
4502 * case, the ANSI codepage's charset takes precedence over other charsets.
4503 * This function works as a filter other than DEFAULT_CHARSET case.
4505 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4507 CHARSETINFO csi;
4508 DWORD n = 0;
4510 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4511 csi.fs.fsCsb[0] != 0) {
4512 list->element[n].mask = csi.fs.fsCsb[0];
4513 list->element[n].charset = csi.ciCharset;
4514 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4515 n++;
4517 else { /* charset is DEFAULT_CHARSET or invalid. */
4518 INT acp, i;
4520 /* Set the current codepage's charset as the first element. */
4521 acp = GetACP();
4522 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4523 csi.fs.fsCsb[0] != 0) {
4524 list->element[n].mask = csi.fs.fsCsb[0];
4525 list->element[n].charset = csi.ciCharset;
4526 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4527 n++;
4530 /* Fill out left elements. */
4531 for (i = 0; i < 32; i++) {
4532 FONTSIGNATURE fs;
4533 fs.fsCsb[0] = 1L << i;
4534 fs.fsCsb[1] = 0;
4535 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4536 continue; /* skip, already added. */
4537 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4538 continue; /* skip, this is an invalid fsCsb bit. */
4540 list->element[n].mask = fs.fsCsb[0];
4541 list->element[n].charset = csi.ciCharset;
4542 load_script_name( i, list->element[n].name );
4543 n++;
4546 list->total = n;
4548 return n;
4551 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4552 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4554 GdiFont *font;
4555 LONG width, height;
4557 if (face->cached_enum_data)
4559 TRACE("Cached\n");
4560 *pelf = face->cached_enum_data->elf;
4561 *pntm = face->cached_enum_data->ntm;
4562 *ptype = face->cached_enum_data->type;
4563 return;
4566 font = alloc_font();
4568 if(face->scalable) {
4569 height = -2048; /* 2048 is the most common em size */
4570 width = 0;
4571 } else {
4572 height = face->size.y_ppem >> 6;
4573 width = face->size.x_ppem >> 6;
4575 font->scale_y = 1.0;
4577 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4579 free_font(font);
4580 return;
4583 font->name = strdupW(face->family->FamilyName);
4584 font->ntmFlags = face->ntmFlags;
4586 if (get_outline_text_metrics(font))
4588 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4590 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4592 lstrcpynW(pelf->elfLogFont.lfFaceName,
4593 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4594 LF_FACESIZE);
4595 lstrcpynW(pelf->elfFullName,
4596 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4597 LF_FULLFACESIZE);
4598 lstrcpynW(pelf->elfStyle,
4599 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4600 LF_FACESIZE);
4602 else
4604 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4606 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4608 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4609 if (face->FullName)
4610 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4611 else
4612 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4613 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4616 pntm->ntmTm.ntmFlags = face->ntmFlags;
4617 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4618 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4619 pntm->ntmFontSig = face->fs;
4621 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4623 pelf->elfLogFont.lfEscapement = 0;
4624 pelf->elfLogFont.lfOrientation = 0;
4625 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4626 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4627 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4628 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4629 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4630 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4631 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4632 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4633 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4634 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4635 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4637 *ptype = 0;
4638 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4639 *ptype |= TRUETYPE_FONTTYPE;
4640 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4641 *ptype |= DEVICE_FONTTYPE;
4642 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4643 *ptype |= RASTER_FONTTYPE;
4645 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4646 if (face->cached_enum_data)
4648 face->cached_enum_data->elf = *pelf;
4649 face->cached_enum_data->ntm = *pntm;
4650 face->cached_enum_data->type = *ptype;
4653 free_font(font);
4656 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4658 struct list *face_elem_ptr;
4660 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4662 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4664 static const WCHAR spaceW[] = { ' ',0 };
4665 WCHAR full_family_name[LF_FULLFACESIZE];
4666 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4668 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4670 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4671 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4672 continue;
4675 strcpyW(full_family_name, family->FamilyName);
4676 strcatW(full_family_name, spaceW);
4677 strcatW(full_family_name, face->StyleName);
4678 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4681 return FALSE;
4684 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4686 static const WCHAR spaceW[] = { ' ',0 };
4687 WCHAR full_family_name[LF_FULLFACESIZE];
4689 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4691 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4693 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4694 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4695 return FALSE;
4698 strcpyW(full_family_name, face->family->FamilyName);
4699 strcatW(full_family_name, spaceW);
4700 strcatW(full_family_name, face->StyleName);
4701 return !strcmpiW(lf->lfFaceName, full_family_name);
4704 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4705 FONTENUMPROCW proc, LPARAM lparam)
4707 ENUMLOGFONTEXW elf;
4708 NEWTEXTMETRICEXW ntm;
4709 DWORD type = 0;
4710 int i;
4712 GetEnumStructs(face, &elf, &ntm, &type);
4713 for(i = 0; i < list->total; i++) {
4714 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4715 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4716 load_script_name( IDS_OEM_DOS, elf.elfScript );
4717 i = list->total; /* break out of loop after enumeration */
4718 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4719 continue;
4720 else {
4721 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4722 strcpyW(elf.elfScript, list->element[i].name);
4723 if (!elf.elfScript[0])
4724 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4726 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4727 debugstr_w(elf.elfLogFont.lfFaceName),
4728 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4729 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4730 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4731 ntm.ntmTm.ntmFlags);
4732 /* release section before callback (FIXME) */
4733 LeaveCriticalSection( &freetype_cs );
4734 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4735 EnterCriticalSection( &freetype_cs );
4737 return TRUE;
4740 /*************************************************************
4741 * freetype_EnumFonts
4743 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4745 Family *family;
4746 Face *face;
4747 struct list *family_elem_ptr, *face_elem_ptr;
4748 LOGFONTW lf;
4749 struct enum_charset_list enum_charsets;
4751 if (!plf)
4753 lf.lfCharSet = DEFAULT_CHARSET;
4754 lf.lfPitchAndFamily = 0;
4755 lf.lfFaceName[0] = 0;
4756 plf = &lf;
4759 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4761 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4763 GDI_CheckNotLock();
4764 EnterCriticalSection( &freetype_cs );
4765 if(plf->lfFaceName[0]) {
4766 FontSubst *psub;
4767 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4769 if(psub) {
4770 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4771 debugstr_w(psub->to.name));
4772 lf = *plf;
4773 strcpyW(lf.lfFaceName, psub->to.name);
4774 plf = &lf;
4777 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4778 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4779 if(family_matches(family, plf)) {
4780 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4781 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4782 if (!face_matches(face, plf)) continue;
4783 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4787 } else {
4788 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4789 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4790 face_elem_ptr = list_head(&family->faces);
4791 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4792 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4795 LeaveCriticalSection( &freetype_cs );
4796 return TRUE;
4799 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4801 pt->x.value = vec->x >> 6;
4802 pt->x.fract = (vec->x & 0x3f) << 10;
4803 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4804 pt->y.value = vec->y >> 6;
4805 pt->y.fract = (vec->y & 0x3f) << 10;
4806 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4807 return;
4810 /***************************************************
4811 * According to the MSDN documentation on WideCharToMultiByte,
4812 * certain codepages cannot set the default_used parameter.
4813 * This returns TRUE if the codepage can set that parameter, false else
4814 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4816 static BOOL codepage_sets_default_used(UINT codepage)
4818 switch (codepage)
4820 case CP_UTF7:
4821 case CP_UTF8:
4822 case CP_SYMBOL:
4823 return FALSE;
4824 default:
4825 return TRUE;
4830 * GSUB Table handling functions
4833 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4835 const GSUB_CoverageFormat1* cf1;
4837 cf1 = table;
4839 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4841 int count = GET_BE_WORD(cf1->GlyphCount);
4842 int i;
4843 TRACE("Coverage Format 1, %i glyphs\n",count);
4844 for (i = 0; i < count; i++)
4845 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4846 return i;
4847 return -1;
4849 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4851 const GSUB_CoverageFormat2* cf2;
4852 int i;
4853 int count;
4854 cf2 = (const GSUB_CoverageFormat2*)cf1;
4856 count = GET_BE_WORD(cf2->RangeCount);
4857 TRACE("Coverage Format 2, %i ranges\n",count);
4858 for (i = 0; i < count; i++)
4860 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4861 return -1;
4862 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4863 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4865 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4866 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4869 return -1;
4871 else
4872 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4874 return -1;
4877 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4879 const GSUB_ScriptList *script;
4880 const GSUB_Script *deflt = NULL;
4881 int i;
4882 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4884 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4885 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4887 const GSUB_Script *scr;
4888 int offset;
4890 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4891 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4893 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4894 return scr;
4895 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4896 deflt = scr;
4898 return deflt;
4901 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4903 int i;
4904 int offset;
4905 const GSUB_LangSys *Lang;
4907 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4909 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4911 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4912 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4914 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4915 return Lang;
4917 offset = GET_BE_WORD(script->DefaultLangSys);
4918 if (offset)
4920 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4921 return Lang;
4923 return NULL;
4926 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4928 int i;
4929 const GSUB_FeatureList *feature;
4930 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4932 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4933 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4935 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4936 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4938 const GSUB_Feature *feat;
4939 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4940 return feat;
4943 return NULL;
4946 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4948 int i;
4949 int offset;
4950 const GSUB_LookupList *lookup;
4951 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4953 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4954 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4956 const GSUB_LookupTable *look;
4957 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4958 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4959 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4960 if (GET_BE_WORD(look->LookupType) != 1)
4961 FIXME("We only handle SubType 1\n");
4962 else
4964 int j;
4966 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4968 const GSUB_SingleSubstFormat1 *ssf1;
4969 offset = GET_BE_WORD(look->SubTable[j]);
4970 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4971 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4973 int offset = GET_BE_WORD(ssf1->Coverage);
4974 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4975 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4977 TRACE(" Glyph 0x%x ->",glyph);
4978 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4979 TRACE(" 0x%x\n",glyph);
4982 else
4984 const GSUB_SingleSubstFormat2 *ssf2;
4985 INT index;
4986 INT offset;
4988 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4989 offset = GET_BE_WORD(ssf1->Coverage);
4990 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4991 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4992 TRACE(" Coverage index %i\n",index);
4993 if (index != -1)
4995 TRACE(" Glyph is 0x%x ->",glyph);
4996 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4997 TRACE("0x%x\n",glyph);
5003 return glyph;
5006 static const char* get_opentype_script(const GdiFont *font)
5009 * I am not sure if this is the correct way to generate our script tag
5012 switch (font->charset)
5014 case ANSI_CHARSET: return "latn";
5015 case BALTIC_CHARSET: return "latn"; /* ?? */
5016 case CHINESEBIG5_CHARSET: return "hani";
5017 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5018 case GB2312_CHARSET: return "hani";
5019 case GREEK_CHARSET: return "grek";
5020 case HANGUL_CHARSET: return "hang";
5021 case RUSSIAN_CHARSET: return "cyrl";
5022 case SHIFTJIS_CHARSET: return "kana";
5023 case TURKISH_CHARSET: return "latn"; /* ?? */
5024 case VIETNAMESE_CHARSET: return "latn";
5025 case JOHAB_CHARSET: return "latn"; /* ?? */
5026 case ARABIC_CHARSET: return "arab";
5027 case HEBREW_CHARSET: return "hebr";
5028 case THAI_CHARSET: return "thai";
5029 default: return "latn";
5033 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5035 const GSUB_Header *header;
5036 const GSUB_Script *script;
5037 const GSUB_LangSys *language;
5038 const GSUB_Feature *feature;
5040 if (!font->GSUB_Table)
5041 return glyph;
5043 header = font->GSUB_Table;
5045 script = GSUB_get_script_table(header, get_opentype_script(font));
5046 if (!script)
5048 TRACE("Script not found\n");
5049 return glyph;
5051 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5052 if (!language)
5054 TRACE("Language not found\n");
5055 return glyph;
5057 feature = GSUB_get_feature(header, language, "vrt2");
5058 if (!feature)
5059 feature = GSUB_get_feature(header, language, "vert");
5060 if (!feature)
5062 TRACE("vrt2/vert feature not found\n");
5063 return glyph;
5065 return GSUB_apply_feature(header, feature, glyph);
5068 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5070 FT_UInt glyphId;
5072 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5073 WCHAR wc = (WCHAR)glyph;
5074 BOOL default_used;
5075 BOOL *default_used_pointer;
5076 FT_UInt ret;
5077 char buf;
5078 default_used_pointer = NULL;
5079 default_used = FALSE;
5080 if (codepage_sets_default_used(font->codepage))
5081 default_used_pointer = &default_used;
5082 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5083 ret = 0;
5084 else
5085 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5086 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5087 return ret;
5090 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5092 if (glyph < 0x100) glyph += 0xf000;
5093 /* there is a number of old pre-Unicode "broken" TTFs, which
5094 do have symbols at U+00XX instead of U+f0XX */
5095 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5096 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5098 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5100 return glyphId;
5103 /*************************************************************
5104 * freetype_GetGlyphIndices
5106 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5108 struct freetype_physdev *physdev = get_freetype_dev( dev );
5109 int i;
5110 WORD default_char;
5111 BOOL got_default = FALSE;
5113 if (!physdev->font)
5115 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5116 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5119 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5121 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5122 got_default = TRUE;
5125 GDI_CheckNotLock();
5126 EnterCriticalSection( &freetype_cs );
5128 for(i = 0; i < count; i++)
5130 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5131 if (pgi[i] == 0)
5133 if (!got_default)
5135 if (FT_IS_SFNT(physdev->font->ft_face))
5137 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5138 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5140 else
5142 TEXTMETRICW textm;
5143 get_text_metrics(physdev->font, &textm);
5144 default_char = textm.tmDefaultChar;
5146 got_default = TRUE;
5148 pgi[i] = default_char;
5151 LeaveCriticalSection( &freetype_cs );
5152 return count;
5155 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5157 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5158 return !memcmp(matrix, &identity, sizeof(FMAT2));
5161 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5163 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5164 return !memcmp(matrix, &identity, sizeof(MAT2));
5167 static inline BYTE get_max_level( UINT format )
5169 switch( format )
5171 case GGO_GRAY2_BITMAP: return 4;
5172 case GGO_GRAY4_BITMAP: return 16;
5173 case GGO_GRAY8_BITMAP: return 64;
5175 return 255;
5178 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5180 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5181 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5182 const MAT2* lpmat)
5184 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5185 FT_Face ft_face = incoming_font->ft_face;
5186 GdiFont *font = incoming_font;
5187 FT_UInt glyph_index;
5188 DWORD width, height, pitch, needed = 0;
5189 FT_Bitmap ft_bitmap;
5190 FT_Error err;
5191 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5192 FT_Angle angle = 0;
5193 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5194 double widthRatio = 1.0;
5195 FT_Matrix transMat = identityMat;
5196 FT_Matrix transMatUnrotated;
5197 BOOL needsTransform = FALSE;
5198 BOOL tategaki = (font->GSUB_Table != NULL);
5199 UINT original_index;
5201 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5202 buflen, buf, lpmat);
5204 TRACE("font transform %f %f %f %f\n",
5205 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5206 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5208 if(format & GGO_GLYPH_INDEX) {
5209 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5210 original_index = glyph;
5211 format &= ~GGO_GLYPH_INDEX;
5212 } else {
5213 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5214 ft_face = font->ft_face;
5215 original_index = glyph_index;
5218 if(format & GGO_UNHINTED) {
5219 load_flags |= FT_LOAD_NO_HINTING;
5220 format &= ~GGO_UNHINTED;
5223 /* tategaki never appears to happen to lower glyph index */
5224 if (glyph_index < TATEGAKI_LOWER_BOUND )
5225 tategaki = FALSE;
5227 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5228 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5229 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5230 font->gmsize * sizeof(GM*));
5231 } else {
5232 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5233 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5235 *lpgm = FONT_GM(font,original_index)->gm;
5236 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5237 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5238 lpgm->gmCellIncX, lpgm->gmCellIncY);
5239 return 1; /* FIXME */
5243 if (!font->gm[original_index / GM_BLOCK_SIZE])
5244 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5246 /* Scaling factor */
5247 if (font->aveWidth)
5249 TEXTMETRICW tm;
5251 get_text_metrics(font, &tm);
5253 widthRatio = (double)font->aveWidth;
5254 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5256 else
5257 widthRatio = font->scale_y;
5259 /* Scaling transform */
5260 if (widthRatio != 1.0 || font->scale_y != 1.0)
5262 FT_Matrix scaleMat;
5263 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5264 scaleMat.xy = 0;
5265 scaleMat.yx = 0;
5266 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5268 pFT_Matrix_Multiply(&scaleMat, &transMat);
5269 needsTransform = TRUE;
5272 /* Slant transform */
5273 if (font->fake_italic) {
5274 FT_Matrix slantMat;
5276 slantMat.xx = (1 << 16);
5277 slantMat.xy = ((1 << 16) >> 2);
5278 slantMat.yx = 0;
5279 slantMat.yy = (1 << 16);
5280 pFT_Matrix_Multiply(&slantMat, &transMat);
5281 needsTransform = TRUE;
5284 /* Rotation transform */
5285 transMatUnrotated = transMat;
5286 if(font->orientation && !tategaki) {
5287 FT_Matrix rotationMat;
5288 FT_Vector vecAngle;
5289 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5290 pFT_Vector_Unit(&vecAngle, angle);
5291 rotationMat.xx = vecAngle.x;
5292 rotationMat.xy = -vecAngle.y;
5293 rotationMat.yx = -rotationMat.xy;
5294 rotationMat.yy = rotationMat.xx;
5296 pFT_Matrix_Multiply(&rotationMat, &transMat);
5297 needsTransform = TRUE;
5300 /* World transform */
5301 if (!is_identity_FMAT2(&font->font_desc.matrix))
5303 FT_Matrix worldMat;
5304 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5305 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5306 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5307 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5308 pFT_Matrix_Multiply(&worldMat, &transMat);
5309 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5310 needsTransform = TRUE;
5313 /* Extra transformation specified by caller */
5314 if (!is_identity_MAT2(lpmat))
5316 FT_Matrix extraMat;
5317 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5318 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5319 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5320 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5321 pFT_Matrix_Multiply(&extraMat, &transMat);
5322 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5323 needsTransform = TRUE;
5326 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5327 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5328 format == GGO_GRAY8_BITMAP))
5330 load_flags |= FT_LOAD_NO_BITMAP;
5333 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5335 if(err) {
5336 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5337 return GDI_ERROR;
5340 if(!needsTransform) {
5341 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5342 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5343 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5345 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5346 bottom = (ft_face->glyph->metrics.horiBearingY -
5347 ft_face->glyph->metrics.height) & -64;
5348 lpgm->gmCellIncX = adv;
5349 lpgm->gmCellIncY = 0;
5350 } else {
5351 INT xc, yc;
5352 FT_Vector vec;
5354 left = right = 0;
5356 for(xc = 0; xc < 2; xc++) {
5357 for(yc = 0; yc < 2; yc++) {
5358 vec.x = (ft_face->glyph->metrics.horiBearingX +
5359 xc * ft_face->glyph->metrics.width);
5360 vec.y = ft_face->glyph->metrics.horiBearingY -
5361 yc * ft_face->glyph->metrics.height;
5362 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5363 pFT_Vector_Transform(&vec, &transMat);
5364 if(xc == 0 && yc == 0) {
5365 left = right = vec.x;
5366 top = bottom = vec.y;
5367 } else {
5368 if(vec.x < left) left = vec.x;
5369 else if(vec.x > right) right = vec.x;
5370 if(vec.y < bottom) bottom = vec.y;
5371 else if(vec.y > top) top = vec.y;
5375 left = left & -64;
5376 right = (right + 63) & -64;
5377 bottom = bottom & -64;
5378 top = (top + 63) & -64;
5380 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5381 vec.x = ft_face->glyph->metrics.horiAdvance;
5382 vec.y = 0;
5383 pFT_Vector_Transform(&vec, &transMat);
5384 lpgm->gmCellIncX = (vec.x+63) >> 6;
5385 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5387 vec.x = ft_face->glyph->metrics.horiAdvance;
5388 vec.y = 0;
5389 pFT_Vector_Transform(&vec, &transMatUnrotated);
5390 adv = (vec.x+63) >> 6;
5393 lsb = left >> 6;
5394 bbx = (right - left) >> 6;
5395 lpgm->gmBlackBoxX = (right - left) >> 6;
5396 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5397 lpgm->gmptGlyphOrigin.x = left >> 6;
5398 lpgm->gmptGlyphOrigin.y = top >> 6;
5400 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5401 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5402 lpgm->gmCellIncX, lpgm->gmCellIncY);
5404 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5405 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5407 FONT_GM(font,original_index)->gm = *lpgm;
5408 FONT_GM(font,original_index)->adv = adv;
5409 FONT_GM(font,original_index)->lsb = lsb;
5410 FONT_GM(font,original_index)->bbx = bbx;
5411 FONT_GM(font,original_index)->init = TRUE;
5414 if(format == GGO_METRICS)
5416 return 1; /* FIXME */
5419 if(ft_face->glyph->format != ft_glyph_format_outline &&
5420 (format == GGO_NATIVE || format == GGO_BEZIER))
5422 TRACE("loaded a bitmap\n");
5423 return GDI_ERROR;
5426 switch(format) {
5427 case GGO_BITMAP:
5428 width = lpgm->gmBlackBoxX;
5429 height = lpgm->gmBlackBoxY;
5430 pitch = ((width + 31) >> 5) << 2;
5431 needed = pitch * height;
5433 if(!buf || !buflen) break;
5435 switch(ft_face->glyph->format) {
5436 case ft_glyph_format_bitmap:
5438 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5439 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5440 INT h = ft_face->glyph->bitmap.rows;
5441 while(h--) {
5442 memcpy(dst, src, w);
5443 src += ft_face->glyph->bitmap.pitch;
5444 dst += pitch;
5446 break;
5449 case ft_glyph_format_outline:
5450 ft_bitmap.width = width;
5451 ft_bitmap.rows = height;
5452 ft_bitmap.pitch = pitch;
5453 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5454 ft_bitmap.buffer = buf;
5456 if(needsTransform)
5457 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5459 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5461 /* Note: FreeType will only set 'black' bits for us. */
5462 memset(buf, 0, needed);
5463 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5464 break;
5466 default:
5467 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5468 return GDI_ERROR;
5470 break;
5472 case GGO_GRAY2_BITMAP:
5473 case GGO_GRAY4_BITMAP:
5474 case GGO_GRAY8_BITMAP:
5475 case WINE_GGO_GRAY16_BITMAP:
5477 unsigned int max_level, row, col;
5478 BYTE *start, *ptr;
5480 width = lpgm->gmBlackBoxX;
5481 height = lpgm->gmBlackBoxY;
5482 pitch = (width + 3) / 4 * 4;
5483 needed = pitch * height;
5485 if(!buf || !buflen) break;
5487 max_level = get_max_level( format );
5489 switch(ft_face->glyph->format) {
5490 case ft_glyph_format_bitmap:
5492 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5493 INT h = ft_face->glyph->bitmap.rows;
5494 INT x;
5495 memset( buf, 0, needed );
5496 while(h--) {
5497 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5498 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5499 src += ft_face->glyph->bitmap.pitch;
5500 dst += pitch;
5502 return needed;
5504 case ft_glyph_format_outline:
5506 ft_bitmap.width = width;
5507 ft_bitmap.rows = height;
5508 ft_bitmap.pitch = pitch;
5509 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5510 ft_bitmap.buffer = buf;
5512 if(needsTransform)
5513 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5515 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5517 memset(ft_bitmap.buffer, 0, buflen);
5519 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5521 if (max_level != 255)
5523 for (row = 0, start = buf; row < height; row++)
5525 for (col = 0, ptr = start; col < width; col++, ptr++)
5526 *ptr = (((int)*ptr) * max_level + 128) / 256;
5527 start += pitch;
5530 return needed;
5533 default:
5534 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5535 return GDI_ERROR;
5537 break;
5540 case WINE_GGO_HRGB_BITMAP:
5541 case WINE_GGO_HBGR_BITMAP:
5542 case WINE_GGO_VRGB_BITMAP:
5543 case WINE_GGO_VBGR_BITMAP:
5544 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5546 switch (ft_face->glyph->format)
5548 case FT_GLYPH_FORMAT_BITMAP:
5550 BYTE *src, *dst;
5551 INT src_pitch, x;
5553 width = lpgm->gmBlackBoxX;
5554 height = lpgm->gmBlackBoxY;
5555 pitch = width * 4;
5556 needed = pitch * height;
5558 if (!buf || !buflen) break;
5560 memset(buf, 0, buflen);
5561 dst = buf;
5562 src = ft_face->glyph->bitmap.buffer;
5563 src_pitch = ft_face->glyph->bitmap.pitch;
5565 height = min( height, ft_face->glyph->bitmap.rows );
5566 while ( height-- )
5568 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5570 if ( src[x / 8] & masks[x % 8] )
5571 ((unsigned int *)dst)[x] = ~0u;
5573 src += src_pitch;
5574 dst += pitch;
5577 break;
5580 case FT_GLYPH_FORMAT_OUTLINE:
5582 unsigned int *dst;
5583 BYTE *src;
5584 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5585 INT x_shift, y_shift;
5586 BOOL rgb;
5587 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5588 FT_Render_Mode render_mode =
5589 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5590 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5592 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5594 if ( render_mode == FT_RENDER_MODE_LCD)
5596 lpgm->gmBlackBoxX += 2;
5597 lpgm->gmptGlyphOrigin.x -= 1;
5599 else
5601 lpgm->gmBlackBoxY += 2;
5602 lpgm->gmptGlyphOrigin.y += 1;
5606 width = lpgm->gmBlackBoxX;
5607 height = lpgm->gmBlackBoxY;
5608 pitch = width * 4;
5609 needed = pitch * height;
5611 if (!buf || !buflen) break;
5613 memset(buf, 0, buflen);
5614 dst = buf;
5615 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5617 if ( needsTransform )
5618 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5620 if ( pFT_Library_SetLcdFilter )
5621 pFT_Library_SetLcdFilter( library, lcdfilter );
5622 pFT_Render_Glyph (ft_face->glyph, render_mode);
5624 src = ft_face->glyph->bitmap.buffer;
5625 src_pitch = ft_face->glyph->bitmap.pitch;
5626 src_width = ft_face->glyph->bitmap.width;
5627 src_height = ft_face->glyph->bitmap.rows;
5629 if ( render_mode == FT_RENDER_MODE_LCD)
5631 rgb_interval = 1;
5632 hmul = 3;
5633 vmul = 1;
5635 else
5637 rgb_interval = src_pitch;
5638 hmul = 1;
5639 vmul = 3;
5642 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5643 if ( x_shift < 0 ) x_shift = 0;
5644 if ( x_shift + (src_width / hmul) > width )
5645 x_shift = width - (src_width / hmul);
5647 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5648 if ( y_shift < 0 ) y_shift = 0;
5649 if ( y_shift + (src_height / vmul) > height )
5650 y_shift = height - (src_height / vmul);
5652 dst += x_shift + y_shift * ( pitch / 4 );
5653 while ( src_height )
5655 for ( x = 0; x < src_width / hmul; x++ )
5657 if ( rgb )
5659 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5660 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5661 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5662 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5664 else
5666 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5667 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5668 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5669 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5672 src += src_pitch * vmul;
5673 dst += pitch / 4;
5674 src_height -= vmul;
5677 break;
5680 default:
5681 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5682 return GDI_ERROR;
5685 break;
5687 #else
5688 return GDI_ERROR;
5689 #endif
5691 case GGO_NATIVE:
5693 int contour, point = 0, first_pt;
5694 FT_Outline *outline = &ft_face->glyph->outline;
5695 TTPOLYGONHEADER *pph;
5696 TTPOLYCURVE *ppc;
5697 DWORD pph_start, cpfx, type;
5699 if(buflen == 0) buf = NULL;
5701 if (needsTransform && buf) {
5702 pFT_Outline_Transform(outline, &transMat);
5705 for(contour = 0; contour < outline->n_contours; contour++) {
5706 pph_start = needed;
5707 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5708 first_pt = point;
5709 if(buf) {
5710 pph->dwType = TT_POLYGON_TYPE;
5711 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5713 needed += sizeof(*pph);
5714 point++;
5715 while(point <= outline->contours[contour]) {
5716 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5717 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5718 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5719 cpfx = 0;
5720 do {
5721 if(buf)
5722 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5723 cpfx++;
5724 point++;
5725 } while(point <= outline->contours[contour] &&
5726 (outline->tags[point] & FT_Curve_Tag_On) ==
5727 (outline->tags[point-1] & FT_Curve_Tag_On));
5728 /* At the end of a contour Windows adds the start point, but
5729 only for Beziers */
5730 if(point > outline->contours[contour] &&
5731 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5732 if(buf)
5733 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5734 cpfx++;
5735 } else if(point <= outline->contours[contour] &&
5736 outline->tags[point] & FT_Curve_Tag_On) {
5737 /* add closing pt for bezier */
5738 if(buf)
5739 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5740 cpfx++;
5741 point++;
5743 if(buf) {
5744 ppc->wType = type;
5745 ppc->cpfx = cpfx;
5747 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5749 if(buf)
5750 pph->cb = needed - pph_start;
5752 break;
5754 case GGO_BEZIER:
5756 /* Convert the quadratic Beziers to cubic Beziers.
5757 The parametric eqn for a cubic Bezier is, from PLRM:
5758 r(t) = at^3 + bt^2 + ct + r0
5759 with the control points:
5760 r1 = r0 + c/3
5761 r2 = r1 + (c + b)/3
5762 r3 = r0 + c + b + a
5764 A quadratic Bezier has the form:
5765 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5767 So equating powers of t leads to:
5768 r1 = 2/3 p1 + 1/3 p0
5769 r2 = 2/3 p1 + 1/3 p2
5770 and of course r0 = p0, r3 = p2
5773 int contour, point = 0, first_pt;
5774 FT_Outline *outline = &ft_face->glyph->outline;
5775 TTPOLYGONHEADER *pph;
5776 TTPOLYCURVE *ppc;
5777 DWORD pph_start, cpfx, type;
5778 FT_Vector cubic_control[4];
5779 if(buflen == 0) buf = NULL;
5781 if (needsTransform && buf) {
5782 pFT_Outline_Transform(outline, &transMat);
5785 for(contour = 0; contour < outline->n_contours; contour++) {
5786 pph_start = needed;
5787 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5788 first_pt = point;
5789 if(buf) {
5790 pph->dwType = TT_POLYGON_TYPE;
5791 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5793 needed += sizeof(*pph);
5794 point++;
5795 while(point <= outline->contours[contour]) {
5796 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5797 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5798 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5799 cpfx = 0;
5800 do {
5801 if(type == TT_PRIM_LINE) {
5802 if(buf)
5803 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5804 cpfx++;
5805 point++;
5806 } else {
5807 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5808 so cpfx = 3n */
5810 /* FIXME: Possible optimization in endpoint calculation
5811 if there are two consecutive curves */
5812 cubic_control[0] = outline->points[point-1];
5813 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5814 cubic_control[0].x += outline->points[point].x + 1;
5815 cubic_control[0].y += outline->points[point].y + 1;
5816 cubic_control[0].x >>= 1;
5817 cubic_control[0].y >>= 1;
5819 if(point+1 > outline->contours[contour])
5820 cubic_control[3] = outline->points[first_pt];
5821 else {
5822 cubic_control[3] = outline->points[point+1];
5823 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5824 cubic_control[3].x += outline->points[point].x + 1;
5825 cubic_control[3].y += outline->points[point].y + 1;
5826 cubic_control[3].x >>= 1;
5827 cubic_control[3].y >>= 1;
5830 /* r1 = 1/3 p0 + 2/3 p1
5831 r2 = 1/3 p2 + 2/3 p1 */
5832 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5833 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5834 cubic_control[2] = cubic_control[1];
5835 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5836 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5837 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5838 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5839 if(buf) {
5840 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5841 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5842 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5844 cpfx += 3;
5845 point++;
5847 } while(point <= outline->contours[contour] &&
5848 (outline->tags[point] & FT_Curve_Tag_On) ==
5849 (outline->tags[point-1] & FT_Curve_Tag_On));
5850 /* At the end of a contour Windows adds the start point,
5851 but only for Beziers and we've already done that.
5853 if(point <= outline->contours[contour] &&
5854 outline->tags[point] & FT_Curve_Tag_On) {
5855 /* This is the closing pt of a bezier, but we've already
5856 added it, so just inc point and carry on */
5857 point++;
5859 if(buf) {
5860 ppc->wType = type;
5861 ppc->cpfx = cpfx;
5863 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5865 if(buf)
5866 pph->cb = needed - pph_start;
5868 break;
5871 default:
5872 FIXME("Unsupported format %d\n", format);
5873 return GDI_ERROR;
5875 return needed;
5878 static BOOL get_bitmap_text_metrics(GdiFont *font)
5880 FT_Face ft_face = font->ft_face;
5881 FT_WinFNT_HeaderRec winfnt_header;
5882 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5883 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5884 font->potm->otmSize = size;
5886 #define TM font->potm->otmTextMetrics
5887 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5889 TM.tmHeight = winfnt_header.pixel_height;
5890 TM.tmAscent = winfnt_header.ascent;
5891 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5892 TM.tmInternalLeading = winfnt_header.internal_leading;
5893 TM.tmExternalLeading = winfnt_header.external_leading;
5894 TM.tmAveCharWidth = winfnt_header.avg_width;
5895 TM.tmMaxCharWidth = winfnt_header.max_width;
5896 TM.tmWeight = winfnt_header.weight;
5897 TM.tmOverhang = 0;
5898 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5899 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5900 TM.tmFirstChar = winfnt_header.first_char;
5901 TM.tmLastChar = winfnt_header.last_char;
5902 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5903 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5904 TM.tmItalic = winfnt_header.italic;
5905 TM.tmUnderlined = font->underline;
5906 TM.tmStruckOut = font->strikeout;
5907 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5908 TM.tmCharSet = winfnt_header.charset;
5910 else
5912 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5913 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5914 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5915 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5916 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5917 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5918 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5919 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5920 TM.tmOverhang = 0;
5921 TM.tmDigitizedAspectX = 96; /* FIXME */
5922 TM.tmDigitizedAspectY = 96; /* FIXME */
5923 TM.tmFirstChar = 1;
5924 TM.tmLastChar = 255;
5925 TM.tmDefaultChar = 32;
5926 TM.tmBreakChar = 32;
5927 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5928 TM.tmUnderlined = font->underline;
5929 TM.tmStruckOut = font->strikeout;
5930 /* NB inverted meaning of TMPF_FIXED_PITCH */
5931 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5932 TM.tmCharSet = font->charset;
5934 #undef TM
5936 return TRUE;
5940 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5942 double scale_x, scale_y;
5944 if (font->aveWidth)
5946 scale_x = (double)font->aveWidth;
5947 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5949 else
5950 scale_x = font->scale_y;
5952 scale_x *= fabs(font->font_desc.matrix.eM11);
5953 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5955 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5956 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5958 SCALE_Y(ptm->tmHeight);
5959 SCALE_Y(ptm->tmAscent);
5960 SCALE_Y(ptm->tmDescent);
5961 SCALE_Y(ptm->tmInternalLeading);
5962 SCALE_Y(ptm->tmExternalLeading);
5963 SCALE_Y(ptm->tmOverhang);
5965 SCALE_X(ptm->tmAveCharWidth);
5966 SCALE_X(ptm->tmMaxCharWidth);
5968 #undef SCALE_X
5969 #undef SCALE_Y
5972 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5974 double scale_x, scale_y;
5976 if (font->aveWidth)
5978 scale_x = (double)font->aveWidth;
5979 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5981 else
5982 scale_x = font->scale_y;
5984 scale_x *= fabs(font->font_desc.matrix.eM11);
5985 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5987 scale_font_metrics(font, &potm->otmTextMetrics);
5989 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5990 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5992 SCALE_Y(potm->otmAscent);
5993 SCALE_Y(potm->otmDescent);
5994 SCALE_Y(potm->otmLineGap);
5995 SCALE_Y(potm->otmsCapEmHeight);
5996 SCALE_Y(potm->otmsXHeight);
5997 SCALE_Y(potm->otmrcFontBox.top);
5998 SCALE_Y(potm->otmrcFontBox.bottom);
5999 SCALE_X(potm->otmrcFontBox.left);
6000 SCALE_X(potm->otmrcFontBox.right);
6001 SCALE_Y(potm->otmMacAscent);
6002 SCALE_Y(potm->otmMacDescent);
6003 SCALE_Y(potm->otmMacLineGap);
6004 SCALE_X(potm->otmptSubscriptSize.x);
6005 SCALE_Y(potm->otmptSubscriptSize.y);
6006 SCALE_X(potm->otmptSubscriptOffset.x);
6007 SCALE_Y(potm->otmptSubscriptOffset.y);
6008 SCALE_X(potm->otmptSuperscriptSize.x);
6009 SCALE_Y(potm->otmptSuperscriptSize.y);
6010 SCALE_X(potm->otmptSuperscriptOffset.x);
6011 SCALE_Y(potm->otmptSuperscriptOffset.y);
6012 SCALE_Y(potm->otmsStrikeoutSize);
6013 SCALE_Y(potm->otmsStrikeoutPosition);
6014 SCALE_Y(potm->otmsUnderscoreSize);
6015 SCALE_Y(potm->otmsUnderscorePosition);
6017 #undef SCALE_X
6018 #undef SCALE_Y
6021 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6023 if(!font->potm)
6025 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6027 /* Make sure that the font has sane width/height ratio */
6028 if (font->aveWidth)
6030 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6032 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6033 font->aveWidth = 0;
6037 *ptm = font->potm->otmTextMetrics;
6038 scale_font_metrics(font, ptm);
6039 return TRUE;
6042 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6044 int i;
6046 for(i = 0; i < ft_face->num_charmaps; i++)
6048 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6049 return TRUE;
6051 return FALSE;
6054 static BOOL get_outline_text_metrics(GdiFont *font)
6056 BOOL ret = FALSE;
6057 FT_Face ft_face = font->ft_face;
6058 UINT needed, lenfam, lensty;
6059 TT_OS2 *pOS2;
6060 TT_HoriHeader *pHori;
6061 TT_Postscript *pPost;
6062 FT_Fixed x_scale, y_scale;
6063 WCHAR *family_nameW, *style_nameW;
6064 static const WCHAR spaceW[] = {' ', '\0'};
6065 char *cp;
6066 INT ascent, descent;
6068 TRACE("font=%p\n", font);
6070 if(!FT_IS_SCALABLE(ft_face))
6071 return FALSE;
6073 needed = sizeof(*font->potm);
6075 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6076 family_nameW = strdupW(font->name);
6078 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6079 * sizeof(WCHAR);
6080 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6081 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6082 style_nameW, lensty/sizeof(WCHAR));
6084 /* These names should be read from the TT name table */
6086 /* length of otmpFamilyName */
6087 needed += lenfam;
6089 /* length of otmpFaceName */
6090 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6091 needed += lenfam; /* just the family name */
6092 } else {
6093 needed += lenfam + lensty; /* family + " " + style */
6096 /* length of otmpStyleName */
6097 needed += lensty;
6099 /* length of otmpFullName */
6100 needed += lenfam + lensty;
6103 x_scale = ft_face->size->metrics.x_scale;
6104 y_scale = ft_face->size->metrics.y_scale;
6106 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6107 if(!pOS2) {
6108 FIXME("Can't find OS/2 table - not TT font?\n");
6109 goto end;
6112 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6113 if(!pHori) {
6114 FIXME("Can't find HHEA table - not TT font?\n");
6115 goto end;
6118 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6120 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",
6121 pOS2->usWinAscent, pOS2->usWinDescent,
6122 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6123 ft_face->ascender, ft_face->descender, ft_face->height,
6124 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6125 ft_face->bbox.yMax, ft_face->bbox.yMin);
6127 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6128 font->potm->otmSize = needed;
6130 #define TM font->potm->otmTextMetrics
6132 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6133 ascent = pHori->Ascender;
6134 descent = -pHori->Descender;
6135 } else {
6136 ascent = pOS2->usWinAscent;
6137 descent = pOS2->usWinDescent;
6140 if(font->yMax) {
6141 TM.tmAscent = font->yMax;
6142 TM.tmDescent = -font->yMin;
6143 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6144 } else {
6145 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6146 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6147 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6148 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6151 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6153 /* MSDN says:
6154 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6156 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6157 ((ascent + descent) -
6158 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6160 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6161 if (TM.tmAveCharWidth == 0) {
6162 TM.tmAveCharWidth = 1;
6164 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6165 TM.tmWeight = FW_REGULAR;
6166 if (font->fake_bold)
6167 TM.tmWeight = FW_BOLD;
6168 else
6170 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6172 if (pOS2->usWeightClass > FW_MEDIUM)
6173 TM.tmWeight = pOS2->usWeightClass;
6175 else if (pOS2->usWeightClass <= FW_MEDIUM)
6176 TM.tmWeight = pOS2->usWeightClass;
6178 TM.tmOverhang = 0;
6179 TM.tmDigitizedAspectX = 300;
6180 TM.tmDigitizedAspectY = 300;
6181 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6182 * symbol range to 0 - f0ff
6185 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6187 TM.tmFirstChar = 0;
6188 switch(GetACP())
6190 case 1257: /* Baltic */
6191 TM.tmLastChar = 0xf8fd;
6192 break;
6193 default:
6194 TM.tmLastChar = 0xf0ff;
6196 TM.tmBreakChar = 0x20;
6197 TM.tmDefaultChar = 0x1f;
6199 else
6201 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6202 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6204 if(pOS2->usFirstCharIndex <= 1)
6205 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6206 else if (pOS2->usFirstCharIndex > 0xff)
6207 TM.tmBreakChar = 0x20;
6208 else
6209 TM.tmBreakChar = pOS2->usFirstCharIndex;
6210 TM.tmDefaultChar = TM.tmBreakChar - 1;
6212 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6213 TM.tmUnderlined = font->underline;
6214 TM.tmStruckOut = font->strikeout;
6216 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6217 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6218 (pOS2->version == 0xFFFFU ||
6219 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6220 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6221 else
6222 TM.tmPitchAndFamily = 0;
6224 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6226 case PAN_FAMILY_SCRIPT:
6227 TM.tmPitchAndFamily |= FF_SCRIPT;
6228 break;
6230 case PAN_FAMILY_DECORATIVE:
6231 TM.tmPitchAndFamily |= FF_DECORATIVE;
6232 break;
6234 case PAN_ANY:
6235 case PAN_NO_FIT:
6236 case PAN_FAMILY_TEXT_DISPLAY:
6237 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6238 /* which is clearly not what the panose spec says. */
6239 default:
6240 if(TM.tmPitchAndFamily == 0 || /* fixed */
6241 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6242 TM.tmPitchAndFamily = FF_MODERN;
6243 else
6245 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6247 case PAN_ANY:
6248 case PAN_NO_FIT:
6249 default:
6250 TM.tmPitchAndFamily |= FF_DONTCARE;
6251 break;
6253 case PAN_SERIF_COVE:
6254 case PAN_SERIF_OBTUSE_COVE:
6255 case PAN_SERIF_SQUARE_COVE:
6256 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6257 case PAN_SERIF_SQUARE:
6258 case PAN_SERIF_THIN:
6259 case PAN_SERIF_BONE:
6260 case PAN_SERIF_EXAGGERATED:
6261 case PAN_SERIF_TRIANGLE:
6262 TM.tmPitchAndFamily |= FF_ROMAN;
6263 break;
6265 case PAN_SERIF_NORMAL_SANS:
6266 case PAN_SERIF_OBTUSE_SANS:
6267 case PAN_SERIF_PERP_SANS:
6268 case PAN_SERIF_FLARED:
6269 case PAN_SERIF_ROUNDED:
6270 TM.tmPitchAndFamily |= FF_SWISS;
6271 break;
6274 break;
6277 if(FT_IS_SCALABLE(ft_face))
6278 TM.tmPitchAndFamily |= TMPF_VECTOR;
6280 if(FT_IS_SFNT(ft_face))
6282 if (font->ntmFlags & NTM_PS_OPENTYPE)
6283 TM.tmPitchAndFamily |= TMPF_DEVICE;
6284 else
6285 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6288 TM.tmCharSet = font->charset;
6290 font->potm->otmFiller = 0;
6291 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6292 font->potm->otmfsSelection = pOS2->fsSelection;
6293 font->potm->otmfsType = pOS2->fsType;
6294 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6295 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6296 font->potm->otmItalicAngle = 0; /* POST table */
6297 font->potm->otmEMSquare = ft_face->units_per_EM;
6298 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6299 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6300 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6301 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6302 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6303 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6304 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6305 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6306 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6307 font->potm->otmMacAscent = TM.tmAscent;
6308 font->potm->otmMacDescent = -TM.tmDescent;
6309 font->potm->otmMacLineGap = font->potm->otmLineGap;
6310 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6311 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6312 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6313 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6314 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6315 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6316 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6317 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6318 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6319 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6320 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6321 if(!pPost) {
6322 font->potm->otmsUnderscoreSize = 0;
6323 font->potm->otmsUnderscorePosition = 0;
6324 } else {
6325 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6326 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6328 #undef TM
6330 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6331 cp = (char*)font->potm + sizeof(*font->potm);
6332 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6333 strcpyW((WCHAR*)cp, family_nameW);
6334 cp += lenfam;
6335 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6336 strcpyW((WCHAR*)cp, style_nameW);
6337 cp += lensty;
6338 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6339 strcpyW((WCHAR*)cp, family_nameW);
6340 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6341 strcatW((WCHAR*)cp, spaceW);
6342 strcatW((WCHAR*)cp, style_nameW);
6343 cp += lenfam + lensty;
6344 } else
6345 cp += lenfam;
6346 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6347 strcpyW((WCHAR*)cp, family_nameW);
6348 strcatW((WCHAR*)cp, spaceW);
6349 strcatW((WCHAR*)cp, style_nameW);
6350 ret = TRUE;
6352 end:
6353 HeapFree(GetProcessHeap(), 0, style_nameW);
6354 HeapFree(GetProcessHeap(), 0, family_nameW);
6355 return ret;
6358 /*************************************************************
6359 * freetype_GetGlyphOutline
6361 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6362 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6364 struct freetype_physdev *physdev = get_freetype_dev( dev );
6365 DWORD ret;
6367 if (!physdev->font)
6369 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6370 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6373 GDI_CheckNotLock();
6374 EnterCriticalSection( &freetype_cs );
6375 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6376 LeaveCriticalSection( &freetype_cs );
6377 return ret;
6380 /*************************************************************
6381 * freetype_GetTextMetrics
6383 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6385 struct freetype_physdev *physdev = get_freetype_dev( dev );
6386 BOOL ret;
6388 if (!physdev->font)
6390 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6391 return dev->funcs->pGetTextMetrics( dev, metrics );
6394 GDI_CheckNotLock();
6395 EnterCriticalSection( &freetype_cs );
6396 ret = get_text_metrics( physdev->font, metrics );
6397 LeaveCriticalSection( &freetype_cs );
6398 return ret;
6401 /*************************************************************
6402 * freetype_GetOutlineTextMetrics
6404 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6406 struct freetype_physdev *physdev = get_freetype_dev( dev );
6407 UINT ret = 0;
6409 if (!physdev->font)
6411 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6412 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6415 TRACE("font=%p\n", physdev->font);
6417 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6419 GDI_CheckNotLock();
6420 EnterCriticalSection( &freetype_cs );
6422 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6424 if(cbSize >= physdev->font->potm->otmSize)
6426 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6427 scale_outline_font_metrics(physdev->font, potm);
6429 ret = physdev->font->potm->otmSize;
6431 LeaveCriticalSection( &freetype_cs );
6432 return ret;
6435 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6437 HFONTLIST *hfontlist;
6438 child->font = alloc_font();
6439 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6440 if(!child->font->ft_face)
6442 free_font(child->font);
6443 child->font = NULL;
6444 return FALSE;
6447 child->font->font_desc = font->font_desc;
6448 child->font->ntmFlags = child->face->ntmFlags;
6449 child->font->orientation = font->orientation;
6450 child->font->scale_y = font->scale_y;
6451 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6452 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6453 child->font->name = strdupW(child->face->family->FamilyName);
6454 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6455 child->font->base_font = font;
6456 list_add_head(&child_font_list, &child->font->entry);
6457 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6458 return TRUE;
6461 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6463 FT_UInt g;
6464 CHILD_FONT *child_font;
6466 if(font->base_font)
6467 font = font->base_font;
6469 *linked_font = font;
6471 if((*glyph = get_glyph_index(font, c)))
6473 *glyph = get_GSUB_vert_glyph(font, *glyph);
6474 return TRUE;
6477 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6479 if(!child_font->font)
6480 if(!load_child_font(font, child_font))
6481 continue;
6483 if(!child_font->font->ft_face)
6484 continue;
6485 g = get_glyph_index(child_font->font, c);
6486 g = get_GSUB_vert_glyph(child_font->font, g);
6487 if(g)
6489 *glyph = g;
6490 *linked_font = child_font->font;
6491 return TRUE;
6494 return FALSE;
6497 /*************************************************************
6498 * freetype_GetCharWidth
6500 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6502 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6503 UINT c;
6504 GLYPHMETRICS gm;
6505 FT_UInt glyph_index;
6506 GdiFont *linked_font;
6507 struct freetype_physdev *physdev = get_freetype_dev( dev );
6509 if (!physdev->font)
6511 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6512 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6515 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6517 GDI_CheckNotLock();
6518 EnterCriticalSection( &freetype_cs );
6519 for(c = firstChar; c <= lastChar; c++) {
6520 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6521 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6522 &gm, 0, NULL, &identity);
6523 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6525 LeaveCriticalSection( &freetype_cs );
6526 return TRUE;
6529 /*************************************************************
6530 * freetype_GetCharABCWidths
6532 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6534 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6535 UINT c;
6536 GLYPHMETRICS gm;
6537 FT_UInt glyph_index;
6538 GdiFont *linked_font;
6539 struct freetype_physdev *physdev = get_freetype_dev( dev );
6541 if (!physdev->font)
6543 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6544 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6547 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6549 GDI_CheckNotLock();
6550 EnterCriticalSection( &freetype_cs );
6552 for(c = firstChar; c <= lastChar; c++) {
6553 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6554 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6555 &gm, 0, NULL, &identity);
6556 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6557 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6558 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6559 FONT_GM(linked_font,glyph_index)->bbx;
6561 LeaveCriticalSection( &freetype_cs );
6562 return TRUE;
6565 /*************************************************************
6566 * freetype_GetCharABCWidthsI
6568 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6570 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6571 UINT c;
6572 GLYPHMETRICS gm;
6573 FT_UInt glyph_index;
6574 GdiFont *linked_font;
6575 struct freetype_physdev *physdev = get_freetype_dev( dev );
6577 if (!physdev->font)
6579 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6580 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6583 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6584 return FALSE;
6586 GDI_CheckNotLock();
6587 EnterCriticalSection( &freetype_cs );
6589 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6590 if (!pgi)
6591 for(c = firstChar; c < firstChar+count; c++) {
6592 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6593 &gm, 0, NULL, &identity);
6594 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6595 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6596 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6597 - FONT_GM(linked_font,c)->bbx;
6599 else
6600 for(c = 0; c < count; c++) {
6601 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6602 &gm, 0, NULL, &identity);
6603 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6604 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6605 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6606 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6609 LeaveCriticalSection( &freetype_cs );
6610 return TRUE;
6613 /*************************************************************
6614 * freetype_GetTextExtentExPoint
6616 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6617 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6619 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6620 INT idx;
6621 INT nfit = 0, ext;
6622 GLYPHMETRICS gm;
6623 TEXTMETRICW tm;
6624 FT_UInt glyph_index;
6625 GdiFont *linked_font;
6626 struct freetype_physdev *physdev = get_freetype_dev( dev );
6628 if (!physdev->font)
6630 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6631 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6634 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6636 GDI_CheckNotLock();
6637 EnterCriticalSection( &freetype_cs );
6639 size->cx = 0;
6640 get_text_metrics( physdev->font, &tm );
6641 size->cy = tm.tmHeight;
6643 for(idx = 0; idx < count; idx++) {
6644 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6645 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6646 &gm, 0, NULL, &identity);
6647 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6648 ext = size->cx;
6649 if (! pnfit || ext <= max_ext) {
6650 ++nfit;
6651 if (dxs)
6652 dxs[idx] = ext;
6656 if (pnfit)
6657 *pnfit = nfit;
6659 LeaveCriticalSection( &freetype_cs );
6660 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6661 return TRUE;
6664 /*************************************************************
6665 * freetype_GetTextExtentExPointI
6667 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6668 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6670 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6671 INT idx;
6672 INT nfit = 0, ext;
6673 GLYPHMETRICS gm;
6674 TEXTMETRICW tm;
6675 struct freetype_physdev *physdev = get_freetype_dev( dev );
6677 if (!physdev->font)
6679 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6680 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6683 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6685 GDI_CheckNotLock();
6686 EnterCriticalSection( &freetype_cs );
6688 size->cx = 0;
6689 get_text_metrics(physdev->font, &tm);
6690 size->cy = tm.tmHeight;
6692 for(idx = 0; idx < count; idx++) {
6693 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6694 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6695 ext = size->cx;
6696 if (! pnfit || ext <= max_ext) {
6697 ++nfit;
6698 if (dxs)
6699 dxs[idx] = ext;
6703 if (pnfit)
6704 *pnfit = nfit;
6706 LeaveCriticalSection( &freetype_cs );
6707 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6708 return TRUE;
6711 /*************************************************************
6712 * freetype_GetFontData
6714 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6716 struct freetype_physdev *physdev = get_freetype_dev( dev );
6718 if (!physdev->font)
6720 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6721 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6724 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6725 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6726 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6728 return get_font_data( physdev->font, table, offset, buf, cbData );
6731 /*************************************************************
6732 * freetype_GetTextFace
6734 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6736 INT n;
6737 struct freetype_physdev *physdev = get_freetype_dev( dev );
6739 if (!physdev->font)
6741 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6742 return dev->funcs->pGetTextFace( dev, count, str );
6745 n = strlenW(physdev->font->name) + 1;
6746 if (str)
6748 lstrcpynW(str, physdev->font->name, count);
6749 n = min(count, n);
6751 return n;
6754 /*************************************************************
6755 * freetype_GetTextCharsetInfo
6757 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6759 struct freetype_physdev *physdev = get_freetype_dev( dev );
6761 if (!physdev->font)
6763 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6764 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6766 if (fs) *fs = physdev->font->fs;
6767 return physdev->font->charset;
6770 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6772 GdiFont *font = dc->gdiFont, *linked_font;
6773 struct list *first_hfont;
6774 BOOL ret;
6776 GDI_CheckNotLock();
6777 EnterCriticalSection( &freetype_cs );
6778 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6779 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6780 if(font == linked_font)
6781 *new_hfont = dc->hFont;
6782 else
6784 first_hfont = list_head(&linked_font->hfontlist);
6785 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6787 LeaveCriticalSection( &freetype_cs );
6788 return ret;
6791 /* Retrieve a list of supported Unicode ranges for a given font.
6792 * Can be called with NULL gs to calculate the buffer size. Returns
6793 * the number of ranges found.
6795 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6797 DWORD num_ranges = 0;
6799 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6801 FT_UInt glyph_code;
6802 FT_ULong char_code, char_code_prev;
6804 glyph_code = 0;
6805 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6807 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6808 face->num_glyphs, glyph_code, char_code);
6810 if (!glyph_code) return 0;
6812 if (gs)
6814 gs->ranges[0].wcLow = (USHORT)char_code;
6815 gs->ranges[0].cGlyphs = 0;
6816 gs->cGlyphsSupported = 0;
6819 num_ranges = 1;
6820 while (glyph_code)
6822 if (char_code < char_code_prev)
6824 ERR("expected increasing char code from FT_Get_Next_Char\n");
6825 return 0;
6827 if (char_code - char_code_prev > 1)
6829 num_ranges++;
6830 if (gs)
6832 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6833 gs->ranges[num_ranges - 1].cGlyphs = 1;
6834 gs->cGlyphsSupported++;
6837 else if (gs)
6839 gs->ranges[num_ranges - 1].cGlyphs++;
6840 gs->cGlyphsSupported++;
6842 char_code_prev = char_code;
6843 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6846 else
6847 FIXME("encoding %u not supported\n", face->charmap->encoding);
6849 return num_ranges;
6852 /*************************************************************
6853 * freetype_GetFontUnicodeRanges
6855 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6857 struct freetype_physdev *physdev = get_freetype_dev( dev );
6858 DWORD size, num_ranges;
6860 if (!physdev->font)
6862 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6863 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6866 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6867 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6868 if (glyphset)
6870 glyphset->cbThis = size;
6871 glyphset->cRanges = num_ranges;
6872 glyphset->flAccel = 0;
6874 return size;
6877 /*************************************************************
6878 * freetype_FontIsLinked
6880 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6882 struct freetype_physdev *physdev = get_freetype_dev( dev );
6883 BOOL ret;
6885 if (!physdev->font)
6887 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6888 return dev->funcs->pFontIsLinked( dev );
6891 GDI_CheckNotLock();
6892 EnterCriticalSection( &freetype_cs );
6893 ret = !list_empty(&physdev->font->child_fonts);
6894 LeaveCriticalSection( &freetype_cs );
6895 return ret;
6898 static BOOL is_hinting_enabled(void)
6900 /* Use the >= 2.2.0 function if available */
6901 if(pFT_Get_TrueType_Engine_Type)
6903 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6904 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6906 #ifdef FT_DRIVER_HAS_HINTER
6907 else
6909 FT_Module mod;
6911 /* otherwise if we've been compiled with < 2.2.0 headers
6912 use the internal macro */
6913 mod = pFT_Get_Module(library, "truetype");
6914 if(mod && FT_DRIVER_HAS_HINTER(mod))
6915 return TRUE;
6917 #endif
6919 return FALSE;
6922 static BOOL is_subpixel_rendering_enabled( void )
6924 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6925 return pFT_Library_SetLcdFilter &&
6926 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6927 #else
6928 return FALSE;
6929 #endif
6932 /*************************************************************************
6933 * GetRasterizerCaps (GDI32.@)
6935 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6937 static int hinting = -1;
6938 static int subpixel = -1;
6940 if(hinting == -1)
6942 hinting = is_hinting_enabled();
6943 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6946 if ( subpixel == -1 )
6948 subpixel = is_subpixel_rendering_enabled();
6949 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6952 lprs->nSize = sizeof(RASTERIZER_STATUS);
6953 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6954 if ( subpixel )
6955 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6956 lprs->nLanguageID = 0;
6957 return TRUE;
6960 /*************************************************************
6961 * freetype_GdiRealizationInfo
6963 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6965 struct freetype_physdev *physdev = get_freetype_dev( dev );
6966 realization_info_t *info = ptr;
6968 if (!physdev->font)
6970 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6971 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6974 FIXME("(%p, %p): stub!\n", physdev->font, info);
6976 info->flags = 1;
6977 if(FT_IS_SCALABLE(physdev->font->ft_face))
6978 info->flags |= 2;
6980 info->cache_num = physdev->font->cache_num;
6981 info->unknown2 = -1;
6982 return TRUE;
6985 /*************************************************************************
6986 * Kerning support for TrueType fonts
6988 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6990 struct TT_kern_table
6992 USHORT version;
6993 USHORT nTables;
6996 struct TT_kern_subtable
6998 USHORT version;
6999 USHORT length;
7000 union
7002 USHORT word;
7003 struct
7005 USHORT horizontal : 1;
7006 USHORT minimum : 1;
7007 USHORT cross_stream: 1;
7008 USHORT override : 1;
7009 USHORT reserved1 : 4;
7010 USHORT format : 8;
7011 } bits;
7012 } coverage;
7015 struct TT_format0_kern_subtable
7017 USHORT nPairs;
7018 USHORT searchRange;
7019 USHORT entrySelector;
7020 USHORT rangeShift;
7023 struct TT_kern_pair
7025 USHORT left;
7026 USHORT right;
7027 short value;
7030 static DWORD parse_format0_kern_subtable(GdiFont *font,
7031 const struct TT_format0_kern_subtable *tt_f0_ks,
7032 const USHORT *glyph_to_char,
7033 KERNINGPAIR *kern_pair, DWORD cPairs)
7035 USHORT i, nPairs;
7036 const struct TT_kern_pair *tt_kern_pair;
7038 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7040 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7042 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7043 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7044 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7046 if (!kern_pair || !cPairs)
7047 return nPairs;
7049 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7051 nPairs = min(nPairs, cPairs);
7053 for (i = 0; i < nPairs; i++)
7055 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7056 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7057 /* this algorithm appears to better match what Windows does */
7058 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7059 if (kern_pair->iKernAmount < 0)
7061 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7062 kern_pair->iKernAmount -= font->ppem;
7064 else if (kern_pair->iKernAmount > 0)
7066 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7067 kern_pair->iKernAmount += font->ppem;
7069 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7071 TRACE("left %u right %u value %d\n",
7072 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7074 kern_pair++;
7076 TRACE("copied %u entries\n", nPairs);
7077 return nPairs;
7080 /*************************************************************
7081 * freetype_GetKerningPairs
7083 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7085 DWORD length;
7086 void *buf;
7087 const struct TT_kern_table *tt_kern_table;
7088 const struct TT_kern_subtable *tt_kern_subtable;
7089 USHORT i, nTables;
7090 USHORT *glyph_to_char;
7091 GdiFont *font;
7092 struct freetype_physdev *physdev = get_freetype_dev( dev );
7094 if (!(font = physdev->font))
7096 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7097 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7100 GDI_CheckNotLock();
7101 EnterCriticalSection( &freetype_cs );
7102 if (font->total_kern_pairs != (DWORD)-1)
7104 if (cPairs && kern_pair)
7106 cPairs = min(cPairs, font->total_kern_pairs);
7107 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7109 else cPairs = font->total_kern_pairs;
7111 LeaveCriticalSection( &freetype_cs );
7112 return cPairs;
7115 font->total_kern_pairs = 0;
7117 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7119 if (length == GDI_ERROR)
7121 TRACE("no kerning data in the font\n");
7122 LeaveCriticalSection( &freetype_cs );
7123 return 0;
7126 buf = HeapAlloc(GetProcessHeap(), 0, length);
7127 if (!buf)
7129 WARN("Out of memory\n");
7130 LeaveCriticalSection( &freetype_cs );
7131 return 0;
7134 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7136 /* build a glyph index to char code map */
7137 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7138 if (!glyph_to_char)
7140 WARN("Out of memory allocating a glyph index to char code map\n");
7141 HeapFree(GetProcessHeap(), 0, buf);
7142 LeaveCriticalSection( &freetype_cs );
7143 return 0;
7146 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7148 FT_UInt glyph_code;
7149 FT_ULong char_code;
7151 glyph_code = 0;
7152 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7154 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7155 font->ft_face->num_glyphs, glyph_code, char_code);
7157 while (glyph_code)
7159 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7161 /* FIXME: This doesn't match what Windows does: it does some fancy
7162 * things with duplicate glyph index to char code mappings, while
7163 * we just avoid overriding existing entries.
7165 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7166 glyph_to_char[glyph_code] = (USHORT)char_code;
7168 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7171 else
7173 ULONG n;
7175 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7176 for (n = 0; n <= 65535; n++)
7177 glyph_to_char[n] = (USHORT)n;
7180 tt_kern_table = buf;
7181 nTables = GET_BE_WORD(tt_kern_table->nTables);
7182 TRACE("version %u, nTables %u\n",
7183 GET_BE_WORD(tt_kern_table->version), nTables);
7185 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7187 for (i = 0; i < nTables; i++)
7189 struct TT_kern_subtable tt_kern_subtable_copy;
7191 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7192 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7193 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7195 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7196 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7197 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7199 /* According to the TrueType specification this is the only format
7200 * that will be properly interpreted by Windows and OS/2
7202 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7204 DWORD new_chunk, old_total = font->total_kern_pairs;
7206 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7207 glyph_to_char, NULL, 0);
7208 font->total_kern_pairs += new_chunk;
7210 if (!font->kern_pairs)
7211 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7212 font->total_kern_pairs * sizeof(*font->kern_pairs));
7213 else
7214 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7215 font->total_kern_pairs * sizeof(*font->kern_pairs));
7217 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7218 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7220 else
7221 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7223 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7226 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7227 HeapFree(GetProcessHeap(), 0, buf);
7229 if (cPairs && kern_pair)
7231 cPairs = min(cPairs, font->total_kern_pairs);
7232 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7234 else cPairs = font->total_kern_pairs;
7236 LeaveCriticalSection( &freetype_cs );
7237 return cPairs;
7240 static const struct gdi_dc_funcs freetype_funcs =
7242 NULL, /* pAbortDoc */
7243 NULL, /* pAbortPath */
7244 NULL, /* pAlphaBlend */
7245 NULL, /* pAngleArc */
7246 NULL, /* pArc */
7247 NULL, /* pArcTo */
7248 NULL, /* pBeginPath */
7249 NULL, /* pBlendImage */
7250 NULL, /* pChoosePixelFormat */
7251 NULL, /* pChord */
7252 NULL, /* pCloseFigure */
7253 NULL, /* pCopyBitmap */
7254 NULL, /* pCreateBitmap */
7255 NULL, /* pCreateCompatibleDC */
7256 freetype_CreateDC, /* pCreateDC */
7257 NULL, /* pDeleteBitmap */
7258 freetype_DeleteDC, /* pDeleteDC */
7259 NULL, /* pDeleteObject */
7260 NULL, /* pDescribePixelFormat */
7261 NULL, /* pDeviceCapabilities */
7262 NULL, /* pEllipse */
7263 NULL, /* pEndDoc */
7264 NULL, /* pEndPage */
7265 NULL, /* pEndPath */
7266 freetype_EnumFonts, /* pEnumFonts */
7267 NULL, /* pEnumICMProfiles */
7268 NULL, /* pExcludeClipRect */
7269 NULL, /* pExtDeviceMode */
7270 NULL, /* pExtEscape */
7271 NULL, /* pExtFloodFill */
7272 NULL, /* pExtSelectClipRgn */
7273 NULL, /* pExtTextOut */
7274 NULL, /* pFillPath */
7275 NULL, /* pFillRgn */
7276 NULL, /* pFlattenPath */
7277 freetype_FontIsLinked, /* pFontIsLinked */
7278 NULL, /* pFrameRgn */
7279 NULL, /* pGdiComment */
7280 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7281 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7282 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7283 freetype_GetCharWidth, /* pGetCharWidth */
7284 NULL, /* pGetDeviceCaps */
7285 NULL, /* pGetDeviceGammaRamp */
7286 freetype_GetFontData, /* pGetFontData */
7287 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7288 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7289 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7290 NULL, /* pGetICMProfile */
7291 NULL, /* pGetImage */
7292 freetype_GetKerningPairs, /* pGetKerningPairs */
7293 NULL, /* pGetNearestColor */
7294 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7295 NULL, /* pGetPixel */
7296 NULL, /* pGetPixelFormat */
7297 NULL, /* pGetSystemPaletteEntries */
7298 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7299 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7300 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7301 freetype_GetTextFace, /* pGetTextFace */
7302 freetype_GetTextMetrics, /* pGetTextMetrics */
7303 NULL, /* pGradientFill */
7304 NULL, /* pIntersectClipRect */
7305 NULL, /* pInvertRgn */
7306 NULL, /* pLineTo */
7307 NULL, /* pModifyWorldTransform */
7308 NULL, /* pMoveTo */
7309 NULL, /* pOffsetClipRgn */
7310 NULL, /* pOffsetViewportOrg */
7311 NULL, /* pOffsetWindowOrg */
7312 NULL, /* pPaintRgn */
7313 NULL, /* pPatBlt */
7314 NULL, /* pPie */
7315 NULL, /* pPolyBezier */
7316 NULL, /* pPolyBezierTo */
7317 NULL, /* pPolyDraw */
7318 NULL, /* pPolyPolygon */
7319 NULL, /* pPolyPolyline */
7320 NULL, /* pPolygon */
7321 NULL, /* pPolyline */
7322 NULL, /* pPolylineTo */
7323 NULL, /* pPutImage */
7324 NULL, /* pRealizeDefaultPalette */
7325 NULL, /* pRealizePalette */
7326 NULL, /* pRectangle */
7327 NULL, /* pResetDC */
7328 NULL, /* pRestoreDC */
7329 NULL, /* pRoundRect */
7330 NULL, /* pSaveDC */
7331 NULL, /* pScaleViewportExt */
7332 NULL, /* pScaleWindowExt */
7333 NULL, /* pSelectBitmap */
7334 NULL, /* pSelectBrush */
7335 NULL, /* pSelectClipPath */
7336 freetype_SelectFont, /* pSelectFont */
7337 NULL, /* pSelectPalette */
7338 NULL, /* pSelectPen */
7339 NULL, /* pSetArcDirection */
7340 NULL, /* pSetBkColor */
7341 NULL, /* pSetBkMode */
7342 NULL, /* pSetDCBrushColor */
7343 NULL, /* pSetDCPenColor */
7344 NULL, /* pSetDIBColorTable */
7345 NULL, /* pSetDIBitsToDevice */
7346 NULL, /* pSetDeviceClipping */
7347 NULL, /* pSetDeviceGammaRamp */
7348 NULL, /* pSetLayout */
7349 NULL, /* pSetMapMode */
7350 NULL, /* pSetMapperFlags */
7351 NULL, /* pSetPixel */
7352 NULL, /* pSetPixelFormat */
7353 NULL, /* pSetPolyFillMode */
7354 NULL, /* pSetROP2 */
7355 NULL, /* pSetRelAbs */
7356 NULL, /* pSetStretchBltMode */
7357 NULL, /* pSetTextAlign */
7358 NULL, /* pSetTextCharacterExtra */
7359 NULL, /* pSetTextColor */
7360 NULL, /* pSetTextJustification */
7361 NULL, /* pSetViewportExt */
7362 NULL, /* pSetViewportOrg */
7363 NULL, /* pSetWindowExt */
7364 NULL, /* pSetWindowOrg */
7365 NULL, /* pSetWorldTransform */
7366 NULL, /* pStartDoc */
7367 NULL, /* pStartPage */
7368 NULL, /* pStretchBlt */
7369 NULL, /* pStretchDIBits */
7370 NULL, /* pStrokeAndFillPath */
7371 NULL, /* pStrokePath */
7372 NULL, /* pSwapBuffers */
7373 NULL, /* pUnrealizePalette */
7374 NULL, /* pWidenPath */
7375 /* OpenGL not supported */
7378 #else /* HAVE_FREETYPE */
7380 /*************************************************************************/
7382 BOOL WineEngInit(void)
7384 return FALSE;
7386 BOOL WineEngDestroyFontInstance(HFONT hfont)
7388 return FALSE;
7391 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7393 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7394 return 1;
7397 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7399 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7400 return TRUE;
7403 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7405 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7406 return NULL;
7409 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7411 return FALSE;
7414 /*************************************************************************
7415 * GetRasterizerCaps (GDI32.@)
7417 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7419 lprs->nSize = sizeof(RASTERIZER_STATUS);
7420 lprs->wFlags = 0;
7421 lprs->nLanguageID = 0;
7422 return TRUE;
7425 #endif /* HAVE_FREETYPE */