msi: Implement session object directly on top of automation object.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob37725a19592c2cfda78728f40ab9bf3278ea2f3d
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 /****************************************
536 * Notes on .fon files
538 * The fonts System, FixedSys and Terminal are special. There are typically multiple
539 * versions installed for different resolutions and codepages. Windows stores which one to use
540 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
541 * Key Meaning
542 * FIXEDFON.FON FixedSys
543 * FONTS.FON System
544 * OEMFONT.FON Terminal
545 * LogPixels Current dpi set by the display control panel applet
546 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
547 * also has a LogPixels value that appears to mirror this)
549 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
550 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
551 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
552 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
553 * so that makes sense.
555 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
556 * to be mapped into the registry on Windows 2000 at least).
557 * I have
558 * woafont=app850.fon
559 * ega80woa.fon=ega80850.fon
560 * ega40woa.fon=ega40850.fon
561 * cga80woa.fon=cga80850.fon
562 * cga40woa.fon=cga40850.fon
565 /* These are all structures needed for the GSUB table */
567 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
568 #define TATEGAKI_LOWER_BOUND 0x02F1
570 typedef struct {
571 DWORD version;
572 WORD ScriptList;
573 WORD FeatureList;
574 WORD LookupList;
575 } GSUB_Header;
577 typedef struct {
578 CHAR ScriptTag[4];
579 WORD Script;
580 } GSUB_ScriptRecord;
582 typedef struct {
583 WORD ScriptCount;
584 GSUB_ScriptRecord ScriptRecord[1];
585 } GSUB_ScriptList;
587 typedef struct {
588 CHAR LangSysTag[4];
589 WORD LangSys;
590 } GSUB_LangSysRecord;
592 typedef struct {
593 WORD DefaultLangSys;
594 WORD LangSysCount;
595 GSUB_LangSysRecord LangSysRecord[1];
596 } GSUB_Script;
598 typedef struct {
599 WORD LookupOrder; /* Reserved */
600 WORD ReqFeatureIndex;
601 WORD FeatureCount;
602 WORD FeatureIndex[1];
603 } GSUB_LangSys;
605 typedef struct {
606 CHAR FeatureTag[4];
607 WORD Feature;
608 } GSUB_FeatureRecord;
610 typedef struct {
611 WORD FeatureCount;
612 GSUB_FeatureRecord FeatureRecord[1];
613 } GSUB_FeatureList;
615 typedef struct {
616 WORD FeatureParams; /* Reserved */
617 WORD LookupCount;
618 WORD LookupListIndex[1];
619 } GSUB_Feature;
621 typedef struct {
622 WORD LookupCount;
623 WORD Lookup[1];
624 } GSUB_LookupList;
626 typedef struct {
627 WORD LookupType;
628 WORD LookupFlag;
629 WORD SubTableCount;
630 WORD SubTable[1];
631 } GSUB_LookupTable;
633 typedef struct {
634 WORD CoverageFormat;
635 WORD GlyphCount;
636 WORD GlyphArray[1];
637 } GSUB_CoverageFormat1;
639 typedef struct {
640 WORD Start;
641 WORD End;
642 WORD StartCoverageIndex;
643 } GSUB_RangeRecord;
645 typedef struct {
646 WORD CoverageFormat;
647 WORD RangeCount;
648 GSUB_RangeRecord RangeRecord[1];
649 } GSUB_CoverageFormat2;
651 typedef struct {
652 WORD SubstFormat; /* = 1 */
653 WORD Coverage;
654 WORD DeltaGlyphID;
655 } GSUB_SingleSubstFormat1;
657 typedef struct {
658 WORD SubstFormat; /* = 2 */
659 WORD Coverage;
660 WORD GlyphCount;
661 WORD Substitute[1];
662 }GSUB_SingleSubstFormat2;
664 #ifdef HAVE_CARBON_CARBON_H
665 static char *find_cache_dir(void)
667 FSRef ref;
668 OSErr err;
669 static char cached_path[MAX_PATH];
670 static const char *wine = "/Wine", *fonts = "/Fonts";
672 if(*cached_path) return cached_path;
674 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
675 if(err != noErr)
677 WARN("can't create cached data folder\n");
678 return NULL;
680 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
681 if(err != noErr)
683 WARN("can't create cached data path\n");
684 *cached_path = '\0';
685 return NULL;
687 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
689 ERR("Could not create full path\n");
690 *cached_path = '\0';
691 return NULL;
693 strcat(cached_path, wine);
695 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
697 WARN("Couldn't mkdir %s\n", cached_path);
698 *cached_path = '\0';
699 return NULL;
701 strcat(cached_path, fonts);
702 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
704 WARN("Couldn't mkdir %s\n", cached_path);
705 *cached_path = '\0';
706 return NULL;
708 return cached_path;
711 /******************************************************************
712 * expand_mac_font
714 * Extracts individual TrueType font files from a Mac suitcase font
715 * and saves them into the user's caches directory (see
716 * find_cache_dir()).
717 * Returns a NULL terminated array of filenames.
719 * We do this because they are apps that try to read ttf files
720 * themselves and they don't like Mac suitcase files.
722 static char **expand_mac_font(const char *path)
724 FSRef ref;
725 SInt16 res_ref;
726 OSStatus s;
727 unsigned int idx;
728 const char *out_dir;
729 const char *filename;
730 int output_len;
731 struct {
732 char **array;
733 unsigned int size, max_size;
734 } ret;
736 TRACE("path %s\n", path);
738 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
739 if(s != noErr)
741 WARN("failed to get ref\n");
742 return NULL;
745 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
746 if(s != noErr)
748 TRACE("no data fork, so trying resource fork\n");
749 res_ref = FSOpenResFile(&ref, fsRdPerm);
750 if(res_ref == -1)
752 TRACE("unable to open resource fork\n");
753 return NULL;
757 ret.size = 0;
758 ret.max_size = 10;
759 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
760 if(!ret.array)
762 CloseResFile(res_ref);
763 return NULL;
766 out_dir = find_cache_dir();
768 filename = strrchr(path, '/');
769 if(!filename) filename = path;
770 else filename++;
772 /* output filename has the form out_dir/filename_%04x.ttf */
773 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
775 UseResFile(res_ref);
776 idx = 1;
777 while(1)
779 FamRec *fam_rec;
780 unsigned short *num_faces_ptr, num_faces, face;
781 AsscEntry *assoc;
782 Handle fond;
783 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
785 fond = Get1IndResource(fond_res, idx);
786 if(!fond) break;
787 TRACE("got fond resource %d\n", idx);
788 HLock(fond);
790 fam_rec = *(FamRec**)fond;
791 num_faces_ptr = (unsigned short *)(fam_rec + 1);
792 num_faces = GET_BE_WORD(*num_faces_ptr);
793 num_faces++;
794 assoc = (AsscEntry*)(num_faces_ptr + 1);
795 TRACE("num faces %04x\n", num_faces);
796 for(face = 0; face < num_faces; face++, assoc++)
798 Handle sfnt;
799 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
800 unsigned short size, font_id;
801 char *output;
803 size = GET_BE_WORD(assoc->fontSize);
804 font_id = GET_BE_WORD(assoc->fontID);
805 if(size != 0)
807 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
808 continue;
811 TRACE("trying to load sfnt id %04x\n", font_id);
812 sfnt = GetResource(sfnt_res, font_id);
813 if(!sfnt)
815 TRACE("can't get sfnt resource %04x\n", font_id);
816 continue;
819 output = HeapAlloc(GetProcessHeap(), 0, output_len);
820 if(output)
822 int fd;
824 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
826 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
827 if(fd != -1 || errno == EEXIST)
829 if(fd != -1)
831 unsigned char *sfnt_data;
833 HLock(sfnt);
834 sfnt_data = *(unsigned char**)sfnt;
835 write(fd, sfnt_data, GetHandleSize(sfnt));
836 HUnlock(sfnt);
837 close(fd);
839 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
841 ret.max_size *= 2;
842 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
844 ret.array[ret.size++] = output;
846 else
848 WARN("unable to create %s\n", output);
849 HeapFree(GetProcessHeap(), 0, output);
852 ReleaseResource(sfnt);
854 HUnlock(fond);
855 ReleaseResource(fond);
856 idx++;
858 CloseResFile(res_ref);
860 return ret.array;
863 #endif /* HAVE_CARBON_CARBON_H */
865 static inline BOOL is_win9x(void)
867 return GetVersion() & 0x80000000;
870 This function builds an FT_Fixed from a double. It fails if the absolute
871 value of the float number is greater than 32768.
873 static inline FT_Fixed FT_FixedFromFloat(double f)
875 return f * 0x10000;
879 This function builds an FT_Fixed from a FIXED. It simply put f.value
880 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
882 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
884 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
888 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
890 Family *family;
891 Face *face;
892 const char *file;
893 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
894 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
896 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
897 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
899 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
901 if(face_name && strcmpiW(face_name, family->FamilyName))
902 continue;
903 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
905 if (!face->file)
906 continue;
907 file = strrchr(face->file, '/');
908 if(!file)
909 file = face->file;
910 else
911 file++;
912 if(!strcasecmp(file, file_nameA))
914 HeapFree(GetProcessHeap(), 0, file_nameA);
915 return face;
919 HeapFree(GetProcessHeap(), 0, file_nameA);
920 return NULL;
923 static Family *find_family_from_name(const WCHAR *name)
925 Family *family;
927 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
929 if(!strcmpiW(family->FamilyName, name))
930 return family;
933 return NULL;
936 static void DumpSubstList(void)
938 FontSubst *psub;
940 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
942 if(psub->from.charset != -1 || psub->to.charset != -1)
943 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
944 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
945 else
946 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
947 debugstr_w(psub->to.name));
949 return;
952 static LPWSTR strdupW(LPCWSTR p)
954 LPWSTR ret;
955 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
956 ret = HeapAlloc(GetProcessHeap(), 0, len);
957 memcpy(ret, p, len);
958 return ret;
961 static LPSTR strdupA(LPCSTR p)
963 LPSTR ret;
964 DWORD len = (strlen(p) + 1);
965 ret = HeapAlloc(GetProcessHeap(), 0, len);
966 memcpy(ret, p, len);
967 return ret;
970 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
971 INT from_charset)
973 FontSubst *element;
975 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
977 if(!strcmpiW(element->from.name, from_name) &&
978 (element->from.charset == from_charset ||
979 element->from.charset == -1))
980 return element;
983 return NULL;
986 #define ADD_FONT_SUBST_FORCE 1
988 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
990 FontSubst *from_exist, *to_exist;
992 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
994 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
996 list_remove(&from_exist->entry);
997 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
998 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
999 HeapFree(GetProcessHeap(), 0, from_exist);
1000 from_exist = NULL;
1003 if(!from_exist)
1005 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1007 if(to_exist)
1009 HeapFree(GetProcessHeap(), 0, subst->to.name);
1010 subst->to.name = strdupW(to_exist->to.name);
1013 list_add_tail(subst_list, &subst->entry);
1015 return TRUE;
1018 HeapFree(GetProcessHeap(), 0, subst->from.name);
1019 HeapFree(GetProcessHeap(), 0, subst->to.name);
1020 HeapFree(GetProcessHeap(), 0, subst);
1021 return FALSE;
1024 static WCHAR *towstr(UINT cp, const char *str)
1026 int len;
1027 WCHAR *wstr;
1029 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1030 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1031 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1032 return wstr;
1035 static void split_subst_info(NameCs *nc, LPSTR str)
1037 CHAR *p = strrchr(str, ',');
1039 nc->charset = -1;
1040 if(p && *(p+1)) {
1041 nc->charset = strtol(p+1, NULL, 10);
1042 *p = '\0';
1044 nc->name = towstr(CP_ACP, str);
1047 static void LoadSubstList(void)
1049 FontSubst *psub;
1050 HKEY hkey;
1051 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1052 LPSTR value;
1053 LPVOID data;
1055 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1056 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1057 &hkey) == ERROR_SUCCESS) {
1059 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1060 &valuelen, &datalen, NULL, NULL);
1062 valuelen++; /* returned value doesn't include room for '\0' */
1063 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1064 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1066 dlen = datalen;
1067 vlen = valuelen;
1068 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1069 &dlen) == ERROR_SUCCESS) {
1070 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1072 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1073 split_subst_info(&psub->from, value);
1074 split_subst_info(&psub->to, data);
1076 /* Win 2000 doesn't allow mapping between different charsets
1077 or mapping of DEFAULT_CHARSET */
1078 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1079 psub->to.charset == DEFAULT_CHARSET) {
1080 HeapFree(GetProcessHeap(), 0, psub->to.name);
1081 HeapFree(GetProcessHeap(), 0, psub->from.name);
1082 HeapFree(GetProcessHeap(), 0, psub);
1083 } else {
1084 add_font_subst(&font_subst_list, psub, 0);
1086 /* reset dlen and vlen */
1087 dlen = datalen;
1088 vlen = valuelen;
1090 HeapFree(GetProcessHeap(), 0, data);
1091 HeapFree(GetProcessHeap(), 0, value);
1092 RegCloseKey(hkey);
1097 /*****************************************************************
1098 * get_name_table_entry
1100 * Supply the platform, encoding, language and name ids in req
1101 * and if the name exists the function will fill in the string
1102 * and string_len members. The string is owned by FreeType so
1103 * don't free it. Returns TRUE if the name is found else FALSE.
1105 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1107 FT_SfntName name;
1108 FT_UInt num_names, name_index;
1110 if(FT_IS_SFNT(ft_face))
1112 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1114 for(name_index = 0; name_index < num_names; name_index++)
1116 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1118 if((name.platform_id == req->platform_id) &&
1119 (name.encoding_id == req->encoding_id) &&
1120 (name.language_id == req->language_id) &&
1121 (name.name_id == req->name_id))
1123 req->string = name.string;
1124 req->string_len = name.string_len;
1125 return TRUE;
1130 req->string = NULL;
1131 req->string_len = 0;
1132 return FALSE;
1135 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1137 WCHAR *ret = NULL;
1138 FT_SfntName name;
1140 name.platform_id = TT_PLATFORM_MICROSOFT;
1141 name.encoding_id = TT_MS_ID_UNICODE_CS;
1142 name.language_id = language_id;
1143 name.name_id = name_id;
1145 if(get_name_table_entry(ft_face, &name))
1147 FT_UInt i;
1149 /* String is not nul terminated and string_len is a byte length. */
1150 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1151 for(i = 0; i < name.string_len / 2; i++)
1153 WORD *tmp = (WORD *)&name.string[i * 2];
1154 ret[i] = GET_BE_WORD(*tmp);
1156 ret[i] = 0;
1157 TRACE("Got localised name %s\n", debugstr_w(ret));
1160 return ret;
1163 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1165 DWORD type, needed;
1166 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1167 if(r != ERROR_SUCCESS) return r;
1168 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1169 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1172 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1174 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1177 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1179 DWORD needed;
1180 DWORD num_strikes, max_strike_key_len;
1182 /* If we have a File Name key then this is a real font, not just the parent
1183 key of a bunch of non-scalable strikes */
1184 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1186 DWORD italic, bold;
1187 Face *face;
1188 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1189 face->cached_enum_data = NULL;
1191 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1192 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1194 face->StyleName = strdupW(face_name);
1195 face->family = family;
1197 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1199 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1200 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1201 face->FullName = fullName;
1203 else
1204 face->FullName = NULL;
1206 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1207 reg_load_dword(hkey_face, face_italic_value, &italic);
1208 reg_load_dword(hkey_face, face_bold_value, &bold);
1209 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1210 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1212 needed = sizeof(face->fs);
1213 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1214 memset(&face->fs_links, 0, sizeof(face->fs_links));
1216 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1218 face->scalable = TRUE;
1219 memset(&face->size, 0, sizeof(face->size));
1221 else
1223 face->scalable = FALSE;
1224 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1225 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1226 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1227 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1228 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1230 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1231 face->size.height, face->size.width, face->size.size >> 6,
1232 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1235 face->ntmFlags = 0;
1236 if (italic) face->ntmFlags |= NTM_ITALIC;
1237 if (bold) face->ntmFlags |= NTM_BOLD;
1238 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1240 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1241 face->fs.fsCsb[0], face->fs.fsCsb[1],
1242 face->fs.fsUsb[0], face->fs.fsUsb[1],
1243 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1245 if(!italic && !bold)
1246 list_add_head(&family->faces, &face->entry);
1247 else
1248 list_add_tail(&family->faces, &face->entry);
1250 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1253 /* do we have any bitmap strikes? */
1254 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1255 NULL, NULL, NULL, NULL);
1256 if(num_strikes != 0)
1258 WCHAR strike_name[10];
1259 DWORD strike_index = 0;
1261 needed = sizeof(strike_name) / sizeof(WCHAR);
1262 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1263 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1265 HKEY hkey_strike;
1266 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1267 load_face(hkey_strike, face_name, family);
1268 RegCloseKey(hkey_strike);
1269 needed = sizeof(strike_name) / sizeof(WCHAR);
1274 static void load_font_list_from_cache(HKEY hkey_font_cache)
1276 DWORD max_family_key_len, size;
1277 WCHAR *family_name;
1278 DWORD family_index = 0;
1279 Family *family;
1280 HKEY hkey_family;
1282 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1283 NULL, NULL, NULL, NULL);
1284 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1286 size = max_family_key_len + 1;
1287 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1288 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1290 WCHAR *english_family = NULL;
1291 DWORD face_index = 0;
1292 WCHAR *face_name;
1293 DWORD max_face_key_len;
1295 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1296 TRACE("opened family key %s\n", debugstr_w(family_name));
1297 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1299 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1300 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1303 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1304 family->FamilyName = strdupW(family_name);
1305 family->EnglishName = english_family;
1306 list_init(&family->faces);
1307 list_add_tail(&font_list, &family->entry);
1309 if(english_family)
1311 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1312 subst->from.name = strdupW(english_family);
1313 subst->from.charset = -1;
1314 subst->to.name = strdupW(family_name);
1315 subst->to.charset = -1;
1316 add_font_subst(&font_subst_list, subst, 0);
1319 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1320 NULL, NULL, NULL, NULL);
1322 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1323 size = max_face_key_len + 1;
1324 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1325 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1327 HKEY hkey_face;
1329 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1330 load_face(hkey_face, face_name, family);
1331 RegCloseKey(hkey_face);
1332 size = max_face_key_len + 1;
1334 HeapFree(GetProcessHeap(), 0, face_name);
1335 RegCloseKey(hkey_family);
1336 size = max_family_key_len + 1;
1339 HeapFree(GetProcessHeap(), 0, family_name);
1342 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1344 LONG ret;
1345 HKEY hkey_wine_fonts;
1347 /* We don't want to create the fonts key as volatile, so open this first */
1348 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1349 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1350 if(ret != ERROR_SUCCESS)
1352 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1353 return ret;
1356 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1357 KEY_ALL_ACCESS, NULL, hkey, disposition);
1358 RegCloseKey(hkey_wine_fonts);
1359 return ret;
1362 static void add_face_to_cache(Face *face)
1364 HKEY hkey_font_cache, hkey_family, hkey_face;
1365 WCHAR *face_key_name;
1367 create_font_cache_key(&hkey_font_cache, NULL);
1369 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1370 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1371 if(face->family->EnglishName)
1372 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1373 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1375 if(face->scalable)
1376 face_key_name = face->StyleName;
1377 else
1379 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1380 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1381 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1383 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1384 &hkey_face, NULL);
1385 if(!face->scalable)
1386 HeapFree(GetProcessHeap(), 0, face_key_name);
1388 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1389 if (face->FullName)
1390 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1391 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1393 reg_save_dword(hkey_face, face_index_value, face->face_index);
1394 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1395 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1396 reg_save_dword(hkey_face, face_version_value, face->font_version);
1397 reg_save_dword(hkey_face, face_external_value, face->external);
1399 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1401 if(!face->scalable)
1403 reg_save_dword(hkey_face, face_height_value, face->size.height);
1404 reg_save_dword(hkey_face, face_width_value, face->size.width);
1405 reg_save_dword(hkey_face, face_size_value, face->size.size);
1406 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1407 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1408 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1410 RegCloseKey(hkey_face);
1411 RegCloseKey(hkey_family);
1412 RegCloseKey(hkey_font_cache);
1415 static inline int TestStyles(DWORD flags, DWORD styles)
1417 return (flags & styles) == styles;
1420 static int StyleOrdering(Face *face)
1422 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1423 return 3;
1424 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1425 return 2;
1426 if (TestStyles(face->ntmFlags, NTM_BOLD))
1427 return 1;
1428 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1429 return 0;
1431 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1432 debugstr_w(face->family->FamilyName),
1433 debugstr_w(face->StyleName),
1434 face->ntmFlags);
1436 return 9999;
1439 /* Add a style of face to a font family using an ordering of the list such
1440 that regular fonts come before bold and italic, and single styles come
1441 before compound styles. */
1442 static void AddFaceToFamily(Face *face, Family *family)
1444 struct list *entry;
1446 LIST_FOR_EACH( entry, &family->faces )
1448 Face *ent = LIST_ENTRY(entry, Face, entry);
1449 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1451 list_add_before( entry, &face->entry );
1454 static WCHAR *prepend_at(WCHAR *family)
1456 WCHAR *str;
1458 if (!family)
1459 return NULL;
1461 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1462 str[0] = '@';
1463 strcpyW(str + 1, family);
1464 HeapFree(GetProcessHeap(), 0, family);
1465 return str;
1468 #define ADDFONT_EXTERNAL_FONT 0x01
1469 #define ADDFONT_FORCE_BITMAP 0x02
1470 #define ADDFONT_ADD_TO_CACHE 0x04
1472 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)
1474 int bitmap_num = 0;
1475 Family *family;
1476 WCHAR *StyleW;
1478 do {
1479 TT_OS2 *pOS2;
1480 TT_Header *pHeader;
1481 WCHAR *english_family, *localised_family;
1482 Face *face;
1483 struct list *face_elem_ptr;
1484 FT_WinFNT_HeaderRec winfnt_header;
1485 int internal_leading;
1486 FONTSIGNATURE fs;
1487 My_FT_Bitmap_Size *size = NULL;
1488 FT_ULong tmp_size;
1490 if(!FT_IS_SCALABLE(ft_face))
1491 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1493 if (fake_family)
1495 english_family = towstr(CP_ACP, fake_family);
1496 localised_family = NULL;
1498 else
1500 english_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1501 if (!english_family)
1502 english_family = towstr(CP_ACP, ft_face->family_name);
1504 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1505 if (localised_family && !strcmpiW(localised_family, english_family))
1507 HeapFree(GetProcessHeap(), 0, localised_family);
1508 localised_family = NULL;
1512 if (vertical)
1514 english_family = prepend_at(english_family);
1515 localised_family = prepend_at(localised_family);
1518 family = find_family_from_name(localised_family ? localised_family : english_family);
1519 if(!family) {
1520 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1521 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1522 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1523 list_init(&family->faces);
1524 list_add_tail(&font_list, &family->entry);
1526 if(localised_family) {
1527 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1528 subst->from.name = strdupW(english_family);
1529 subst->from.charset = -1;
1530 subst->to.name = strdupW(localised_family);
1531 subst->to.charset = -1;
1532 add_font_subst(&font_subst_list, subst, 0);
1535 HeapFree(GetProcessHeap(), 0, localised_family);
1536 HeapFree(GetProcessHeap(), 0, english_family);
1538 StyleW = towstr(CP_ACP, ft_face->style_name);
1540 internal_leading = 0;
1541 memset(&fs, 0, sizeof(fs));
1543 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1544 if(pOS2) {
1545 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1546 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1547 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1548 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1549 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1550 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1551 if(pOS2->version == 0) {
1552 FT_UInt dummy;
1554 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1555 fs.fsCsb[0] |= FS_LATIN1;
1556 else
1557 fs.fsCsb[0] |= FS_SYMBOL;
1560 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1561 CHARSETINFO csi;
1562 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1563 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1564 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1565 fs = csi.fs;
1566 internal_leading = winfnt_header.internal_leading;
1569 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1570 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1571 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1572 if(!strcmpiW(face->StyleName, StyleW) &&
1573 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1574 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1575 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1576 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1578 if(fake_family) {
1579 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1580 HeapFree(GetProcessHeap(), 0, StyleW);
1581 return;
1583 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1584 TRACE("Original font is newer so skipping this one\n");
1585 HeapFree(GetProcessHeap(), 0, StyleW);
1586 return;
1587 } else {
1588 TRACE("Replacing original with this one\n");
1589 list_remove(&face->entry);
1590 HeapFree(GetProcessHeap(), 0, face->file);
1591 HeapFree(GetProcessHeap(), 0, face->StyleName);
1592 HeapFree(GetProcessHeap(), 0, face->FullName);
1593 HeapFree(GetProcessHeap(), 0, face);
1594 break;
1598 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1599 face->cached_enum_data = NULL;
1600 face->StyleName = StyleW;
1601 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1602 if (file)
1604 face->file = strdupA(file);
1605 face->font_data_ptr = NULL;
1606 face->font_data_size = 0;
1608 else
1610 face->file = NULL;
1611 face->font_data_ptr = font_data_ptr;
1612 face->font_data_size = font_data_size;
1614 face->face_index = face_index;
1615 face->ntmFlags = 0;
1616 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1617 face->ntmFlags |= NTM_ITALIC;
1618 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1619 face->ntmFlags |= NTM_BOLD;
1620 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1621 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1622 face->family = family;
1623 face->vertical = vertical;
1624 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1625 face->fs = fs;
1626 memset(&face->fs_links, 0, sizeof(face->fs_links));
1628 if(FT_IS_SCALABLE(ft_face)) {
1629 memset(&face->size, 0, sizeof(face->size));
1630 face->scalable = TRUE;
1631 } else {
1632 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1633 size->height, size->width, size->size >> 6,
1634 size->x_ppem >> 6, size->y_ppem >> 6);
1635 face->size.height = size->height;
1636 face->size.width = size->width;
1637 face->size.size = size->size;
1638 face->size.x_ppem = size->x_ppem;
1639 face->size.y_ppem = size->y_ppem;
1640 face->size.internal_leading = internal_leading;
1641 face->scalable = FALSE;
1644 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1645 tmp_size = 0;
1646 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1648 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1649 face->ntmFlags |= NTM_PS_OPENTYPE;
1652 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1653 face->fs.fsCsb[0], face->fs.fsCsb[1],
1654 face->fs.fsUsb[0], face->fs.fsUsb[1],
1655 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1657 if(face->fs.fsCsb[0] == 0)
1659 int i;
1661 /* let's see if we can find any interesting cmaps */
1662 for(i = 0; i < ft_face->num_charmaps; i++) {
1663 switch(ft_face->charmaps[i]->encoding) {
1664 case FT_ENCODING_UNICODE:
1665 case FT_ENCODING_APPLE_ROMAN:
1666 face->fs.fsCsb[0] |= FS_LATIN1;
1667 break;
1668 case FT_ENCODING_MS_SYMBOL:
1669 face->fs.fsCsb[0] |= FS_SYMBOL;
1670 break;
1671 default:
1672 break;
1677 if(flags & ADDFONT_ADD_TO_CACHE)
1678 add_face_to_cache(face);
1680 AddFaceToFamily(face, family);
1682 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1684 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1685 debugstr_w(StyleW));
1688 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1690 FT_Face ft_face;
1691 TT_OS2 *pOS2;
1692 TT_Header *pHeader = NULL;
1693 WCHAR *localised_family;
1694 FT_Error err;
1695 FT_Long face_index = 0, num_faces;
1696 INT ret = 0;
1698 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1699 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1701 #ifdef HAVE_CARBON_CARBON_H
1702 if(file && !fake_family)
1704 char **mac_list = expand_mac_font(file);
1705 if(mac_list)
1707 BOOL had_one = FALSE;
1708 char **cursor;
1709 for(cursor = mac_list; *cursor; cursor++)
1711 had_one = TRUE;
1712 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1713 HeapFree(GetProcessHeap(), 0, *cursor);
1715 HeapFree(GetProcessHeap(), 0, mac_list);
1716 if(had_one)
1717 return 1;
1720 #endif /* HAVE_CARBON_CARBON_H */
1722 do {
1723 if (file)
1725 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1726 err = pFT_New_Face(library, file, face_index, &ft_face);
1727 } else
1729 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1730 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1733 if(err != 0) {
1734 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1735 return 0;
1738 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*/
1739 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1740 pFT_Done_Face(ft_face);
1741 return 0;
1744 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1745 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1746 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1747 pFT_Done_Face(ft_face);
1748 return 0;
1751 if(FT_IS_SFNT(ft_face))
1753 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1754 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1755 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1757 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1758 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1759 pFT_Done_Face(ft_face);
1760 return 0;
1763 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1764 we don't want to load these. */
1765 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1767 FT_ULong len = 0;
1769 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1771 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1772 pFT_Done_Face(ft_face);
1773 return 0;
1778 if(!ft_face->family_name || !ft_face->style_name) {
1779 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1780 pFT_Done_Face(ft_face);
1781 return 0;
1784 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1786 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1787 pFT_Done_Face(ft_face);
1788 return 0;
1791 if (target_family)
1793 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1794 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1796 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1797 HeapFree(GetProcessHeap(), 0, localised_family);
1798 num_faces = ft_face->num_faces;
1799 pFT_Done_Face(ft_face);
1800 continue;
1802 HeapFree(GetProcessHeap(), 0, localised_family);
1805 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1806 ++ret;
1808 if (FT_HAS_VERTICAL(ft_face))
1810 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1811 ++ret;
1814 num_faces = ft_face->num_faces;
1815 pFT_Done_Face(ft_face);
1816 } while(num_faces > ++face_index);
1817 return ret;
1820 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1822 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1825 static void DumpFontList(void)
1827 Family *family;
1828 Face *face;
1829 struct list *family_elem_ptr, *face_elem_ptr;
1831 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1832 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1833 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1834 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1835 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1836 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1837 if(!face->scalable)
1838 TRACE(" %d", face->size.height);
1839 TRACE("\n");
1842 return;
1845 /***********************************************************
1846 * The replacement list is a way to map an entire font
1847 * family onto another family. For example adding
1849 * [HKCU\Software\Wine\Fonts\Replacements]
1850 * "Wingdings"="Winedings"
1852 * would enumerate the Winedings font both as Winedings and
1853 * Wingdings. However if a real Wingdings font is present the
1854 * replacement does not take place.
1857 static void LoadReplaceList(void)
1859 HKEY hkey;
1860 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1861 LPWSTR value;
1862 LPVOID data;
1863 Family *family;
1864 Face *face;
1865 struct list *family_elem_ptr, *face_elem_ptr;
1866 CHAR familyA[400];
1868 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1869 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1871 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1872 &valuelen, &datalen, NULL, NULL);
1874 valuelen++; /* returned value doesn't include room for '\0' */
1875 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1876 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1878 dlen = datalen;
1879 vlen = valuelen;
1880 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1881 &dlen) == ERROR_SUCCESS) {
1882 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1883 /* "NewName"="Oldname" */
1884 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1886 if(!find_family_from_name(value))
1888 /* Find the old family and hence all of the font files
1889 in that family */
1890 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1891 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1892 if(!strcmpiW(family->FamilyName, data)) {
1893 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1894 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1895 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1896 debugstr_w(face->StyleName), familyA);
1897 /* Now add a new entry with the new family name */
1898 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1899 familyA, family->FamilyName,
1900 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1902 break;
1906 /* reset dlen and vlen */
1907 dlen = datalen;
1908 vlen = valuelen;
1910 HeapFree(GetProcessHeap(), 0, data);
1911 HeapFree(GetProcessHeap(), 0, value);
1912 RegCloseKey(hkey);
1916 /*************************************************************
1917 * init_system_links
1919 static BOOL init_system_links(void)
1921 HKEY hkey;
1922 BOOL ret = FALSE;
1923 DWORD type, max_val, max_data, val_len, data_len, index;
1924 WCHAR *value, *data;
1925 WCHAR *entry, *next;
1926 SYSTEM_LINKS *font_link, *system_font_link;
1927 CHILD_FONT *child_font;
1928 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1929 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1930 FONTSIGNATURE fs;
1931 Family *family;
1932 Face *face;
1933 FontSubst *psub;
1935 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1937 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1938 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1939 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1940 val_len = max_val + 1;
1941 data_len = max_data;
1942 index = 0;
1943 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1945 memset(&fs, 0, sizeof(fs));
1946 psub = get_font_subst(&font_subst_list, value, -1);
1947 /* Don't store fonts that are only substitutes for other fonts */
1948 if(psub)
1950 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1951 goto next;
1953 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1954 font_link->font_name = strdupW(value);
1955 list_init(&font_link->links);
1956 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1958 WCHAR *face_name;
1959 CHILD_FONT *child_font;
1961 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1963 next = entry + strlenW(entry) + 1;
1965 face_name = strchrW(entry, ',');
1966 if(face_name)
1968 *face_name++ = 0;
1969 while(isspaceW(*face_name))
1970 face_name++;
1972 psub = get_font_subst(&font_subst_list, face_name, -1);
1973 if(psub)
1974 face_name = psub->to.name;
1976 face = find_face_from_filename(entry, face_name);
1977 if(!face)
1979 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1980 continue;
1983 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1984 child_font->face = face;
1985 child_font->font = NULL;
1986 fs.fsCsb[0] |= face->fs.fsCsb[0];
1987 fs.fsCsb[1] |= face->fs.fsCsb[1];
1988 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1989 list_add_tail(&font_link->links, &child_font->entry);
1991 family = find_family_from_name(font_link->font_name);
1992 if(family)
1994 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1996 face->fs_links = fs;
1999 list_add_tail(&system_links, &font_link->entry);
2000 next:
2001 val_len = max_val + 1;
2002 data_len = max_data;
2005 HeapFree(GetProcessHeap(), 0, value);
2006 HeapFree(GetProcessHeap(), 0, data);
2007 RegCloseKey(hkey);
2010 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2011 that Tahoma has */
2013 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2014 system_font_link->font_name = strdupW(System);
2015 list_init(&system_font_link->links);
2017 face = find_face_from_filename(tahoma_ttf, Tahoma);
2018 if(face)
2020 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2021 child_font->face = face;
2022 child_font->font = NULL;
2023 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2024 list_add_tail(&system_font_link->links, &child_font->entry);
2026 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2028 if(!strcmpiW(font_link->font_name, Tahoma))
2030 CHILD_FONT *font_link_entry;
2031 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2033 CHILD_FONT *new_child;
2034 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2035 new_child->face = font_link_entry->face;
2036 new_child->font = NULL;
2037 list_add_tail(&system_font_link->links, &new_child->entry);
2039 break;
2042 list_add_tail(&system_links, &system_font_link->entry);
2043 return ret;
2046 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2048 DIR *dir;
2049 struct dirent *dent;
2050 char path[MAX_PATH];
2052 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2054 dir = opendir(dirname);
2055 if(!dir) {
2056 WARN("Can't open directory %s\n", debugstr_a(dirname));
2057 return FALSE;
2059 while((dent = readdir(dir)) != NULL) {
2060 struct stat statbuf;
2062 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2063 continue;
2065 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2067 sprintf(path, "%s/%s", dirname, dent->d_name);
2069 if(stat(path, &statbuf) == -1)
2071 WARN("Can't stat %s\n", debugstr_a(path));
2072 continue;
2074 if(S_ISDIR(statbuf.st_mode))
2075 ReadFontDir(path, external_fonts);
2076 else
2078 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2079 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2080 AddFontFileToList(path, NULL, NULL, addfont_flags);
2083 closedir(dir);
2084 return TRUE;
2087 static void load_fontconfig_fonts(void)
2089 #ifdef SONAME_LIBFONTCONFIG
2090 void *fc_handle = NULL;
2091 FcConfig *config;
2092 FcPattern *pat;
2093 FcObjectSet *os;
2094 FcFontSet *fontset;
2095 int i, len;
2096 char *file;
2097 const char *ext;
2099 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2100 if(!fc_handle) {
2101 TRACE("Wine cannot find the fontconfig library (%s).\n",
2102 SONAME_LIBFONTCONFIG);
2103 return;
2105 #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;}
2106 LOAD_FUNCPTR(FcConfigGetCurrent);
2107 LOAD_FUNCPTR(FcFontList);
2108 LOAD_FUNCPTR(FcFontSetDestroy);
2109 LOAD_FUNCPTR(FcInit);
2110 LOAD_FUNCPTR(FcObjectSetAdd);
2111 LOAD_FUNCPTR(FcObjectSetCreate);
2112 LOAD_FUNCPTR(FcObjectSetDestroy);
2113 LOAD_FUNCPTR(FcPatternCreate);
2114 LOAD_FUNCPTR(FcPatternDestroy);
2115 LOAD_FUNCPTR(FcPatternGetBool);
2116 LOAD_FUNCPTR(FcPatternGetString);
2117 #undef LOAD_FUNCPTR
2119 if(!pFcInit()) return;
2121 config = pFcConfigGetCurrent();
2122 pat = pFcPatternCreate();
2123 os = pFcObjectSetCreate();
2124 pFcObjectSetAdd(os, FC_FILE);
2125 pFcObjectSetAdd(os, FC_SCALABLE);
2126 fontset = pFcFontList(config, pat, os);
2127 if(!fontset) return;
2128 for(i = 0; i < fontset->nfont; i++) {
2129 FcBool scalable;
2131 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2132 continue;
2133 TRACE("fontconfig: %s\n", file);
2135 /* We're just interested in OT/TT fonts for now, so this hack just
2136 picks up the scalable fonts without extensions .pf[ab] to save time
2137 loading every other font */
2139 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2141 TRACE("not scalable\n");
2142 continue;
2145 len = strlen( file );
2146 if(len < 4) continue;
2147 ext = &file[ len - 3 ];
2148 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2149 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2151 pFcFontSetDestroy(fontset);
2152 pFcObjectSetDestroy(os);
2153 pFcPatternDestroy(pat);
2154 sym_not_found:
2155 #endif
2156 return;
2159 static BOOL load_font_from_data_dir(LPCWSTR file)
2161 BOOL ret = FALSE;
2162 const char *data_dir = wine_get_data_dir();
2164 if (!data_dir) data_dir = wine_get_build_dir();
2166 if (data_dir)
2168 INT len;
2169 char *unix_name;
2171 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2173 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2175 strcpy(unix_name, data_dir);
2176 strcat(unix_name, "/fonts/");
2178 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2180 EnterCriticalSection( &freetype_cs );
2181 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2182 LeaveCriticalSection( &freetype_cs );
2183 HeapFree(GetProcessHeap(), 0, unix_name);
2185 return ret;
2188 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2190 static const WCHAR slashW[] = {'\\','\0'};
2191 BOOL ret = FALSE;
2192 WCHAR windowsdir[MAX_PATH];
2193 char *unixname;
2195 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2196 strcatW(windowsdir, fontsW);
2197 strcatW(windowsdir, slashW);
2198 strcatW(windowsdir, file);
2199 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2200 EnterCriticalSection( &freetype_cs );
2201 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2202 LeaveCriticalSection( &freetype_cs );
2203 HeapFree(GetProcessHeap(), 0, unixname);
2205 return ret;
2208 static void load_system_fonts(void)
2210 HKEY hkey;
2211 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2212 const WCHAR * const *value;
2213 DWORD dlen, type;
2214 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2215 char *unixname;
2217 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2218 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2219 strcatW(windowsdir, fontsW);
2220 for(value = SystemFontValues; *value; value++) {
2221 dlen = sizeof(data);
2222 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2223 type == REG_SZ) {
2224 BOOL added = FALSE;
2226 sprintfW(pathW, fmtW, windowsdir, data);
2227 if((unixname = wine_get_unix_file_name(pathW))) {
2228 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2229 HeapFree(GetProcessHeap(), 0, unixname);
2231 if (!added)
2232 load_font_from_data_dir(data);
2235 RegCloseKey(hkey);
2239 /*************************************************************
2241 * This adds registry entries for any externally loaded fonts
2242 * (fonts from fontconfig or FontDirs). It also deletes entries
2243 * of no longer existing fonts.
2246 static void update_reg_entries(void)
2248 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2249 LPWSTR valueW;
2250 DWORD len, len_fam;
2251 Family *family;
2252 Face *face;
2253 struct list *family_elem_ptr, *face_elem_ptr;
2254 WCHAR *file;
2255 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2256 static const WCHAR spaceW[] = {' ', '\0'};
2257 char *path;
2259 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2260 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2261 ERR("Can't create Windows font reg key\n");
2262 goto end;
2265 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2266 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2267 ERR("Can't create Windows font reg key\n");
2268 goto end;
2271 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2272 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2273 ERR("Can't create external font reg key\n");
2274 goto end;
2277 /* enumerate the fonts and add external ones to the two keys */
2279 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2280 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2281 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2282 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2283 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2284 if(!face->external) continue;
2285 len = len_fam;
2286 if (!(face->ntmFlags & NTM_REGULAR))
2287 len = len_fam + strlenW(face->StyleName) + 1;
2288 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2289 strcpyW(valueW, family->FamilyName);
2290 if(len != len_fam) {
2291 strcatW(valueW, spaceW);
2292 strcatW(valueW, face->StyleName);
2294 strcatW(valueW, TrueType);
2296 file = wine_get_dos_file_name(face->file);
2297 if(file)
2298 len = strlenW(file) + 1;
2299 else
2301 if((path = strrchr(face->file, '/')) == NULL)
2302 path = face->file;
2303 else
2304 path++;
2305 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2307 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2308 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2310 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2311 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2312 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2314 HeapFree(GetProcessHeap(), 0, file);
2315 HeapFree(GetProcessHeap(), 0, valueW);
2318 end:
2319 if(external_key) RegCloseKey(external_key);
2320 if(win9x_key) RegCloseKey(win9x_key);
2321 if(winnt_key) RegCloseKey(winnt_key);
2322 return;
2325 static void delete_external_font_keys(void)
2327 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2328 DWORD dlen, vlen, datalen, valuelen, i, type;
2329 LPWSTR valueW;
2330 LPVOID data;
2332 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2333 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2334 ERR("Can't create Windows font reg key\n");
2335 goto end;
2338 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2339 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2340 ERR("Can't create Windows font reg key\n");
2341 goto end;
2344 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2345 ERR("Can't create external font reg key\n");
2346 goto end;
2349 /* Delete all external fonts added last time */
2351 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2352 &valuelen, &datalen, NULL, NULL);
2353 valuelen++; /* returned value doesn't include room for '\0' */
2354 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2355 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2357 dlen = datalen * sizeof(WCHAR);
2358 vlen = valuelen;
2359 i = 0;
2360 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2361 &dlen) == ERROR_SUCCESS) {
2363 RegDeleteValueW(winnt_key, valueW);
2364 RegDeleteValueW(win9x_key, valueW);
2365 /* reset dlen and vlen */
2366 dlen = datalen;
2367 vlen = valuelen;
2369 HeapFree(GetProcessHeap(), 0, data);
2370 HeapFree(GetProcessHeap(), 0, valueW);
2372 /* Delete the old external fonts key */
2373 RegCloseKey(external_key);
2374 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2376 end:
2377 if(win9x_key) RegCloseKey(win9x_key);
2378 if(winnt_key) RegCloseKey(winnt_key);
2381 /*************************************************************
2382 * WineEngAddFontResourceEx
2385 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2387 INT ret = 0;
2389 GDI_CheckNotLock();
2391 if (ft_handle) /* do it only if we have freetype up and running */
2393 char *unixname;
2395 if(flags)
2396 FIXME("Ignoring flags %x\n", flags);
2398 if((unixname = wine_get_unix_file_name(file)))
2400 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2402 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2403 EnterCriticalSection( &freetype_cs );
2404 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2405 LeaveCriticalSection( &freetype_cs );
2406 HeapFree(GetProcessHeap(), 0, unixname);
2408 if (!ret && !strchrW(file, '\\')) {
2409 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2410 ret = load_font_from_winfonts_dir(file);
2411 if (!ret) {
2412 /* Try in datadir/fonts (or builddir/fonts),
2413 * needed for Magic the Gathering Online
2415 ret = load_font_from_data_dir(file);
2419 return ret;
2422 /*************************************************************
2423 * WineEngAddFontMemResourceEx
2426 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2428 GDI_CheckNotLock();
2430 if (ft_handle) /* do it only if we have freetype up and running */
2432 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2434 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2435 memcpy(pFontCopy, pbFont, cbFont);
2437 EnterCriticalSection( &freetype_cs );
2438 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2439 LeaveCriticalSection( &freetype_cs );
2441 if (*pcFonts == 0)
2443 TRACE("AddFontToList failed\n");
2444 HeapFree(GetProcessHeap(), 0, pFontCopy);
2445 return 0;
2447 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2448 * For now return something unique but quite random
2450 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2451 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2454 *pcFonts = 0;
2455 return 0;
2458 /*************************************************************
2459 * WineEngRemoveFontResourceEx
2462 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2464 GDI_CheckNotLock();
2465 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2466 return TRUE;
2469 static const struct nls_update_font_list
2471 UINT ansi_cp, oem_cp;
2472 const char *oem, *fixed, *system;
2473 const char *courier, *serif, *small, *sserif;
2474 /* these are for font substitutes */
2475 const char *shelldlg, *tmsrmn;
2476 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2477 *helv_0, *tmsrmn_0;
2478 const struct subst
2480 const char *from, *to;
2481 } arial_0, courier_new_0, times_new_roman_0;
2482 } nls_update_font_list[] =
2484 /* Latin 1 (United States) */
2485 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2486 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2487 "Tahoma","Times New Roman",
2488 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2489 { 0 }, { 0 }, { 0 }
2491 /* Latin 1 (Multilingual) */
2492 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2493 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2494 "Tahoma","Times New Roman", /* FIXME unverified */
2495 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2496 { 0 }, { 0 }, { 0 }
2498 /* Eastern Europe */
2499 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2500 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2501 "Tahoma","Times New Roman", /* FIXME unverified */
2502 "Fixedsys,238", "System,238",
2503 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2504 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2505 { "Arial CE,0", "Arial,238" },
2506 { "Courier New CE,0", "Courier New,238" },
2507 { "Times New Roman CE,0", "Times New Roman,238" }
2509 /* Cyrillic */
2510 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2511 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2512 "Tahoma","Times New Roman", /* FIXME unverified */
2513 "Fixedsys,204", "System,204",
2514 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2515 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2516 { "Arial Cyr,0", "Arial,204" },
2517 { "Courier New Cyr,0", "Courier New,204" },
2518 { "Times New Roman Cyr,0", "Times New Roman,204" }
2520 /* Greek */
2521 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2522 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2523 "Tahoma","Times New Roman", /* FIXME unverified */
2524 "Fixedsys,161", "System,161",
2525 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2526 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2527 { "Arial Greek,0", "Arial,161" },
2528 { "Courier New Greek,0", "Courier New,161" },
2529 { "Times New Roman Greek,0", "Times New Roman,161" }
2531 /* Turkish */
2532 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2533 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2534 "Tahoma","Times New Roman", /* FIXME unverified */
2535 "Fixedsys,162", "System,162",
2536 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2537 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2538 { "Arial Tur,0", "Arial,162" },
2539 { "Courier New Tur,0", "Courier New,162" },
2540 { "Times New Roman Tur,0", "Times New Roman,162" }
2542 /* Hebrew */
2543 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2544 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2545 "Tahoma","Times New Roman", /* FIXME unverified */
2546 "Fixedsys,177", "System,177",
2547 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2548 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2549 { 0 }, { 0 }, { 0 }
2551 /* Arabic */
2552 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2553 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2554 "Tahoma","Times New Roman", /* FIXME unverified */
2555 "Fixedsys,178", "System,178",
2556 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2557 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2558 { 0 }, { 0 }, { 0 }
2560 /* Baltic */
2561 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2562 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2563 "Tahoma","Times New Roman", /* FIXME unverified */
2564 "Fixedsys,186", "System,186",
2565 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2566 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2567 { "Arial Baltic,0", "Arial,186" },
2568 { "Courier New Baltic,0", "Courier New,186" },
2569 { "Times New Roman Baltic,0", "Times New Roman,186" }
2571 /* Vietnamese */
2572 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2573 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2574 "Tahoma","Times New Roman", /* FIXME unverified */
2575 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2576 { 0 }, { 0 }, { 0 }
2578 /* Thai */
2579 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2580 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2581 "Tahoma","Times New Roman", /* FIXME unverified */
2582 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2583 { 0 }, { 0 }, { 0 }
2585 /* Japanese */
2586 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2587 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2588 "MS UI Gothic","MS Serif",
2589 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2590 { 0 }, { 0 }, { 0 }
2592 /* Chinese Simplified */
2593 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2594 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2595 "SimSun", "NSimSun",
2596 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2597 { 0 }, { 0 }, { 0 }
2599 /* Korean */
2600 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2601 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2602 "Gulim", "Batang",
2603 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2604 { 0 }, { 0 }, { 0 }
2606 /* Chinese Traditional */
2607 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2608 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2609 "PMingLiU", "MingLiU",
2610 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2611 { 0 }, { 0 }, { 0 }
2615 static const WCHAR *font_links_list[] =
2617 Lucida_Sans_Unicode,
2618 Microsoft_Sans_Serif,
2619 Tahoma
2622 static const struct font_links_defaults_list
2624 /* Keyed off substitution for "MS Shell Dlg" */
2625 const WCHAR *shelldlg;
2626 /* Maximum of four substitutes, plus terminating NULL pointer */
2627 const WCHAR *substitutes[5];
2628 } font_links_defaults_list[] =
2630 /* Non East-Asian */
2631 { Tahoma, /* FIXME unverified ordering */
2632 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2634 /* Below lists are courtesy of
2635 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2637 /* Japanese */
2638 { MS_UI_Gothic,
2639 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2641 /* Chinese Simplified */
2642 { SimSun,
2643 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2645 /* Korean */
2646 { Gulim,
2647 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2649 /* Chinese Traditional */
2650 { PMingLiU,
2651 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2655 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2657 return ( ansi_cp == 932 /* CP932 for Japanese */
2658 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2659 || ansi_cp == 949 /* CP949 for Korean */
2660 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2663 static inline HKEY create_fonts_NT_registry_key(void)
2665 HKEY hkey = 0;
2667 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2668 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2669 return hkey;
2672 static inline HKEY create_fonts_9x_registry_key(void)
2674 HKEY hkey = 0;
2676 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2677 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2678 return hkey;
2681 static inline HKEY create_config_fonts_registry_key(void)
2683 HKEY hkey = 0;
2685 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2686 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2687 return hkey;
2690 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2692 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2693 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2694 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2695 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2698 static void set_value_key(HKEY hkey, const char *name, const char *value)
2700 if (value)
2701 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2702 else if (name)
2703 RegDeleteValueA(hkey, name);
2706 static void update_font_info(void)
2708 char buf[40], cpbuf[40];
2709 DWORD len, type;
2710 HKEY hkey = 0;
2711 UINT i, ansi_cp = 0, oem_cp = 0;
2712 BOOL done = FALSE;
2714 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2715 return;
2717 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2718 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2719 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2720 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2721 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2723 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2724 if (is_dbcs_ansi_cp(ansi_cp))
2725 use_default_fallback = TRUE;
2727 len = sizeof(buf);
2728 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2730 if (!strcmp( buf, cpbuf )) /* already set correctly */
2732 RegCloseKey(hkey);
2733 return;
2735 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2737 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2739 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2740 RegCloseKey(hkey);
2742 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2744 HKEY hkey;
2746 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2747 nls_update_font_list[i].oem_cp == oem_cp)
2749 hkey = create_config_fonts_registry_key();
2750 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2751 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2752 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2753 RegCloseKey(hkey);
2755 hkey = create_fonts_NT_registry_key();
2756 add_font_list(hkey, &nls_update_font_list[i]);
2757 RegCloseKey(hkey);
2759 hkey = create_fonts_9x_registry_key();
2760 add_font_list(hkey, &nls_update_font_list[i]);
2761 RegCloseKey(hkey);
2763 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2765 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2766 strlen(nls_update_font_list[i].shelldlg)+1);
2767 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2768 strlen(nls_update_font_list[i].tmsrmn)+1);
2770 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2771 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2772 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2773 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2774 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2775 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2776 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2777 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2779 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2780 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2781 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2783 RegCloseKey(hkey);
2785 done = TRUE;
2787 else
2789 /* Delete the FontSubstitutes from other locales */
2790 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2792 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2793 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2794 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2795 RegCloseKey(hkey);
2799 if (!done)
2800 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2802 /* Clear out system links */
2803 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2806 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2808 const WCHAR *value;
2809 int i;
2810 FontSubst *psub;
2811 Family *family;
2812 Face *face;
2813 const char *file;
2814 WCHAR *fileW;
2815 WCHAR buff[MAX_PATH];
2816 WCHAR *data;
2817 int entryLen;
2819 static const WCHAR comma[] = {',',0};
2821 RegDeleteValueW(hkey, name);
2822 if (values)
2824 data = buff;
2825 data[0] = '\0';
2826 for (i = 0; values[i] != NULL; i++)
2828 value = values[i];
2829 if (!strcmpiW(name,value))
2830 continue;
2831 psub = get_font_subst(&font_subst_list, value, -1);
2832 if(psub)
2833 value = psub->to.name;
2834 family = find_family_from_name(value);
2835 if (!family)
2836 continue;
2837 file = NULL;
2838 /* Use first extant filename for this Family */
2839 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2841 if (!face->file)
2842 continue;
2843 file = strrchr(face->file, '/');
2844 if (!file)
2845 file = face->file;
2846 else
2847 file++;
2848 break;
2850 if (!file)
2851 continue;
2852 fileW = towstr(CP_UNIXCP, file);
2853 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2854 if (sizeof(buff)-(data-buff) < entryLen + 1)
2856 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2857 HeapFree(GetProcessHeap(), 0, fileW);
2858 break;
2860 strcpyW(data, fileW);
2861 strcatW(data, comma);
2862 strcatW(data, value);
2863 data += entryLen;
2864 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2865 HeapFree(GetProcessHeap(), 0, fileW);
2867 if (data != buff)
2869 *data='\0';
2870 data++;
2871 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2872 } else
2873 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2874 } else
2875 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2878 static void update_system_links(void)
2880 HKEY hkey = 0;
2881 UINT i, j;
2882 BOOL done = FALSE;
2883 DWORD disposition;
2884 FontSubst *psub;
2886 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2888 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2890 if (disposition == REG_OPENED_EXISTING_KEY)
2892 TRACE("SystemLink key already exists, doing nothing\n");
2893 RegCloseKey(hkey);
2894 return;
2897 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2898 if (!psub) {
2899 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2900 RegCloseKey(hkey);
2901 return;
2904 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2906 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2908 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2909 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2911 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2912 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2913 done = TRUE;
2915 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2917 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2920 RegCloseKey(hkey);
2921 if (!done)
2922 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2923 } else
2924 WARN("failed to create SystemLink key\n");
2928 static BOOL init_freetype(void)
2930 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2931 if(!ft_handle) {
2932 WINE_MESSAGE(
2933 "Wine cannot find the FreeType font library. To enable Wine to\n"
2934 "use TrueType fonts please install a version of FreeType greater than\n"
2935 "or equal to 2.0.5.\n"
2936 "http://www.freetype.org\n");
2937 return FALSE;
2940 #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;}
2942 LOAD_FUNCPTR(FT_Done_Face)
2943 LOAD_FUNCPTR(FT_Get_Char_Index)
2944 LOAD_FUNCPTR(FT_Get_First_Char)
2945 LOAD_FUNCPTR(FT_Get_Module)
2946 LOAD_FUNCPTR(FT_Get_Next_Char)
2947 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2948 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2949 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2950 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2951 LOAD_FUNCPTR(FT_Init_FreeType)
2952 LOAD_FUNCPTR(FT_Library_Version)
2953 LOAD_FUNCPTR(FT_Load_Glyph)
2954 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2955 LOAD_FUNCPTR(FT_Matrix_Multiply)
2956 #ifndef FT_MULFIX_INLINED
2957 LOAD_FUNCPTR(FT_MulFix)
2958 #endif
2959 LOAD_FUNCPTR(FT_New_Face)
2960 LOAD_FUNCPTR(FT_New_Memory_Face)
2961 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2962 LOAD_FUNCPTR(FT_Outline_Transform)
2963 LOAD_FUNCPTR(FT_Outline_Translate)
2964 LOAD_FUNCPTR(FT_Render_Glyph)
2965 LOAD_FUNCPTR(FT_Select_Charmap)
2966 LOAD_FUNCPTR(FT_Set_Charmap)
2967 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2968 LOAD_FUNCPTR(FT_Vector_Transform)
2969 LOAD_FUNCPTR(FT_Vector_Unit)
2970 #undef LOAD_FUNCPTR
2971 /* Don't warn if these ones are missing */
2972 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2973 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2974 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2975 #endif
2977 if(pFT_Init_FreeType(&library) != 0) {
2978 ERR("Can't init FreeType library\n");
2979 wine_dlclose(ft_handle, NULL, 0);
2980 ft_handle = NULL;
2981 return FALSE;
2983 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2985 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2986 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2987 ((FT_Version.minor << 8) & 0x00ff00) |
2988 ((FT_Version.patch ) & 0x0000ff);
2990 font_driver = &freetype_funcs;
2991 return TRUE;
2993 sym_not_found:
2994 WINE_MESSAGE(
2995 "Wine cannot find certain functions that it needs inside the FreeType\n"
2996 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2997 "FreeType to at least version 2.1.4.\n"
2998 "http://www.freetype.org\n");
2999 wine_dlclose(ft_handle, NULL, 0);
3000 ft_handle = NULL;
3001 return FALSE;
3004 static void init_font_list(void)
3006 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3007 static const WCHAR pathW[] = {'P','a','t','h',0};
3008 HKEY hkey;
3009 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3010 WCHAR windowsdir[MAX_PATH];
3011 char *unixname;
3012 const char *data_dir;
3014 delete_external_font_keys();
3016 /* load the system bitmap fonts */
3017 load_system_fonts();
3019 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3020 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3021 strcatW(windowsdir, fontsW);
3022 if((unixname = wine_get_unix_file_name(windowsdir)))
3024 ReadFontDir(unixname, FALSE);
3025 HeapFree(GetProcessHeap(), 0, unixname);
3028 /* load the system truetype fonts */
3029 data_dir = wine_get_data_dir();
3030 if (!data_dir) data_dir = wine_get_build_dir();
3031 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3033 strcpy(unixname, data_dir);
3034 strcat(unixname, "/fonts/");
3035 ReadFontDir(unixname, TRUE);
3036 HeapFree(GetProcessHeap(), 0, unixname);
3039 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3040 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3041 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3042 will skip these. */
3043 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3044 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3045 &hkey) == ERROR_SUCCESS)
3047 LPWSTR data, valueW;
3048 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3049 &valuelen, &datalen, NULL, NULL);
3051 valuelen++; /* returned value doesn't include room for '\0' */
3052 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3053 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3054 if (valueW && data)
3056 dlen = datalen * sizeof(WCHAR);
3057 vlen = valuelen;
3058 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3059 &dlen) == ERROR_SUCCESS)
3061 if(data[0] && (data[1] == ':'))
3063 if((unixname = wine_get_unix_file_name(data)))
3065 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3066 HeapFree(GetProcessHeap(), 0, unixname);
3069 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3071 WCHAR pathW[MAX_PATH];
3072 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3073 BOOL added = FALSE;
3075 sprintfW(pathW, fmtW, windowsdir, data);
3076 if((unixname = wine_get_unix_file_name(pathW)))
3078 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3079 HeapFree(GetProcessHeap(), 0, unixname);
3081 if (!added)
3082 load_font_from_data_dir(data);
3084 /* reset dlen and vlen */
3085 dlen = datalen;
3086 vlen = valuelen;
3089 HeapFree(GetProcessHeap(), 0, data);
3090 HeapFree(GetProcessHeap(), 0, valueW);
3091 RegCloseKey(hkey);
3094 load_fontconfig_fonts();
3096 /* then look in any directories that we've specified in the config file */
3097 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3098 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3100 DWORD len;
3101 LPWSTR valueW;
3102 LPSTR valueA, ptr;
3104 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3106 len += sizeof(WCHAR);
3107 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3108 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3110 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3111 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3112 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3113 TRACE( "got font path %s\n", debugstr_a(valueA) );
3114 ptr = valueA;
3115 while (ptr)
3117 const char* home;
3118 LPSTR next = strchr( ptr, ':' );
3119 if (next) *next++ = 0;
3120 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3121 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3123 strcpy( unixname, home );
3124 strcat( unixname, ptr + 1 );
3125 ReadFontDir( unixname, TRUE );
3126 HeapFree( GetProcessHeap(), 0, unixname );
3128 else
3129 ReadFontDir( ptr, TRUE );
3130 ptr = next;
3132 HeapFree( GetProcessHeap(), 0, valueA );
3134 HeapFree( GetProcessHeap(), 0, valueW );
3136 RegCloseKey(hkey);
3140 static BOOL move_to_front(const WCHAR *name)
3142 Family *family, *cursor2;
3143 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3145 if(!strcmpiW(family->FamilyName, name))
3147 list_remove(&family->entry);
3148 list_add_head(&font_list, &family->entry);
3149 return TRUE;
3152 return FALSE;
3155 static BOOL set_default(const WCHAR **name_list)
3157 while (*name_list)
3159 if (move_to_front(*name_list)) return TRUE;
3160 name_list++;
3163 return FALSE;
3166 static void reorder_font_list(void)
3168 set_default( default_serif_list );
3169 set_default( default_fixed_list );
3170 set_default( default_sans_list );
3173 /*************************************************************
3174 * WineEngInit
3176 * Initialize FreeType library and create a list of available faces
3178 BOOL WineEngInit(void)
3180 HKEY hkey_font_cache;
3181 DWORD disposition;
3182 HANDLE font_mutex;
3184 /* update locale dependent font info in registry */
3185 update_font_info();
3187 if(!init_freetype()) return FALSE;
3189 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3191 ERR("Failed to create font mutex\n");
3192 return FALSE;
3194 WaitForSingleObject(font_mutex, INFINITE);
3196 create_font_cache_key(&hkey_font_cache, &disposition);
3198 if(disposition == REG_CREATED_NEW_KEY)
3199 init_font_list();
3200 else
3201 load_font_list_from_cache(hkey_font_cache);
3203 RegCloseKey(hkey_font_cache);
3205 reorder_font_list();
3207 DumpFontList();
3208 LoadSubstList();
3209 DumpSubstList();
3210 LoadReplaceList();
3212 if(disposition == REG_CREATED_NEW_KEY)
3213 update_reg_entries();
3215 update_system_links();
3216 init_system_links();
3218 ReleaseMutex(font_mutex);
3219 return TRUE;
3223 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3225 TT_OS2 *pOS2;
3226 TT_HoriHeader *pHori;
3228 LONG ppem;
3230 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3231 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3233 if(height == 0) height = 16;
3235 /* Calc. height of EM square:
3237 * For +ve lfHeight we have
3238 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3239 * Re-arranging gives:
3240 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3242 * For -ve lfHeight we have
3243 * |lfHeight| = ppem
3244 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3245 * with il = winAscent + winDescent - units_per_em]
3249 if(height > 0) {
3250 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3251 ppem = MulDiv(ft_face->units_per_EM, height,
3252 pHori->Ascender - pHori->Descender);
3253 else
3254 ppem = MulDiv(ft_face->units_per_EM, height,
3255 pOS2->usWinAscent + pOS2->usWinDescent);
3257 else
3258 ppem = -height;
3260 return ppem;
3263 static struct font_mapping *map_font_file( const char *name )
3265 struct font_mapping *mapping;
3266 struct stat st;
3267 int fd;
3269 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3270 if (fstat( fd, &st ) == -1) goto error;
3272 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3274 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3276 mapping->refcount++;
3277 close( fd );
3278 return mapping;
3281 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3282 goto error;
3284 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3285 close( fd );
3287 if (mapping->data == MAP_FAILED)
3289 HeapFree( GetProcessHeap(), 0, mapping );
3290 return NULL;
3292 mapping->refcount = 1;
3293 mapping->dev = st.st_dev;
3294 mapping->ino = st.st_ino;
3295 mapping->size = st.st_size;
3296 list_add_tail( &mappings_list, &mapping->entry );
3297 return mapping;
3299 error:
3300 close( fd );
3301 return NULL;
3304 static void unmap_font_file( struct font_mapping *mapping )
3306 if (!--mapping->refcount)
3308 list_remove( &mapping->entry );
3309 munmap( mapping->data, mapping->size );
3310 HeapFree( GetProcessHeap(), 0, mapping );
3314 static LONG load_VDMX(GdiFont*, LONG);
3316 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3318 FT_Error err;
3319 FT_Face ft_face;
3320 void *data_ptr;
3321 DWORD data_size;
3323 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3325 if (face->file)
3327 if (!(font->mapping = map_font_file( face->file )))
3329 WARN("failed to map %s\n", debugstr_a(face->file));
3330 return 0;
3332 data_ptr = font->mapping->data;
3333 data_size = font->mapping->size;
3335 else
3337 data_ptr = face->font_data_ptr;
3338 data_size = face->font_data_size;
3341 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3342 if(err) {
3343 ERR("FT_New_Face rets %d\n", err);
3344 return 0;
3347 /* set it here, as load_VDMX needs it */
3348 font->ft_face = ft_face;
3350 if(FT_IS_SCALABLE(ft_face)) {
3351 /* load the VDMX table if we have one */
3352 font->ppem = load_VDMX(font, height);
3353 if(font->ppem == 0)
3354 font->ppem = calc_ppem_for_height(ft_face, height);
3355 TRACE("height %d => ppem %d\n", height, font->ppem);
3357 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3358 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3359 } else {
3360 font->ppem = height;
3361 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3362 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3364 return ft_face;
3368 static int get_nearest_charset(Face *face, int *cp)
3370 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3371 a single face with the requested charset. The idea is to check if
3372 the selected font supports the current ANSI codepage, if it does
3373 return the corresponding charset, else return the first charset */
3375 CHARSETINFO csi;
3376 int acp = GetACP(), i;
3377 DWORD fs0;
3379 *cp = acp;
3380 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3381 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3382 return csi.ciCharset;
3384 for(i = 0; i < 32; i++) {
3385 fs0 = 1L << i;
3386 if(face->fs.fsCsb[0] & fs0) {
3387 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3388 *cp = csi.ciACP;
3389 return csi.ciCharset;
3391 else
3392 FIXME("TCI failing on %x\n", fs0);
3396 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3397 face->fs.fsCsb[0], face->file);
3398 *cp = acp;
3399 return DEFAULT_CHARSET;
3402 static GdiFont *alloc_font(void)
3404 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3405 ret->gmsize = 1;
3406 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3407 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3408 ret->potm = NULL;
3409 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3410 ret->total_kern_pairs = (DWORD)-1;
3411 ret->kern_pairs = NULL;
3412 list_init(&ret->hfontlist);
3413 list_init(&ret->child_fonts);
3414 return ret;
3417 static void free_font(GdiFont *font)
3419 struct list *cursor, *cursor2;
3420 DWORD i;
3422 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3424 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3425 list_remove(cursor);
3426 if(child->font)
3427 free_font(child->font);
3428 HeapFree(GetProcessHeap(), 0, child);
3431 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3433 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3434 DeleteObject(hfontlist->hfont);
3435 list_remove(&hfontlist->entry);
3436 HeapFree(GetProcessHeap(), 0, hfontlist);
3439 if (font->ft_face) pFT_Done_Face(font->ft_face);
3440 if (font->mapping) unmap_font_file( font->mapping );
3441 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3442 HeapFree(GetProcessHeap(), 0, font->potm);
3443 HeapFree(GetProcessHeap(), 0, font->name);
3444 for (i = 0; i < font->gmsize; i++)
3445 HeapFree(GetProcessHeap(),0,font->gm[i]);
3446 HeapFree(GetProcessHeap(), 0, font->gm);
3447 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3448 HeapFree(GetProcessHeap(), 0, font);
3452 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3454 FT_Face ft_face = font->ft_face;
3455 FT_ULong len;
3456 FT_Error err;
3458 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3460 if(!buf)
3461 len = 0;
3462 else
3463 len = cbData;
3465 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3467 /* make sure value of len is the value freetype says it needs */
3468 if (buf && len)
3470 FT_ULong needed = 0;
3471 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3472 if( !err && needed < len) len = needed;
3474 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3475 if (err)
3477 TRACE("Can't find table %c%c%c%c\n",
3478 /* bytes were reversed */
3479 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3480 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3481 return GDI_ERROR;
3483 return len;
3486 /*************************************************************
3487 * load_VDMX
3489 * load the vdmx entry for the specified height
3492 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3493 ( ( (FT_ULong)_x4 << 24 ) | \
3494 ( (FT_ULong)_x3 << 16 ) | \
3495 ( (FT_ULong)_x2 << 8 ) | \
3496 (FT_ULong)_x1 )
3498 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3500 typedef struct {
3501 BYTE bCharSet;
3502 BYTE xRatio;
3503 BYTE yStartRatio;
3504 BYTE yEndRatio;
3505 } Ratios;
3507 typedef struct {
3508 WORD recs;
3509 BYTE startsz;
3510 BYTE endsz;
3511 } VDMX_group;
3513 static LONG load_VDMX(GdiFont *font, LONG height)
3515 WORD hdr[3], tmp;
3516 VDMX_group group;
3517 BYTE devXRatio, devYRatio;
3518 USHORT numRecs, numRatios;
3519 DWORD result, offset = -1;
3520 LONG ppem = 0;
3521 int i;
3523 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3525 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3526 return ppem;
3528 /* FIXME: need the real device aspect ratio */
3529 devXRatio = 1;
3530 devYRatio = 1;
3532 numRecs = GET_BE_WORD(hdr[1]);
3533 numRatios = GET_BE_WORD(hdr[2]);
3535 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3536 for(i = 0; i < numRatios; i++) {
3537 Ratios ratio;
3539 offset = (3 * 2) + (i * sizeof(Ratios));
3540 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3541 offset = -1;
3543 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3545 if((ratio.xRatio == 0 &&
3546 ratio.yStartRatio == 0 &&
3547 ratio.yEndRatio == 0) ||
3548 (devXRatio == ratio.xRatio &&
3549 devYRatio >= ratio.yStartRatio &&
3550 devYRatio <= ratio.yEndRatio))
3552 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3553 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3554 offset = GET_BE_WORD(tmp);
3555 break;
3559 if(offset == -1) {
3560 FIXME("No suitable ratio found\n");
3561 return ppem;
3564 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3565 USHORT recs;
3566 BYTE startsz, endsz;
3567 WORD *vTable;
3569 recs = GET_BE_WORD(group.recs);
3570 startsz = group.startsz;
3571 endsz = group.endsz;
3573 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3575 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3576 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3577 if(result == GDI_ERROR) {
3578 FIXME("Failed to retrieve vTable\n");
3579 goto end;
3582 if(height > 0) {
3583 for(i = 0; i < recs; i++) {
3584 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3585 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3586 ppem = GET_BE_WORD(vTable[i * 3]);
3588 if(yMax + -yMin == height) {
3589 font->yMax = yMax;
3590 font->yMin = yMin;
3591 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3592 break;
3594 if(yMax + -yMin > height) {
3595 if(--i < 0) {
3596 ppem = 0;
3597 goto end; /* failed */
3599 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3600 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3601 ppem = GET_BE_WORD(vTable[i * 3]);
3602 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3603 break;
3606 if(!font->yMax) {
3607 ppem = 0;
3608 TRACE("ppem not found for height %d\n", height);
3611 end:
3612 HeapFree(GetProcessHeap(), 0, vTable);
3615 return ppem;
3618 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3620 if(font->font_desc.hash != fd->hash) return TRUE;
3621 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3622 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3623 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3624 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3627 static void calc_hash(FONT_DESC *pfd)
3629 DWORD hash = 0, *ptr, two_chars;
3630 WORD *pwc;
3631 unsigned int i;
3633 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3634 hash ^= *ptr;
3635 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3636 hash ^= *ptr;
3637 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3638 two_chars = *ptr;
3639 pwc = (WCHAR *)&two_chars;
3640 if(!*pwc) break;
3641 *pwc = toupperW(*pwc);
3642 pwc++;
3643 *pwc = toupperW(*pwc);
3644 hash ^= two_chars;
3645 if(!*pwc) break;
3647 hash ^= !pfd->can_use_bitmap;
3648 pfd->hash = hash;
3649 return;
3652 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3654 GdiFont *ret;
3655 FONT_DESC fd;
3656 HFONTLIST *hflist;
3657 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3659 fd.lf = *plf;
3660 fd.matrix = *pmat;
3661 fd.can_use_bitmap = can_use_bitmap;
3662 calc_hash(&fd);
3664 /* try the child list */
3665 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3666 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3667 if(!fontcmp(ret, &fd)) {
3668 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3669 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3670 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3671 if(hflist->hfont == hfont)
3672 return ret;
3677 /* try the in-use list */
3678 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3679 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3680 if(!fontcmp(ret, &fd)) {
3681 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3682 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3683 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3684 if(hflist->hfont == hfont)
3685 return ret;
3687 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3688 hflist->hfont = hfont;
3689 list_add_head(&ret->hfontlist, &hflist->entry);
3690 return ret;
3694 /* then the unused list */
3695 font_elem_ptr = list_head(&unused_gdi_font_list);
3696 while(font_elem_ptr) {
3697 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3698 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3699 if(!fontcmp(ret, &fd)) {
3700 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3701 assert(list_empty(&ret->hfontlist));
3702 TRACE("Found %p in unused list\n", ret);
3703 list_remove(&ret->entry);
3704 list_add_head(&gdi_font_list, &ret->entry);
3705 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3706 hflist->hfont = hfont;
3707 list_add_head(&ret->hfontlist, &hflist->entry);
3708 return ret;
3711 return NULL;
3714 static void add_to_cache(GdiFont *font)
3716 static DWORD cache_num = 1;
3718 font->cache_num = cache_num++;
3719 list_add_head(&gdi_font_list, &font->entry);
3722 /*************************************************************
3723 * create_child_font_list
3725 static BOOL create_child_font_list(GdiFont *font)
3727 BOOL ret = FALSE;
3728 SYSTEM_LINKS *font_link;
3729 CHILD_FONT *font_link_entry, *new_child;
3730 FontSubst *psub;
3731 WCHAR* font_name;
3733 psub = get_font_subst(&font_subst_list, font->name, -1);
3734 font_name = psub ? psub->to.name : font->name;
3735 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3737 if(!strcmpiW(font_link->font_name, font_name))
3739 TRACE("found entry in system list\n");
3740 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3742 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3743 new_child->face = font_link_entry->face;
3744 new_child->font = NULL;
3745 list_add_tail(&font->child_fonts, &new_child->entry);
3746 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3748 ret = TRUE;
3749 break;
3753 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3754 * Sans Serif. This is how asian windows get default fallbacks for fonts
3756 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3757 font->charset != OEM_CHARSET &&
3758 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3759 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3761 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3763 TRACE("found entry in default fallback list\n");
3764 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3766 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3767 new_child->face = font_link_entry->face;
3768 new_child->font = NULL;
3769 list_add_tail(&font->child_fonts, &new_child->entry);
3770 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3772 ret = TRUE;
3773 break;
3777 return ret;
3780 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3782 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3784 if (pFT_Set_Charmap)
3786 FT_Int i;
3787 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3789 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3791 for (i = 0; i < ft_face->num_charmaps; i++)
3793 if (ft_face->charmaps[i]->encoding == encoding)
3795 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3796 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3798 switch (ft_face->charmaps[i]->platform_id)
3800 default:
3801 cmap_def = ft_face->charmaps[i];
3802 break;
3803 case 0: /* Apple Unicode */
3804 cmap0 = ft_face->charmaps[i];
3805 break;
3806 case 1: /* Macintosh */
3807 cmap1 = ft_face->charmaps[i];
3808 break;
3809 case 2: /* ISO */
3810 cmap2 = ft_face->charmaps[i];
3811 break;
3812 case 3: /* Microsoft */
3813 cmap3 = ft_face->charmaps[i];
3814 break;
3818 if (cmap3) /* prefer Microsoft cmap table */
3819 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3820 else if (cmap1)
3821 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3822 else if (cmap2)
3823 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3824 else if (cmap0)
3825 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3826 else if (cmap_def)
3827 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3829 return ft_err == FT_Err_Ok;
3832 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3836 /*************************************************************
3837 * freetype_CreateDC
3839 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3840 LPCWSTR output, const DEVMODEW *devmode )
3842 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3844 if (!physdev) return FALSE;
3845 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3846 return TRUE;
3850 /*************************************************************
3851 * freetype_DeleteDC
3853 static BOOL freetype_DeleteDC( PHYSDEV dev )
3855 struct freetype_physdev *physdev = get_freetype_dev( dev );
3856 HeapFree( GetProcessHeap(), 0, physdev );
3857 return TRUE;
3861 /*************************************************************
3862 * freetype_SelectFont
3864 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3866 struct freetype_physdev *physdev = get_freetype_dev( dev );
3867 GdiFont *ret;
3868 Face *face, *best, *best_bitmap;
3869 Family *family, *last_resort_family;
3870 struct list *family_elem_ptr, *face_elem_ptr;
3871 INT height, width = 0;
3872 unsigned int score = 0, new_score;
3873 signed int diff = 0, newdiff;
3874 BOOL bd, it, can_use_bitmap;
3875 LOGFONTW lf;
3876 CHARSETINFO csi;
3877 HFONTLIST *hflist;
3878 FMAT2 dcmat;
3879 FontSubst *psub = NULL;
3880 DC *dc = get_dc_ptr( dev->hdc );
3882 if (!hfont) /* notification that the font has been changed by another driver */
3884 dc->gdiFont = NULL;
3885 physdev->font = NULL;
3886 release_dc_ptr( dc );
3887 return 0;
3890 GetObjectW( hfont, sizeof(lf), &lf );
3891 lf.lfWidth = abs(lf.lfWidth);
3893 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3895 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3896 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3897 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3898 lf.lfEscapement);
3900 if(dc->GraphicsMode == GM_ADVANCED)
3901 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3902 else
3904 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3905 font scaling abilities. */
3906 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3907 dcmat.eM21 = dcmat.eM12 = 0;
3910 /* Try to avoid not necessary glyph transformations */
3911 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3913 lf.lfHeight *= fabs(dcmat.eM11);
3914 lf.lfWidth *= fabs(dcmat.eM11);
3915 dcmat.eM11 = dcmat.eM22 = 1.0;
3918 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3919 dcmat.eM21, dcmat.eM22);
3921 GDI_CheckNotLock();
3922 EnterCriticalSection( &freetype_cs );
3924 /* check the cache first */
3925 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3926 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3927 goto done;
3930 if(list_empty(&font_list)) /* No fonts installed */
3932 TRACE("No fonts installed\n");
3933 goto done;
3936 TRACE("not in cache\n");
3937 ret = alloc_font();
3939 ret->font_desc.matrix = dcmat;
3940 ret->font_desc.lf = lf;
3941 ret->font_desc.can_use_bitmap = can_use_bitmap;
3942 calc_hash(&ret->font_desc);
3943 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3944 hflist->hfont = hfont;
3945 list_add_head(&ret->hfontlist, &hflist->entry);
3947 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3948 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3949 original value lfCharSet. Note this is a special case for
3950 Symbol and doesn't happen at least for "Wingdings*" */
3952 if(!strcmpiW(lf.lfFaceName, SymbolW))
3953 lf.lfCharSet = SYMBOL_CHARSET;
3955 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3956 switch(lf.lfCharSet) {
3957 case DEFAULT_CHARSET:
3958 csi.fs.fsCsb[0] = 0;
3959 break;
3960 default:
3961 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3962 csi.fs.fsCsb[0] = 0;
3963 break;
3967 family = NULL;
3968 if(lf.lfFaceName[0] != '\0') {
3969 SYSTEM_LINKS *font_link;
3970 CHILD_FONT *font_link_entry;
3971 LPWSTR FaceName = lf.lfFaceName;
3973 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3975 if(psub) {
3976 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3977 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3978 if (psub->to.charset != -1)
3979 lf.lfCharSet = psub->to.charset;
3982 /* We want a match on name and charset or just name if
3983 charset was DEFAULT_CHARSET. If the latter then
3984 we fixup the returned charset later in get_nearest_charset
3985 where we'll either use the charset of the current ansi codepage
3986 or if that's unavailable the first charset that the font supports.
3988 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3989 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3990 if (!strcmpiW(family->FamilyName, FaceName) ||
3991 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3993 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3994 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3995 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3996 if(face->scalable || can_use_bitmap)
3997 goto found;
4002 /* Search by full face name. */
4003 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4004 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4005 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4006 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4007 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4008 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
4010 if(face->scalable || can_use_bitmap)
4011 goto found_face;
4017 * Try check the SystemLink list first for a replacement font.
4018 * We may find good replacements there.
4020 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4022 if(!strcmpiW(font_link->font_name, FaceName) ||
4023 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4025 TRACE("found entry in system list\n");
4026 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4028 face = font_link_entry->face;
4029 family = face->family;
4030 if(csi.fs.fsCsb[0] &
4031 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4033 if(face->scalable || can_use_bitmap)
4034 goto found;
4041 psub = NULL; /* substitution is no more relevant */
4043 /* If requested charset was DEFAULT_CHARSET then try using charset
4044 corresponding to the current ansi codepage */
4045 if (!csi.fs.fsCsb[0])
4047 INT acp = GetACP();
4048 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4049 FIXME("TCI failed on codepage %d\n", acp);
4050 csi.fs.fsCsb[0] = 0;
4051 } else
4052 lf.lfCharSet = csi.ciCharset;
4055 /* Face families are in the top 4 bits of lfPitchAndFamily,
4056 so mask with 0xF0 before testing */
4058 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4059 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4060 strcpyW(lf.lfFaceName, defFixed);
4061 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4062 strcpyW(lf.lfFaceName, defSerif);
4063 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4064 strcpyW(lf.lfFaceName, defSans);
4065 else
4066 strcpyW(lf.lfFaceName, defSans);
4067 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4068 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4069 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4070 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4071 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4072 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4073 if(face->scalable || can_use_bitmap)
4074 goto found;
4079 last_resort_family = NULL;
4080 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4081 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4082 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4083 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4084 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
4085 if(face->scalable)
4086 goto found;
4087 if(can_use_bitmap && !last_resort_family)
4088 last_resort_family = family;
4093 if(last_resort_family) {
4094 family = last_resort_family;
4095 csi.fs.fsCsb[0] = 0;
4096 goto found;
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->scalable) {
4104 csi.fs.fsCsb[0] = 0;
4105 WARN("just using first face for now\n");
4106 goto found;
4108 if(can_use_bitmap && !last_resort_family)
4109 last_resort_family = family;
4112 if(!last_resort_family) {
4113 FIXME("can't find a single appropriate font - bailing\n");
4114 free_font(ret);
4115 ret = NULL;
4116 goto done;
4119 WARN("could only find a bitmap font - this will probably look awful!\n");
4120 family = last_resort_family;
4121 csi.fs.fsCsb[0] = 0;
4123 found:
4124 it = lf.lfItalic ? 1 : 0;
4125 bd = lf.lfWeight > 550 ? 1 : 0;
4127 height = lf.lfHeight;
4129 face = best = best_bitmap = NULL;
4130 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4132 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4134 BOOL italic, bold;
4136 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4137 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4138 new_score = (italic ^ it) + (bold ^ bd);
4139 if(!best || new_score <= score)
4141 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4142 italic, bold, it, bd);
4143 score = new_score;
4144 best = face;
4145 if(best->scalable && score == 0) break;
4146 if(!best->scalable)
4148 if(height > 0)
4149 newdiff = height - (signed int)(best->size.height);
4150 else
4151 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4152 if(!best_bitmap || new_score < score ||
4153 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4155 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4156 diff = newdiff;
4157 best_bitmap = best;
4158 if(score == 0 && diff == 0) break;
4164 if(best)
4165 face = best->scalable ? best : best_bitmap;
4166 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4167 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4169 found_face:
4170 height = lf.lfHeight;
4172 ret->fs = face->fs;
4174 if(csi.fs.fsCsb[0]) {
4175 ret->charset = lf.lfCharSet;
4176 ret->codepage = csi.ciACP;
4178 else
4179 ret->charset = get_nearest_charset(face, &ret->codepage);
4181 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4182 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4184 ret->aveWidth = height ? lf.lfWidth : 0;
4186 if(!face->scalable) {
4187 /* Windows uses integer scaling factors for bitmap fonts */
4188 INT scale, scaled_height;
4189 GdiFont *cachedfont;
4191 /* FIXME: rotation of bitmap fonts is ignored */
4192 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4193 if (ret->aveWidth)
4194 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4195 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4196 dcmat.eM11 = dcmat.eM22 = 1.0;
4197 /* As we changed the matrix, we need to search the cache for the font again,
4198 * otherwise we might explode the cache. */
4199 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4200 TRACE("Found cached font after non-scalable matrix rescale!\n");
4201 free_font( ret );
4202 ret = cachedfont;
4203 goto done;
4205 calc_hash(&ret->font_desc);
4207 if (height != 0) height = diff;
4208 height += face->size.height;
4210 scale = (height + face->size.height - 1) / face->size.height;
4211 scaled_height = scale * face->size.height;
4212 /* Only jump to the next height if the difference <= 25% original height */
4213 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4214 /* The jump between unscaled and doubled is delayed by 1 */
4215 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4216 ret->scale_y = scale;
4218 width = face->size.x_ppem >> 6;
4219 height = face->size.y_ppem >> 6;
4221 else
4222 ret->scale_y = 1.0;
4223 TRACE("font scale y: %f\n", ret->scale_y);
4225 ret->ft_face = OpenFontFace(ret, face, width, height);
4227 if (!ret->ft_face)
4229 free_font( ret );
4230 ret = NULL;
4231 goto done;
4234 ret->ntmFlags = face->ntmFlags;
4236 if (ret->charset == SYMBOL_CHARSET &&
4237 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4238 /* No ops */
4240 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4241 /* No ops */
4243 else {
4244 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4247 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4248 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4249 ret->underline = lf.lfUnderline ? 0xff : 0;
4250 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4251 create_child_font_list(ret);
4253 if (face->vertical) /* We need to try to load the GSUB table */
4255 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4256 if (length != GDI_ERROR)
4258 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4259 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4260 TRACE("Loaded GSUB table of %i bytes\n",length);
4264 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4266 add_to_cache(ret);
4267 done:
4268 if (ret)
4270 dc->gdiFont = ret;
4271 physdev->font = ret;
4273 LeaveCriticalSection( &freetype_cs );
4274 release_dc_ptr( dc );
4275 return ret ? hfont : 0;
4278 static void dump_gdi_font_list(void)
4280 GdiFont *gdiFont;
4281 struct list *elem_ptr;
4283 TRACE("---------- gdiFont Cache ----------\n");
4284 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4285 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4286 TRACE("gdiFont=%p %s %d\n",
4287 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4290 TRACE("---------- Unused gdiFont Cache ----------\n");
4291 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4292 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4293 TRACE("gdiFont=%p %s %d\n",
4294 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4297 TRACE("---------- Child gdiFont Cache ----------\n");
4298 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4299 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4300 TRACE("gdiFont=%p %s %d\n",
4301 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4305 /*************************************************************
4306 * WineEngDestroyFontInstance
4308 * free the gdiFont associated with this handle
4311 BOOL WineEngDestroyFontInstance(HFONT handle)
4313 GdiFont *gdiFont;
4314 HFONTLIST *hflist;
4315 BOOL ret = FALSE;
4316 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4317 int i = 0;
4319 GDI_CheckNotLock();
4320 EnterCriticalSection( &freetype_cs );
4322 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4324 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4325 while(hfontlist_elem_ptr) {
4326 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4327 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4328 if(hflist->hfont == handle) {
4329 TRACE("removing child font %p from child list\n", gdiFont);
4330 list_remove(&gdiFont->entry);
4331 LeaveCriticalSection( &freetype_cs );
4332 return TRUE;
4337 TRACE("destroying hfont=%p\n", handle);
4338 if(TRACE_ON(font))
4339 dump_gdi_font_list();
4341 font_elem_ptr = list_head(&gdi_font_list);
4342 while(font_elem_ptr) {
4343 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4344 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4346 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4347 while(hfontlist_elem_ptr) {
4348 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4349 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4350 if(hflist->hfont == handle) {
4351 list_remove(&hflist->entry);
4352 HeapFree(GetProcessHeap(), 0, hflist);
4353 ret = TRUE;
4356 if(list_empty(&gdiFont->hfontlist)) {
4357 TRACE("Moving to Unused list\n");
4358 list_remove(&gdiFont->entry);
4359 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4364 font_elem_ptr = list_head(&unused_gdi_font_list);
4365 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4366 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4367 while(font_elem_ptr) {
4368 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4369 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4370 TRACE("freeing %p\n", gdiFont);
4371 list_remove(&gdiFont->entry);
4372 free_font(gdiFont);
4374 LeaveCriticalSection( &freetype_cs );
4375 return ret;
4378 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4380 HRSRC rsrc;
4381 HGLOBAL hMem;
4382 WCHAR *p;
4383 int i;
4385 id += IDS_FIRST_SCRIPT;
4386 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4387 if (!rsrc) return 0;
4388 hMem = LoadResource( gdi32_module, rsrc );
4389 if (!hMem) return 0;
4391 p = LockResource( hMem );
4392 id &= 0x000f;
4393 while (id--) p += *p + 1;
4395 i = min(LF_FACESIZE - 1, *p);
4396 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4397 buffer[i] = 0;
4398 return i;
4402 /***************************************************
4403 * create_enum_charset_list
4405 * This function creates charset enumeration list because in DEFAULT_CHARSET
4406 * case, the ANSI codepage's charset takes precedence over other charsets.
4407 * This function works as a filter other than DEFAULT_CHARSET case.
4409 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4411 CHARSETINFO csi;
4412 DWORD n = 0;
4414 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4415 csi.fs.fsCsb[0] != 0) {
4416 list->element[n].mask = csi.fs.fsCsb[0];
4417 list->element[n].charset = csi.ciCharset;
4418 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4419 n++;
4421 else { /* charset is DEFAULT_CHARSET or invalid. */
4422 INT acp, i;
4424 /* Set the current codepage's charset as the first element. */
4425 acp = GetACP();
4426 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4427 csi.fs.fsCsb[0] != 0) {
4428 list->element[n].mask = csi.fs.fsCsb[0];
4429 list->element[n].charset = csi.ciCharset;
4430 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4431 n++;
4434 /* Fill out left elements. */
4435 for (i = 0; i < 32; i++) {
4436 FONTSIGNATURE fs;
4437 fs.fsCsb[0] = 1L << i;
4438 fs.fsCsb[1] = 0;
4439 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4440 continue; /* skip, already added. */
4441 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4442 continue; /* skip, this is an invalid fsCsb bit. */
4444 list->element[n].mask = fs.fsCsb[0];
4445 list->element[n].charset = csi.ciCharset;
4446 load_script_name( i, list->element[n].name );
4447 n++;
4450 list->total = n;
4452 return n;
4455 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4456 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4458 GdiFont *font;
4459 LONG width, height;
4461 if (face->cached_enum_data)
4463 TRACE("Cached\n");
4464 *pelf = face->cached_enum_data->elf;
4465 *pntm = face->cached_enum_data->ntm;
4466 *ptype = face->cached_enum_data->type;
4467 return;
4470 font = alloc_font();
4472 if(face->scalable) {
4473 height = -2048; /* 2048 is the most common em size */
4474 width = 0;
4475 } else {
4476 height = face->size.y_ppem >> 6;
4477 width = face->size.x_ppem >> 6;
4479 font->scale_y = 1.0;
4481 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4483 free_font(font);
4484 return;
4487 font->name = strdupW(face->family->FamilyName);
4488 font->ntmFlags = face->ntmFlags;
4490 if (get_outline_text_metrics(font))
4492 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4494 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4496 lstrcpynW(pelf->elfLogFont.lfFaceName,
4497 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4498 LF_FACESIZE);
4499 lstrcpynW(pelf->elfFullName,
4500 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4501 LF_FULLFACESIZE);
4502 lstrcpynW(pelf->elfStyle,
4503 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4504 LF_FACESIZE);
4506 else
4508 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4510 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4512 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4513 if (face->FullName)
4514 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4515 else
4516 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4517 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4520 pntm->ntmTm.ntmFlags = face->ntmFlags;
4521 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4522 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4523 pntm->ntmFontSig = face->fs;
4525 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4527 pelf->elfLogFont.lfEscapement = 0;
4528 pelf->elfLogFont.lfOrientation = 0;
4529 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4530 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4531 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4532 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4533 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4534 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4535 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4536 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4537 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4538 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4539 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4541 *ptype = 0;
4542 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4543 *ptype |= TRUETYPE_FONTTYPE;
4544 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4545 *ptype |= DEVICE_FONTTYPE;
4546 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4547 *ptype |= RASTER_FONTTYPE;
4549 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4550 if (face->cached_enum_data)
4552 face->cached_enum_data->elf = *pelf;
4553 face->cached_enum_data->ntm = *pntm;
4554 face->cached_enum_data->type = *ptype;
4557 free_font(font);
4560 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4562 struct list *face_elem_ptr;
4564 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4566 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4568 static const WCHAR spaceW[] = { ' ',0 };
4569 WCHAR full_family_name[LF_FULLFACESIZE];
4570 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4572 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4574 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4575 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4576 continue;
4579 strcpyW(full_family_name, family->FamilyName);
4580 strcatW(full_family_name, spaceW);
4581 strcatW(full_family_name, face->StyleName);
4582 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4585 return FALSE;
4588 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4590 static const WCHAR spaceW[] = { ' ',0 };
4591 WCHAR full_family_name[LF_FULLFACESIZE];
4593 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4595 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4597 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4598 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4599 return FALSE;
4602 strcpyW(full_family_name, face->family->FamilyName);
4603 strcatW(full_family_name, spaceW);
4604 strcatW(full_family_name, face->StyleName);
4605 return !strcmpiW(lf->lfFaceName, full_family_name);
4608 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4609 FONTENUMPROCW proc, LPARAM lparam)
4611 ENUMLOGFONTEXW elf;
4612 NEWTEXTMETRICEXW ntm;
4613 DWORD type = 0;
4614 int i;
4616 GetEnumStructs(face, &elf, &ntm, &type);
4617 for(i = 0; i < list->total; i++) {
4618 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4619 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4620 load_script_name( IDS_OEM_DOS, elf.elfScript );
4621 i = list->total; /* break out of loop after enumeration */
4622 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4623 continue;
4624 else {
4625 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4626 strcpyW(elf.elfScript, list->element[i].name);
4627 if (!elf.elfScript[0])
4628 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4630 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4631 debugstr_w(elf.elfLogFont.lfFaceName),
4632 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4633 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4634 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4635 ntm.ntmTm.ntmFlags);
4636 /* release section before callback (FIXME) */
4637 LeaveCriticalSection( &freetype_cs );
4638 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4639 EnterCriticalSection( &freetype_cs );
4641 return TRUE;
4644 /*************************************************************
4645 * freetype_EnumFonts
4647 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4649 Family *family;
4650 Face *face;
4651 struct list *family_elem_ptr, *face_elem_ptr;
4652 LOGFONTW lf;
4653 struct enum_charset_list enum_charsets;
4655 if (!plf)
4657 lf.lfCharSet = DEFAULT_CHARSET;
4658 lf.lfPitchAndFamily = 0;
4659 lf.lfFaceName[0] = 0;
4660 plf = &lf;
4663 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4665 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4667 GDI_CheckNotLock();
4668 EnterCriticalSection( &freetype_cs );
4669 if(plf->lfFaceName[0]) {
4670 FontSubst *psub;
4671 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4673 if(psub) {
4674 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4675 debugstr_w(psub->to.name));
4676 lf = *plf;
4677 strcpyW(lf.lfFaceName, psub->to.name);
4678 plf = &lf;
4681 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4682 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4683 if(family_matches(family, plf)) {
4684 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4685 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4686 if (!face_matches(face, plf)) continue;
4687 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4691 } else {
4692 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4693 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4694 face_elem_ptr = list_head(&family->faces);
4695 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4696 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4699 LeaveCriticalSection( &freetype_cs );
4700 return TRUE;
4703 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4705 pt->x.value = vec->x >> 6;
4706 pt->x.fract = (vec->x & 0x3f) << 10;
4707 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4708 pt->y.value = vec->y >> 6;
4709 pt->y.fract = (vec->y & 0x3f) << 10;
4710 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4711 return;
4714 /***************************************************
4715 * According to the MSDN documentation on WideCharToMultiByte,
4716 * certain codepages cannot set the default_used parameter.
4717 * This returns TRUE if the codepage can set that parameter, false else
4718 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4720 static BOOL codepage_sets_default_used(UINT codepage)
4722 switch (codepage)
4724 case CP_UTF7:
4725 case CP_UTF8:
4726 case CP_SYMBOL:
4727 return FALSE;
4728 default:
4729 return TRUE;
4734 * GSUB Table handling functions
4737 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4739 const GSUB_CoverageFormat1* cf1;
4741 cf1 = table;
4743 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4745 int count = GET_BE_WORD(cf1->GlyphCount);
4746 int i;
4747 TRACE("Coverage Format 1, %i glyphs\n",count);
4748 for (i = 0; i < count; i++)
4749 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4750 return i;
4751 return -1;
4753 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4755 const GSUB_CoverageFormat2* cf2;
4756 int i;
4757 int count;
4758 cf2 = (const GSUB_CoverageFormat2*)cf1;
4760 count = GET_BE_WORD(cf2->RangeCount);
4761 TRACE("Coverage Format 2, %i ranges\n",count);
4762 for (i = 0; i < count; i++)
4764 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4765 return -1;
4766 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4767 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4769 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4770 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4773 return -1;
4775 else
4776 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4778 return -1;
4781 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4783 const GSUB_ScriptList *script;
4784 const GSUB_Script *deflt = NULL;
4785 int i;
4786 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4788 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4789 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4791 const GSUB_Script *scr;
4792 int offset;
4794 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4795 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4797 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4798 return scr;
4799 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4800 deflt = scr;
4802 return deflt;
4805 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4807 int i;
4808 int offset;
4809 const GSUB_LangSys *Lang;
4811 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4813 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4815 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4816 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4818 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4819 return Lang;
4821 offset = GET_BE_WORD(script->DefaultLangSys);
4822 if (offset)
4824 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4825 return Lang;
4827 return NULL;
4830 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4832 int i;
4833 const GSUB_FeatureList *feature;
4834 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4836 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4837 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4839 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4840 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4842 const GSUB_Feature *feat;
4843 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4844 return feat;
4847 return NULL;
4850 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4852 int i;
4853 int offset;
4854 const GSUB_LookupList *lookup;
4855 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4857 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4858 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4860 const GSUB_LookupTable *look;
4861 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4862 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4863 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4864 if (GET_BE_WORD(look->LookupType) != 1)
4865 FIXME("We only handle SubType 1\n");
4866 else
4868 int j;
4870 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4872 const GSUB_SingleSubstFormat1 *ssf1;
4873 offset = GET_BE_WORD(look->SubTable[j]);
4874 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4875 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4877 int offset = GET_BE_WORD(ssf1->Coverage);
4878 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4879 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4881 TRACE(" Glyph 0x%x ->",glyph);
4882 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4883 TRACE(" 0x%x\n",glyph);
4886 else
4888 const GSUB_SingleSubstFormat2 *ssf2;
4889 INT index;
4890 INT offset;
4892 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4893 offset = GET_BE_WORD(ssf1->Coverage);
4894 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4895 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4896 TRACE(" Coverage index %i\n",index);
4897 if (index != -1)
4899 TRACE(" Glyph is 0x%x ->",glyph);
4900 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4901 TRACE("0x%x\n",glyph);
4907 return glyph;
4910 static const char* get_opentype_script(const GdiFont *font)
4913 * I am not sure if this is the correct way to generate our script tag
4916 switch (font->charset)
4918 case ANSI_CHARSET: return "latn";
4919 case BALTIC_CHARSET: return "latn"; /* ?? */
4920 case CHINESEBIG5_CHARSET: return "hani";
4921 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4922 case GB2312_CHARSET: return "hani";
4923 case GREEK_CHARSET: return "grek";
4924 case HANGUL_CHARSET: return "hang";
4925 case RUSSIAN_CHARSET: return "cyrl";
4926 case SHIFTJIS_CHARSET: return "kana";
4927 case TURKISH_CHARSET: return "latn"; /* ?? */
4928 case VIETNAMESE_CHARSET: return "latn";
4929 case JOHAB_CHARSET: return "latn"; /* ?? */
4930 case ARABIC_CHARSET: return "arab";
4931 case HEBREW_CHARSET: return "hebr";
4932 case THAI_CHARSET: return "thai";
4933 default: return "latn";
4937 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4939 const GSUB_Header *header;
4940 const GSUB_Script *script;
4941 const GSUB_LangSys *language;
4942 const GSUB_Feature *feature;
4944 if (!font->GSUB_Table)
4945 return glyph;
4947 header = font->GSUB_Table;
4949 script = GSUB_get_script_table(header, get_opentype_script(font));
4950 if (!script)
4952 TRACE("Script not found\n");
4953 return glyph;
4955 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4956 if (!language)
4958 TRACE("Language not found\n");
4959 return glyph;
4961 feature = GSUB_get_feature(header, language, "vrt2");
4962 if (!feature)
4963 feature = GSUB_get_feature(header, language, "vert");
4964 if (!feature)
4966 TRACE("vrt2/vert feature not found\n");
4967 return glyph;
4969 return GSUB_apply_feature(header, feature, glyph);
4972 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4974 FT_UInt glyphId;
4976 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4977 WCHAR wc = (WCHAR)glyph;
4978 BOOL default_used;
4979 BOOL *default_used_pointer;
4980 FT_UInt ret;
4981 char buf;
4982 default_used_pointer = NULL;
4983 default_used = FALSE;
4984 if (codepage_sets_default_used(font->codepage))
4985 default_used_pointer = &default_used;
4986 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4987 ret = 0;
4988 else
4989 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4990 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4991 return ret;
4994 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4996 if (glyph < 0x100) glyph += 0xf000;
4997 /* there is a number of old pre-Unicode "broken" TTFs, which
4998 do have symbols at U+00XX instead of U+f0XX */
4999 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5000 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5002 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5004 return glyphId;
5007 /*************************************************************
5008 * freetype_GetGlyphIndices
5010 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5012 struct freetype_physdev *physdev = get_freetype_dev( dev );
5013 int i;
5014 WORD default_char;
5015 BOOL got_default = FALSE;
5017 if (!physdev->font)
5019 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5020 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5023 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5025 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5026 got_default = TRUE;
5029 GDI_CheckNotLock();
5030 EnterCriticalSection( &freetype_cs );
5032 for(i = 0; i < count; i++)
5034 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5035 if (pgi[i] == 0)
5037 if (!got_default)
5039 if (FT_IS_SFNT(physdev->font->ft_face))
5041 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5042 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5044 else
5046 TEXTMETRICW textm;
5047 get_text_metrics(physdev->font, &textm);
5048 default_char = textm.tmDefaultChar;
5050 got_default = TRUE;
5052 pgi[i] = default_char;
5055 LeaveCriticalSection( &freetype_cs );
5056 return count;
5059 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5061 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5062 return !memcmp(matrix, &identity, sizeof(FMAT2));
5065 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5067 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5068 return !memcmp(matrix, &identity, sizeof(MAT2));
5071 static inline BYTE get_max_level( UINT format )
5073 switch( format )
5075 case GGO_GRAY2_BITMAP: return 4;
5076 case GGO_GRAY4_BITMAP: return 16;
5077 case GGO_GRAY8_BITMAP: return 64;
5079 return 255;
5082 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5084 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5085 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5086 const MAT2* lpmat)
5088 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5089 FT_Face ft_face = incoming_font->ft_face;
5090 GdiFont *font = incoming_font;
5091 FT_UInt glyph_index;
5092 DWORD width, height, pitch, needed = 0;
5093 FT_Bitmap ft_bitmap;
5094 FT_Error err;
5095 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5096 FT_Angle angle = 0;
5097 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5098 double widthRatio = 1.0;
5099 FT_Matrix transMat = identityMat;
5100 FT_Matrix transMatUnrotated;
5101 BOOL needsTransform = FALSE;
5102 BOOL tategaki = (font->GSUB_Table != NULL);
5103 UINT original_index;
5105 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5106 buflen, buf, lpmat);
5108 TRACE("font transform %f %f %f %f\n",
5109 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5110 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5112 if(format & GGO_GLYPH_INDEX) {
5113 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5114 original_index = glyph;
5115 format &= ~GGO_GLYPH_INDEX;
5116 } else {
5117 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5118 ft_face = font->ft_face;
5119 original_index = glyph_index;
5122 if(format & GGO_UNHINTED) {
5123 load_flags |= FT_LOAD_NO_HINTING;
5124 format &= ~GGO_UNHINTED;
5127 /* tategaki never appears to happen to lower glyph index */
5128 if (glyph_index < TATEGAKI_LOWER_BOUND )
5129 tategaki = FALSE;
5131 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5132 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5133 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5134 font->gmsize * sizeof(GM*));
5135 } else {
5136 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5137 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5139 *lpgm = FONT_GM(font,original_index)->gm;
5140 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5141 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5142 lpgm->gmCellIncX, lpgm->gmCellIncY);
5143 return 1; /* FIXME */
5147 if (!font->gm[original_index / GM_BLOCK_SIZE])
5148 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5150 /* Scaling factor */
5151 if (font->aveWidth)
5153 TEXTMETRICW tm;
5155 get_text_metrics(font, &tm);
5157 widthRatio = (double)font->aveWidth;
5158 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5160 else
5161 widthRatio = font->scale_y;
5163 /* Scaling transform */
5164 if (widthRatio != 1.0 || font->scale_y != 1.0)
5166 FT_Matrix scaleMat;
5167 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5168 scaleMat.xy = 0;
5169 scaleMat.yx = 0;
5170 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5172 pFT_Matrix_Multiply(&scaleMat, &transMat);
5173 needsTransform = TRUE;
5176 /* Slant transform */
5177 if (font->fake_italic) {
5178 FT_Matrix slantMat;
5180 slantMat.xx = (1 << 16);
5181 slantMat.xy = ((1 << 16) >> 2);
5182 slantMat.yx = 0;
5183 slantMat.yy = (1 << 16);
5184 pFT_Matrix_Multiply(&slantMat, &transMat);
5185 needsTransform = TRUE;
5188 /* Rotation transform */
5189 transMatUnrotated = transMat;
5190 if(font->orientation && !tategaki) {
5191 FT_Matrix rotationMat;
5192 FT_Vector vecAngle;
5193 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5194 pFT_Vector_Unit(&vecAngle, angle);
5195 rotationMat.xx = vecAngle.x;
5196 rotationMat.xy = -vecAngle.y;
5197 rotationMat.yx = -rotationMat.xy;
5198 rotationMat.yy = rotationMat.xx;
5200 pFT_Matrix_Multiply(&rotationMat, &transMat);
5201 needsTransform = TRUE;
5204 /* World transform */
5205 if (!is_identity_FMAT2(&font->font_desc.matrix))
5207 FT_Matrix worldMat;
5208 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5209 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5210 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5211 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5212 pFT_Matrix_Multiply(&worldMat, &transMat);
5213 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5214 needsTransform = TRUE;
5217 /* Extra transformation specified by caller */
5218 if (!is_identity_MAT2(lpmat))
5220 FT_Matrix extraMat;
5221 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5222 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5223 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5224 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5225 pFT_Matrix_Multiply(&extraMat, &transMat);
5226 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5227 needsTransform = TRUE;
5230 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5231 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5232 format == GGO_GRAY8_BITMAP))
5234 load_flags |= FT_LOAD_NO_BITMAP;
5237 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5239 if(err) {
5240 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5241 return GDI_ERROR;
5244 if(!needsTransform) {
5245 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5246 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5247 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5249 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5250 bottom = (ft_face->glyph->metrics.horiBearingY -
5251 ft_face->glyph->metrics.height) & -64;
5252 lpgm->gmCellIncX = adv;
5253 lpgm->gmCellIncY = 0;
5254 } else {
5255 INT xc, yc;
5256 FT_Vector vec;
5258 left = right = 0;
5260 for(xc = 0; xc < 2; xc++) {
5261 for(yc = 0; yc < 2; yc++) {
5262 vec.x = (ft_face->glyph->metrics.horiBearingX +
5263 xc * ft_face->glyph->metrics.width);
5264 vec.y = ft_face->glyph->metrics.horiBearingY -
5265 yc * ft_face->glyph->metrics.height;
5266 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5267 pFT_Vector_Transform(&vec, &transMat);
5268 if(xc == 0 && yc == 0) {
5269 left = right = vec.x;
5270 top = bottom = vec.y;
5271 } else {
5272 if(vec.x < left) left = vec.x;
5273 else if(vec.x > right) right = vec.x;
5274 if(vec.y < bottom) bottom = vec.y;
5275 else if(vec.y > top) top = vec.y;
5279 left = left & -64;
5280 right = (right + 63) & -64;
5281 bottom = bottom & -64;
5282 top = (top + 63) & -64;
5284 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5285 vec.x = ft_face->glyph->metrics.horiAdvance;
5286 vec.y = 0;
5287 pFT_Vector_Transform(&vec, &transMat);
5288 lpgm->gmCellIncX = (vec.x+63) >> 6;
5289 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5291 vec.x = ft_face->glyph->metrics.horiAdvance;
5292 vec.y = 0;
5293 pFT_Vector_Transform(&vec, &transMatUnrotated);
5294 adv = (vec.x+63) >> 6;
5297 lsb = left >> 6;
5298 bbx = (right - left) >> 6;
5299 lpgm->gmBlackBoxX = (right - left) >> 6;
5300 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5301 lpgm->gmptGlyphOrigin.x = left >> 6;
5302 lpgm->gmptGlyphOrigin.y = top >> 6;
5304 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5305 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5306 lpgm->gmCellIncX, lpgm->gmCellIncY);
5308 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5309 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5311 FONT_GM(font,original_index)->gm = *lpgm;
5312 FONT_GM(font,original_index)->adv = adv;
5313 FONT_GM(font,original_index)->lsb = lsb;
5314 FONT_GM(font,original_index)->bbx = bbx;
5315 FONT_GM(font,original_index)->init = TRUE;
5318 if(format == GGO_METRICS)
5320 return 1; /* FIXME */
5323 if(ft_face->glyph->format != ft_glyph_format_outline &&
5324 (format == GGO_NATIVE || format == GGO_BEZIER))
5326 TRACE("loaded a bitmap\n");
5327 return GDI_ERROR;
5330 switch(format) {
5331 case GGO_BITMAP:
5332 width = lpgm->gmBlackBoxX;
5333 height = lpgm->gmBlackBoxY;
5334 pitch = ((width + 31) >> 5) << 2;
5335 needed = pitch * height;
5337 if(!buf || !buflen) break;
5339 switch(ft_face->glyph->format) {
5340 case ft_glyph_format_bitmap:
5342 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5343 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5344 INT h = ft_face->glyph->bitmap.rows;
5345 while(h--) {
5346 memcpy(dst, src, w);
5347 src += ft_face->glyph->bitmap.pitch;
5348 dst += pitch;
5350 break;
5353 case ft_glyph_format_outline:
5354 ft_bitmap.width = width;
5355 ft_bitmap.rows = height;
5356 ft_bitmap.pitch = pitch;
5357 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5358 ft_bitmap.buffer = buf;
5360 if(needsTransform)
5361 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5363 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5365 /* Note: FreeType will only set 'black' bits for us. */
5366 memset(buf, 0, needed);
5367 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5368 break;
5370 default:
5371 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5372 return GDI_ERROR;
5374 break;
5376 case GGO_GRAY2_BITMAP:
5377 case GGO_GRAY4_BITMAP:
5378 case GGO_GRAY8_BITMAP:
5379 case WINE_GGO_GRAY16_BITMAP:
5381 unsigned int max_level, row, col;
5382 BYTE *start, *ptr;
5384 width = lpgm->gmBlackBoxX;
5385 height = lpgm->gmBlackBoxY;
5386 pitch = (width + 3) / 4 * 4;
5387 needed = pitch * height;
5389 if(!buf || !buflen) break;
5391 max_level = get_max_level( format );
5393 switch(ft_face->glyph->format) {
5394 case ft_glyph_format_bitmap:
5396 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5397 INT h = ft_face->glyph->bitmap.rows;
5398 INT x;
5399 memset( buf, 0, needed );
5400 while(h--) {
5401 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5402 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5403 src += ft_face->glyph->bitmap.pitch;
5404 dst += pitch;
5406 return needed;
5408 case ft_glyph_format_outline:
5410 ft_bitmap.width = width;
5411 ft_bitmap.rows = height;
5412 ft_bitmap.pitch = pitch;
5413 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5414 ft_bitmap.buffer = buf;
5416 if(needsTransform)
5417 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5419 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5421 memset(ft_bitmap.buffer, 0, buflen);
5423 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5425 if (max_level != 255)
5427 for (row = 0, start = buf; row < height; row++)
5429 for (col = 0, ptr = start; col < width; col++, ptr++)
5430 *ptr = (((int)*ptr) * max_level + 128) / 256;
5431 start += pitch;
5434 return needed;
5437 default:
5438 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5439 return GDI_ERROR;
5441 break;
5444 case WINE_GGO_HRGB_BITMAP:
5445 case WINE_GGO_HBGR_BITMAP:
5446 case WINE_GGO_VRGB_BITMAP:
5447 case WINE_GGO_VBGR_BITMAP:
5448 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5450 switch (ft_face->glyph->format)
5452 case FT_GLYPH_FORMAT_BITMAP:
5454 BYTE *src, *dst;
5455 INT src_pitch, x;
5457 width = lpgm->gmBlackBoxX;
5458 height = lpgm->gmBlackBoxY;
5459 pitch = width * 4;
5460 needed = pitch * height;
5462 if (!buf || !buflen) break;
5464 memset(buf, 0, buflen);
5465 dst = buf;
5466 src = ft_face->glyph->bitmap.buffer;
5467 src_pitch = ft_face->glyph->bitmap.pitch;
5469 height = min( height, ft_face->glyph->bitmap.rows );
5470 while ( height-- )
5472 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5474 if ( src[x / 8] & masks[x % 8] )
5475 ((unsigned int *)dst)[x] = ~0u;
5477 src += src_pitch;
5478 dst += pitch;
5481 break;
5484 case FT_GLYPH_FORMAT_OUTLINE:
5486 unsigned int *dst;
5487 BYTE *src;
5488 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5489 INT x_shift, y_shift;
5490 BOOL rgb;
5491 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5492 FT_Render_Mode render_mode =
5493 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5494 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5496 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5498 if ( render_mode == FT_RENDER_MODE_LCD)
5500 lpgm->gmBlackBoxX += 2;
5501 lpgm->gmptGlyphOrigin.x -= 1;
5503 else
5505 lpgm->gmBlackBoxY += 2;
5506 lpgm->gmptGlyphOrigin.y += 1;
5510 width = lpgm->gmBlackBoxX;
5511 height = lpgm->gmBlackBoxY;
5512 pitch = width * 4;
5513 needed = pitch * height;
5515 if (!buf || !buflen) break;
5517 memset(buf, 0, buflen);
5518 dst = buf;
5519 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5521 if ( needsTransform )
5522 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5524 if ( pFT_Library_SetLcdFilter )
5525 pFT_Library_SetLcdFilter( library, lcdfilter );
5526 pFT_Render_Glyph (ft_face->glyph, render_mode);
5528 src = ft_face->glyph->bitmap.buffer;
5529 src_pitch = ft_face->glyph->bitmap.pitch;
5530 src_width = ft_face->glyph->bitmap.width;
5531 src_height = ft_face->glyph->bitmap.rows;
5533 if ( render_mode == FT_RENDER_MODE_LCD)
5535 rgb_interval = 1;
5536 hmul = 3;
5537 vmul = 1;
5539 else
5541 rgb_interval = src_pitch;
5542 hmul = 1;
5543 vmul = 3;
5546 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5547 if ( x_shift < 0 ) x_shift = 0;
5548 if ( x_shift + (src_width / hmul) > width )
5549 x_shift = width - (src_width / hmul);
5551 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5552 if ( y_shift < 0 ) y_shift = 0;
5553 if ( y_shift + (src_height / vmul) > height )
5554 y_shift = height - (src_height / vmul);
5556 dst += x_shift + y_shift * ( pitch / 4 );
5557 while ( src_height )
5559 for ( x = 0; x < src_width / hmul; x++ )
5561 if ( rgb )
5563 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5564 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5565 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5566 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5568 else
5570 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5571 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5572 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5573 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5576 src += src_pitch * vmul;
5577 dst += pitch / 4;
5578 src_height -= vmul;
5581 break;
5584 default:
5585 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5586 return GDI_ERROR;
5589 break;
5591 #else
5592 return GDI_ERROR;
5593 #endif
5595 case GGO_NATIVE:
5597 int contour, point = 0, first_pt;
5598 FT_Outline *outline = &ft_face->glyph->outline;
5599 TTPOLYGONHEADER *pph;
5600 TTPOLYCURVE *ppc;
5601 DWORD pph_start, cpfx, type;
5603 if(buflen == 0) buf = NULL;
5605 if (needsTransform && buf) {
5606 pFT_Outline_Transform(outline, &transMat);
5609 for(contour = 0; contour < outline->n_contours; contour++) {
5610 pph_start = needed;
5611 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5612 first_pt = point;
5613 if(buf) {
5614 pph->dwType = TT_POLYGON_TYPE;
5615 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5617 needed += sizeof(*pph);
5618 point++;
5619 while(point <= outline->contours[contour]) {
5620 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5621 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5622 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5623 cpfx = 0;
5624 do {
5625 if(buf)
5626 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5627 cpfx++;
5628 point++;
5629 } while(point <= outline->contours[contour] &&
5630 (outline->tags[point] & FT_Curve_Tag_On) ==
5631 (outline->tags[point-1] & FT_Curve_Tag_On));
5632 /* At the end of a contour Windows adds the start point, but
5633 only for Beziers */
5634 if(point > outline->contours[contour] &&
5635 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5636 if(buf)
5637 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5638 cpfx++;
5639 } else if(point <= outline->contours[contour] &&
5640 outline->tags[point] & FT_Curve_Tag_On) {
5641 /* add closing pt for bezier */
5642 if(buf)
5643 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5644 cpfx++;
5645 point++;
5647 if(buf) {
5648 ppc->wType = type;
5649 ppc->cpfx = cpfx;
5651 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5653 if(buf)
5654 pph->cb = needed - pph_start;
5656 break;
5658 case GGO_BEZIER:
5660 /* Convert the quadratic Beziers to cubic Beziers.
5661 The parametric eqn for a cubic Bezier is, from PLRM:
5662 r(t) = at^3 + bt^2 + ct + r0
5663 with the control points:
5664 r1 = r0 + c/3
5665 r2 = r1 + (c + b)/3
5666 r3 = r0 + c + b + a
5668 A quadratic Bezier has the form:
5669 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5671 So equating powers of t leads to:
5672 r1 = 2/3 p1 + 1/3 p0
5673 r2 = 2/3 p1 + 1/3 p2
5674 and of course r0 = p0, r3 = p2
5677 int contour, point = 0, first_pt;
5678 FT_Outline *outline = &ft_face->glyph->outline;
5679 TTPOLYGONHEADER *pph;
5680 TTPOLYCURVE *ppc;
5681 DWORD pph_start, cpfx, type;
5682 FT_Vector cubic_control[4];
5683 if(buflen == 0) buf = NULL;
5685 if (needsTransform && buf) {
5686 pFT_Outline_Transform(outline, &transMat);
5689 for(contour = 0; contour < outline->n_contours; contour++) {
5690 pph_start = needed;
5691 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5692 first_pt = point;
5693 if(buf) {
5694 pph->dwType = TT_POLYGON_TYPE;
5695 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5697 needed += sizeof(*pph);
5698 point++;
5699 while(point <= outline->contours[contour]) {
5700 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5701 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5702 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5703 cpfx = 0;
5704 do {
5705 if(type == TT_PRIM_LINE) {
5706 if(buf)
5707 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5708 cpfx++;
5709 point++;
5710 } else {
5711 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5712 so cpfx = 3n */
5714 /* FIXME: Possible optimization in endpoint calculation
5715 if there are two consecutive curves */
5716 cubic_control[0] = outline->points[point-1];
5717 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5718 cubic_control[0].x += outline->points[point].x + 1;
5719 cubic_control[0].y += outline->points[point].y + 1;
5720 cubic_control[0].x >>= 1;
5721 cubic_control[0].y >>= 1;
5723 if(point+1 > outline->contours[contour])
5724 cubic_control[3] = outline->points[first_pt];
5725 else {
5726 cubic_control[3] = outline->points[point+1];
5727 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5728 cubic_control[3].x += outline->points[point].x + 1;
5729 cubic_control[3].y += outline->points[point].y + 1;
5730 cubic_control[3].x >>= 1;
5731 cubic_control[3].y >>= 1;
5734 /* r1 = 1/3 p0 + 2/3 p1
5735 r2 = 1/3 p2 + 2/3 p1 */
5736 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5737 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5738 cubic_control[2] = cubic_control[1];
5739 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5740 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5741 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5742 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5743 if(buf) {
5744 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5745 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5746 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5748 cpfx += 3;
5749 point++;
5751 } while(point <= outline->contours[contour] &&
5752 (outline->tags[point] & FT_Curve_Tag_On) ==
5753 (outline->tags[point-1] & FT_Curve_Tag_On));
5754 /* At the end of a contour Windows adds the start point,
5755 but only for Beziers and we've already done that.
5757 if(point <= outline->contours[contour] &&
5758 outline->tags[point] & FT_Curve_Tag_On) {
5759 /* This is the closing pt of a bezier, but we've already
5760 added it, so just inc point and carry on */
5761 point++;
5763 if(buf) {
5764 ppc->wType = type;
5765 ppc->cpfx = cpfx;
5767 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5769 if(buf)
5770 pph->cb = needed - pph_start;
5772 break;
5775 default:
5776 FIXME("Unsupported format %d\n", format);
5777 return GDI_ERROR;
5779 return needed;
5782 static BOOL get_bitmap_text_metrics(GdiFont *font)
5784 FT_Face ft_face = font->ft_face;
5785 FT_WinFNT_HeaderRec winfnt_header;
5786 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5787 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5788 font->potm->otmSize = size;
5790 #define TM font->potm->otmTextMetrics
5791 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5793 TM.tmHeight = winfnt_header.pixel_height;
5794 TM.tmAscent = winfnt_header.ascent;
5795 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5796 TM.tmInternalLeading = winfnt_header.internal_leading;
5797 TM.tmExternalLeading = winfnt_header.external_leading;
5798 TM.tmAveCharWidth = winfnt_header.avg_width;
5799 TM.tmMaxCharWidth = winfnt_header.max_width;
5800 TM.tmWeight = winfnt_header.weight;
5801 TM.tmOverhang = 0;
5802 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5803 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5804 TM.tmFirstChar = winfnt_header.first_char;
5805 TM.tmLastChar = winfnt_header.last_char;
5806 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5807 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5808 TM.tmItalic = winfnt_header.italic;
5809 TM.tmUnderlined = font->underline;
5810 TM.tmStruckOut = font->strikeout;
5811 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5812 TM.tmCharSet = winfnt_header.charset;
5814 else
5816 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5817 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5818 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5819 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5820 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5821 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5822 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5823 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5824 TM.tmOverhang = 0;
5825 TM.tmDigitizedAspectX = 96; /* FIXME */
5826 TM.tmDigitizedAspectY = 96; /* FIXME */
5827 TM.tmFirstChar = 1;
5828 TM.tmLastChar = 255;
5829 TM.tmDefaultChar = 32;
5830 TM.tmBreakChar = 32;
5831 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5832 TM.tmUnderlined = font->underline;
5833 TM.tmStruckOut = font->strikeout;
5834 /* NB inverted meaning of TMPF_FIXED_PITCH */
5835 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5836 TM.tmCharSet = font->charset;
5838 #undef TM
5840 return TRUE;
5844 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5846 double scale_x, scale_y;
5848 if (font->aveWidth)
5850 scale_x = (double)font->aveWidth;
5851 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5853 else
5854 scale_x = font->scale_y;
5856 scale_x *= fabs(font->font_desc.matrix.eM11);
5857 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5859 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5860 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5862 SCALE_Y(ptm->tmHeight);
5863 SCALE_Y(ptm->tmAscent);
5864 SCALE_Y(ptm->tmDescent);
5865 SCALE_Y(ptm->tmInternalLeading);
5866 SCALE_Y(ptm->tmExternalLeading);
5867 SCALE_Y(ptm->tmOverhang);
5869 SCALE_X(ptm->tmAveCharWidth);
5870 SCALE_X(ptm->tmMaxCharWidth);
5872 #undef SCALE_X
5873 #undef SCALE_Y
5876 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5878 double scale_x, scale_y;
5880 if (font->aveWidth)
5882 scale_x = (double)font->aveWidth;
5883 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5885 else
5886 scale_x = font->scale_y;
5888 scale_x *= fabs(font->font_desc.matrix.eM11);
5889 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5891 scale_font_metrics(font, &potm->otmTextMetrics);
5893 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5894 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5896 SCALE_Y(potm->otmAscent);
5897 SCALE_Y(potm->otmDescent);
5898 SCALE_Y(potm->otmLineGap);
5899 SCALE_Y(potm->otmsCapEmHeight);
5900 SCALE_Y(potm->otmsXHeight);
5901 SCALE_Y(potm->otmrcFontBox.top);
5902 SCALE_Y(potm->otmrcFontBox.bottom);
5903 SCALE_X(potm->otmrcFontBox.left);
5904 SCALE_X(potm->otmrcFontBox.right);
5905 SCALE_Y(potm->otmMacAscent);
5906 SCALE_Y(potm->otmMacDescent);
5907 SCALE_Y(potm->otmMacLineGap);
5908 SCALE_X(potm->otmptSubscriptSize.x);
5909 SCALE_Y(potm->otmptSubscriptSize.y);
5910 SCALE_X(potm->otmptSubscriptOffset.x);
5911 SCALE_Y(potm->otmptSubscriptOffset.y);
5912 SCALE_X(potm->otmptSuperscriptSize.x);
5913 SCALE_Y(potm->otmptSuperscriptSize.y);
5914 SCALE_X(potm->otmptSuperscriptOffset.x);
5915 SCALE_Y(potm->otmptSuperscriptOffset.y);
5916 SCALE_Y(potm->otmsStrikeoutSize);
5917 SCALE_Y(potm->otmsStrikeoutPosition);
5918 SCALE_Y(potm->otmsUnderscoreSize);
5919 SCALE_Y(potm->otmsUnderscorePosition);
5921 #undef SCALE_X
5922 #undef SCALE_Y
5925 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5927 if(!font->potm)
5929 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
5931 /* Make sure that the font has sane width/height ratio */
5932 if (font->aveWidth)
5934 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5936 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5937 font->aveWidth = 0;
5941 *ptm = font->potm->otmTextMetrics;
5942 scale_font_metrics(font, ptm);
5943 return TRUE;
5946 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5948 int i;
5950 for(i = 0; i < ft_face->num_charmaps; i++)
5952 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5953 return TRUE;
5955 return FALSE;
5958 static BOOL get_outline_text_metrics(GdiFont *font)
5960 BOOL ret = FALSE;
5961 FT_Face ft_face = font->ft_face;
5962 UINT needed, lenfam, lensty;
5963 TT_OS2 *pOS2;
5964 TT_HoriHeader *pHori;
5965 TT_Postscript *pPost;
5966 FT_Fixed x_scale, y_scale;
5967 WCHAR *family_nameW, *style_nameW;
5968 static const WCHAR spaceW[] = {' ', '\0'};
5969 char *cp;
5970 INT ascent, descent;
5972 TRACE("font=%p\n", font);
5974 if(!FT_IS_SCALABLE(ft_face))
5975 return FALSE;
5977 needed = sizeof(*font->potm);
5979 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5980 family_nameW = strdupW(font->name);
5982 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5983 * sizeof(WCHAR);
5984 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5985 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5986 style_nameW, lensty/sizeof(WCHAR));
5988 /* These names should be read from the TT name table */
5990 /* length of otmpFamilyName */
5991 needed += lenfam;
5993 /* length of otmpFaceName */
5994 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5995 needed += lenfam; /* just the family name */
5996 } else {
5997 needed += lenfam + lensty; /* family + " " + style */
6000 /* length of otmpStyleName */
6001 needed += lensty;
6003 /* length of otmpFullName */
6004 needed += lenfam + lensty;
6007 x_scale = ft_face->size->metrics.x_scale;
6008 y_scale = ft_face->size->metrics.y_scale;
6010 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6011 if(!pOS2) {
6012 FIXME("Can't find OS/2 table - not TT font?\n");
6013 goto end;
6016 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6017 if(!pHori) {
6018 FIXME("Can't find HHEA table - not TT font?\n");
6019 goto end;
6022 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6024 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",
6025 pOS2->usWinAscent, pOS2->usWinDescent,
6026 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6027 ft_face->ascender, ft_face->descender, ft_face->height,
6028 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6029 ft_face->bbox.yMax, ft_face->bbox.yMin);
6031 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6032 font->potm->otmSize = needed;
6034 #define TM font->potm->otmTextMetrics
6036 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6037 ascent = pHori->Ascender;
6038 descent = -pHori->Descender;
6039 } else {
6040 ascent = pOS2->usWinAscent;
6041 descent = pOS2->usWinDescent;
6044 if(font->yMax) {
6045 TM.tmAscent = font->yMax;
6046 TM.tmDescent = -font->yMin;
6047 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6048 } else {
6049 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6050 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6051 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6052 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6055 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6057 /* MSDN says:
6058 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6060 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6061 ((ascent + descent) -
6062 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6064 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6065 if (TM.tmAveCharWidth == 0) {
6066 TM.tmAveCharWidth = 1;
6068 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6069 TM.tmWeight = FW_REGULAR;
6070 if (font->fake_bold)
6071 TM.tmWeight = FW_BOLD;
6072 else
6074 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6076 if (pOS2->usWeightClass > FW_MEDIUM)
6077 TM.tmWeight = pOS2->usWeightClass;
6079 else if (pOS2->usWeightClass <= FW_MEDIUM)
6080 TM.tmWeight = pOS2->usWeightClass;
6082 TM.tmOverhang = 0;
6083 TM.tmDigitizedAspectX = 300;
6084 TM.tmDigitizedAspectY = 300;
6085 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6086 * symbol range to 0 - f0ff
6089 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6091 TM.tmFirstChar = 0;
6092 switch(GetACP())
6094 case 1257: /* Baltic */
6095 TM.tmLastChar = 0xf8fd;
6096 break;
6097 default:
6098 TM.tmLastChar = 0xf0ff;
6100 TM.tmBreakChar = 0x20;
6101 TM.tmDefaultChar = 0x1f;
6103 else
6105 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6106 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6108 if(pOS2->usFirstCharIndex <= 1)
6109 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6110 else if (pOS2->usFirstCharIndex > 0xff)
6111 TM.tmBreakChar = 0x20;
6112 else
6113 TM.tmBreakChar = pOS2->usFirstCharIndex;
6114 TM.tmDefaultChar = TM.tmBreakChar - 1;
6116 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6117 TM.tmUnderlined = font->underline;
6118 TM.tmStruckOut = font->strikeout;
6120 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6121 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6122 (pOS2->version == 0xFFFFU ||
6123 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6124 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6125 else
6126 TM.tmPitchAndFamily = 0;
6128 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6130 case PAN_FAMILY_SCRIPT:
6131 TM.tmPitchAndFamily |= FF_SCRIPT;
6132 break;
6134 case PAN_FAMILY_DECORATIVE:
6135 TM.tmPitchAndFamily |= FF_DECORATIVE;
6136 break;
6138 case PAN_ANY:
6139 case PAN_NO_FIT:
6140 case PAN_FAMILY_TEXT_DISPLAY:
6141 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6142 /* which is clearly not what the panose spec says. */
6143 default:
6144 if(TM.tmPitchAndFamily == 0 || /* fixed */
6145 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6146 TM.tmPitchAndFamily = FF_MODERN;
6147 else
6149 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6151 case PAN_ANY:
6152 case PAN_NO_FIT:
6153 default:
6154 TM.tmPitchAndFamily |= FF_DONTCARE;
6155 break;
6157 case PAN_SERIF_COVE:
6158 case PAN_SERIF_OBTUSE_COVE:
6159 case PAN_SERIF_SQUARE_COVE:
6160 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6161 case PAN_SERIF_SQUARE:
6162 case PAN_SERIF_THIN:
6163 case PAN_SERIF_BONE:
6164 case PAN_SERIF_EXAGGERATED:
6165 case PAN_SERIF_TRIANGLE:
6166 TM.tmPitchAndFamily |= FF_ROMAN;
6167 break;
6169 case PAN_SERIF_NORMAL_SANS:
6170 case PAN_SERIF_OBTUSE_SANS:
6171 case PAN_SERIF_PERP_SANS:
6172 case PAN_SERIF_FLARED:
6173 case PAN_SERIF_ROUNDED:
6174 TM.tmPitchAndFamily |= FF_SWISS;
6175 break;
6178 break;
6181 if(FT_IS_SCALABLE(ft_face))
6182 TM.tmPitchAndFamily |= TMPF_VECTOR;
6184 if(FT_IS_SFNT(ft_face))
6186 if (font->ntmFlags & NTM_PS_OPENTYPE)
6187 TM.tmPitchAndFamily |= TMPF_DEVICE;
6188 else
6189 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6192 TM.tmCharSet = font->charset;
6194 font->potm->otmFiller = 0;
6195 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6196 font->potm->otmfsSelection = pOS2->fsSelection;
6197 font->potm->otmfsType = pOS2->fsType;
6198 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6199 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6200 font->potm->otmItalicAngle = 0; /* POST table */
6201 font->potm->otmEMSquare = ft_face->units_per_EM;
6202 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6203 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6204 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6205 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6206 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6207 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6208 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6209 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6210 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6211 font->potm->otmMacAscent = TM.tmAscent;
6212 font->potm->otmMacDescent = -TM.tmDescent;
6213 font->potm->otmMacLineGap = font->potm->otmLineGap;
6214 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6215 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6216 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6217 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6218 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6219 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6220 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6221 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6222 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6223 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6224 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6225 if(!pPost) {
6226 font->potm->otmsUnderscoreSize = 0;
6227 font->potm->otmsUnderscorePosition = 0;
6228 } else {
6229 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6230 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6232 #undef TM
6234 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6235 cp = (char*)font->potm + sizeof(*font->potm);
6236 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6237 strcpyW((WCHAR*)cp, family_nameW);
6238 cp += lenfam;
6239 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6240 strcpyW((WCHAR*)cp, style_nameW);
6241 cp += lensty;
6242 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6243 strcpyW((WCHAR*)cp, family_nameW);
6244 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6245 strcatW((WCHAR*)cp, spaceW);
6246 strcatW((WCHAR*)cp, style_nameW);
6247 cp += lenfam + lensty;
6248 } else
6249 cp += lenfam;
6250 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6251 strcpyW((WCHAR*)cp, family_nameW);
6252 strcatW((WCHAR*)cp, spaceW);
6253 strcatW((WCHAR*)cp, style_nameW);
6254 ret = TRUE;
6256 end:
6257 HeapFree(GetProcessHeap(), 0, style_nameW);
6258 HeapFree(GetProcessHeap(), 0, family_nameW);
6259 return ret;
6262 /*************************************************************
6263 * freetype_GetGlyphOutline
6265 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6266 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6268 struct freetype_physdev *physdev = get_freetype_dev( dev );
6269 DWORD ret;
6271 if (!physdev->font)
6273 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6274 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6277 GDI_CheckNotLock();
6278 EnterCriticalSection( &freetype_cs );
6279 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6280 LeaveCriticalSection( &freetype_cs );
6281 return ret;
6284 /*************************************************************
6285 * freetype_GetTextMetrics
6287 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6289 struct freetype_physdev *physdev = get_freetype_dev( dev );
6290 BOOL ret;
6292 if (!physdev->font)
6294 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6295 return dev->funcs->pGetTextMetrics( dev, metrics );
6298 GDI_CheckNotLock();
6299 EnterCriticalSection( &freetype_cs );
6300 ret = get_text_metrics( physdev->font, metrics );
6301 LeaveCriticalSection( &freetype_cs );
6302 return ret;
6305 /*************************************************************
6306 * freetype_GetOutlineTextMetrics
6308 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6310 struct freetype_physdev *physdev = get_freetype_dev( dev );
6311 UINT ret = 0;
6313 if (!physdev->font)
6315 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6316 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6319 TRACE("font=%p\n", physdev->font);
6321 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6323 GDI_CheckNotLock();
6324 EnterCriticalSection( &freetype_cs );
6326 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6328 if(cbSize >= physdev->font->potm->otmSize)
6330 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6331 scale_outline_font_metrics(physdev->font, potm);
6333 ret = physdev->font->potm->otmSize;
6335 LeaveCriticalSection( &freetype_cs );
6336 return ret;
6339 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6341 HFONTLIST *hfontlist;
6342 child->font = alloc_font();
6343 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6344 if(!child->font->ft_face)
6346 free_font(child->font);
6347 child->font = NULL;
6348 return FALSE;
6351 child->font->font_desc = font->font_desc;
6352 child->font->ntmFlags = child->face->ntmFlags;
6353 child->font->orientation = font->orientation;
6354 child->font->scale_y = font->scale_y;
6355 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6356 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6357 child->font->name = strdupW(child->face->family->FamilyName);
6358 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6359 child->font->base_font = font;
6360 list_add_head(&child_font_list, &child->font->entry);
6361 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6362 return TRUE;
6365 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6367 FT_UInt g;
6368 CHILD_FONT *child_font;
6370 if(font->base_font)
6371 font = font->base_font;
6373 *linked_font = font;
6375 if((*glyph = get_glyph_index(font, c)))
6377 *glyph = get_GSUB_vert_glyph(font, *glyph);
6378 return TRUE;
6381 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6383 if(!child_font->font)
6384 if(!load_child_font(font, child_font))
6385 continue;
6387 if(!child_font->font->ft_face)
6388 continue;
6389 g = get_glyph_index(child_font->font, c);
6390 g = get_GSUB_vert_glyph(child_font->font, g);
6391 if(g)
6393 *glyph = g;
6394 *linked_font = child_font->font;
6395 return TRUE;
6398 return FALSE;
6401 /*************************************************************
6402 * freetype_GetCharWidth
6404 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6406 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6407 UINT c;
6408 GLYPHMETRICS gm;
6409 FT_UInt glyph_index;
6410 GdiFont *linked_font;
6411 struct freetype_physdev *physdev = get_freetype_dev( dev );
6413 if (!physdev->font)
6415 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6416 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6419 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6421 GDI_CheckNotLock();
6422 EnterCriticalSection( &freetype_cs );
6423 for(c = firstChar; c <= lastChar; c++) {
6424 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6425 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6426 &gm, 0, NULL, &identity);
6427 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6429 LeaveCriticalSection( &freetype_cs );
6430 return TRUE;
6433 /*************************************************************
6434 * freetype_GetCharABCWidths
6436 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6438 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6439 UINT c;
6440 GLYPHMETRICS gm;
6441 FT_UInt glyph_index;
6442 GdiFont *linked_font;
6443 struct freetype_physdev *physdev = get_freetype_dev( dev );
6445 if (!physdev->font)
6447 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6448 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6451 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6453 GDI_CheckNotLock();
6454 EnterCriticalSection( &freetype_cs );
6456 for(c = firstChar; c <= lastChar; c++) {
6457 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6458 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6459 &gm, 0, NULL, &identity);
6460 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6461 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6462 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6463 FONT_GM(linked_font,glyph_index)->bbx;
6465 LeaveCriticalSection( &freetype_cs );
6466 return TRUE;
6469 /*************************************************************
6470 * freetype_GetCharABCWidthsI
6472 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6474 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6475 UINT c;
6476 GLYPHMETRICS gm;
6477 FT_UInt glyph_index;
6478 GdiFont *linked_font;
6479 struct freetype_physdev *physdev = get_freetype_dev( dev );
6481 if (!physdev->font)
6483 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6484 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6487 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6488 return FALSE;
6490 GDI_CheckNotLock();
6491 EnterCriticalSection( &freetype_cs );
6493 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6494 if (!pgi)
6495 for(c = firstChar; c < firstChar+count; c++) {
6496 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6497 &gm, 0, NULL, &identity);
6498 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6499 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6500 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6501 - FONT_GM(linked_font,c)->bbx;
6503 else
6504 for(c = 0; c < count; c++) {
6505 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6506 &gm, 0, NULL, &identity);
6507 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6508 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6509 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6510 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6513 LeaveCriticalSection( &freetype_cs );
6514 return TRUE;
6517 /*************************************************************
6518 * freetype_GetTextExtentExPoint
6520 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6521 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6523 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6524 INT idx;
6525 INT nfit = 0, ext;
6526 GLYPHMETRICS gm;
6527 TEXTMETRICW tm;
6528 FT_UInt glyph_index;
6529 GdiFont *linked_font;
6530 struct freetype_physdev *physdev = get_freetype_dev( dev );
6532 if (!physdev->font)
6534 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6535 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6538 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6540 GDI_CheckNotLock();
6541 EnterCriticalSection( &freetype_cs );
6543 size->cx = 0;
6544 get_text_metrics( physdev->font, &tm );
6545 size->cy = tm.tmHeight;
6547 for(idx = 0; idx < count; idx++) {
6548 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6549 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6550 &gm, 0, NULL, &identity);
6551 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6552 ext = size->cx;
6553 if (! pnfit || ext <= max_ext) {
6554 ++nfit;
6555 if (dxs)
6556 dxs[idx] = ext;
6560 if (pnfit)
6561 *pnfit = nfit;
6563 LeaveCriticalSection( &freetype_cs );
6564 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6565 return TRUE;
6568 /*************************************************************
6569 * freetype_GetTextExtentExPointI
6571 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6572 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6574 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6575 INT idx;
6576 INT nfit = 0, ext;
6577 GLYPHMETRICS gm;
6578 TEXTMETRICW tm;
6579 struct freetype_physdev *physdev = get_freetype_dev( dev );
6581 if (!physdev->font)
6583 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6584 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6587 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6589 GDI_CheckNotLock();
6590 EnterCriticalSection( &freetype_cs );
6592 size->cx = 0;
6593 get_text_metrics(physdev->font, &tm);
6594 size->cy = tm.tmHeight;
6596 for(idx = 0; idx < count; idx++) {
6597 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6598 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6599 ext = size->cx;
6600 if (! pnfit || ext <= max_ext) {
6601 ++nfit;
6602 if (dxs)
6603 dxs[idx] = ext;
6607 if (pnfit)
6608 *pnfit = nfit;
6610 LeaveCriticalSection( &freetype_cs );
6611 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6612 return TRUE;
6615 /*************************************************************
6616 * freetype_GetFontData
6618 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6620 struct freetype_physdev *physdev = get_freetype_dev( dev );
6622 if (!physdev->font)
6624 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6625 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6628 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6629 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6630 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6632 return get_font_data( physdev->font, table, offset, buf, cbData );
6635 /*************************************************************
6636 * freetype_GetTextFace
6638 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6640 INT n;
6641 struct freetype_physdev *physdev = get_freetype_dev( dev );
6643 if (!physdev->font)
6645 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6646 return dev->funcs->pGetTextFace( dev, count, str );
6649 n = strlenW(physdev->font->name) + 1;
6650 if (str)
6652 lstrcpynW(str, physdev->font->name, count);
6653 n = min(count, n);
6655 return n;
6658 /*************************************************************
6659 * freetype_GetTextCharsetInfo
6661 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6663 struct freetype_physdev *physdev = get_freetype_dev( dev );
6665 if (!physdev->font)
6667 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6668 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6670 if (fs) *fs = physdev->font->fs;
6671 return physdev->font->charset;
6674 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6676 GdiFont *font = dc->gdiFont, *linked_font;
6677 struct list *first_hfont;
6678 BOOL ret;
6680 GDI_CheckNotLock();
6681 EnterCriticalSection( &freetype_cs );
6682 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6683 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6684 if(font == linked_font)
6685 *new_hfont = dc->hFont;
6686 else
6688 first_hfont = list_head(&linked_font->hfontlist);
6689 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6691 LeaveCriticalSection( &freetype_cs );
6692 return ret;
6695 /* Retrieve a list of supported Unicode ranges for a given font.
6696 * Can be called with NULL gs to calculate the buffer size. Returns
6697 * the number of ranges found.
6699 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6701 DWORD num_ranges = 0;
6703 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6705 FT_UInt glyph_code;
6706 FT_ULong char_code, char_code_prev;
6708 glyph_code = 0;
6709 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6711 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6712 face->num_glyphs, glyph_code, char_code);
6714 if (!glyph_code) return 0;
6716 if (gs)
6718 gs->ranges[0].wcLow = (USHORT)char_code;
6719 gs->ranges[0].cGlyphs = 0;
6720 gs->cGlyphsSupported = 0;
6723 num_ranges = 1;
6724 while (glyph_code)
6726 if (char_code < char_code_prev)
6728 ERR("expected increasing char code from FT_Get_Next_Char\n");
6729 return 0;
6731 if (char_code - char_code_prev > 1)
6733 num_ranges++;
6734 if (gs)
6736 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6737 gs->ranges[num_ranges - 1].cGlyphs = 1;
6738 gs->cGlyphsSupported++;
6741 else if (gs)
6743 gs->ranges[num_ranges - 1].cGlyphs++;
6744 gs->cGlyphsSupported++;
6746 char_code_prev = char_code;
6747 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6750 else
6751 FIXME("encoding %u not supported\n", face->charmap->encoding);
6753 return num_ranges;
6756 /*************************************************************
6757 * freetype_GetFontUnicodeRanges
6759 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6761 struct freetype_physdev *physdev = get_freetype_dev( dev );
6762 DWORD size, num_ranges;
6764 if (!physdev->font)
6766 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6767 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6770 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6771 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6772 if (glyphset)
6774 glyphset->cbThis = size;
6775 glyphset->cRanges = num_ranges;
6776 glyphset->flAccel = 0;
6778 return size;
6781 /*************************************************************
6782 * freetype_FontIsLinked
6784 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6786 struct freetype_physdev *physdev = get_freetype_dev( dev );
6787 BOOL ret;
6789 if (!physdev->font)
6791 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6792 return dev->funcs->pFontIsLinked( dev );
6795 GDI_CheckNotLock();
6796 EnterCriticalSection( &freetype_cs );
6797 ret = !list_empty(&physdev->font->child_fonts);
6798 LeaveCriticalSection( &freetype_cs );
6799 return ret;
6802 static BOOL is_hinting_enabled(void)
6804 /* Use the >= 2.2.0 function if available */
6805 if(pFT_Get_TrueType_Engine_Type)
6807 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6808 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6810 #ifdef FT_DRIVER_HAS_HINTER
6811 else
6813 FT_Module mod;
6815 /* otherwise if we've been compiled with < 2.2.0 headers
6816 use the internal macro */
6817 mod = pFT_Get_Module(library, "truetype");
6818 if(mod && FT_DRIVER_HAS_HINTER(mod))
6819 return TRUE;
6821 #endif
6823 return FALSE;
6826 static BOOL is_subpixel_rendering_enabled( void )
6828 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6829 return pFT_Library_SetLcdFilter &&
6830 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6831 #else
6832 return FALSE;
6833 #endif
6836 /*************************************************************************
6837 * GetRasterizerCaps (GDI32.@)
6839 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6841 static int hinting = -1;
6842 static int subpixel = -1;
6844 if(hinting == -1)
6846 hinting = is_hinting_enabled();
6847 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6850 if ( subpixel == -1 )
6852 subpixel = is_subpixel_rendering_enabled();
6853 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6856 lprs->nSize = sizeof(RASTERIZER_STATUS);
6857 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6858 if ( subpixel )
6859 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6860 lprs->nLanguageID = 0;
6861 return TRUE;
6864 /*************************************************************
6865 * freetype_GdiRealizationInfo
6867 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6869 struct freetype_physdev *physdev = get_freetype_dev( dev );
6870 realization_info_t *info = ptr;
6872 if (!physdev->font)
6874 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6875 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6878 FIXME("(%p, %p): stub!\n", physdev->font, info);
6880 info->flags = 1;
6881 if(FT_IS_SCALABLE(physdev->font->ft_face))
6882 info->flags |= 2;
6884 info->cache_num = physdev->font->cache_num;
6885 info->unknown2 = -1;
6886 return TRUE;
6889 /*************************************************************************
6890 * Kerning support for TrueType fonts
6892 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6894 struct TT_kern_table
6896 USHORT version;
6897 USHORT nTables;
6900 struct TT_kern_subtable
6902 USHORT version;
6903 USHORT length;
6904 union
6906 USHORT word;
6907 struct
6909 USHORT horizontal : 1;
6910 USHORT minimum : 1;
6911 USHORT cross_stream: 1;
6912 USHORT override : 1;
6913 USHORT reserved1 : 4;
6914 USHORT format : 8;
6915 } bits;
6916 } coverage;
6919 struct TT_format0_kern_subtable
6921 USHORT nPairs;
6922 USHORT searchRange;
6923 USHORT entrySelector;
6924 USHORT rangeShift;
6927 struct TT_kern_pair
6929 USHORT left;
6930 USHORT right;
6931 short value;
6934 static DWORD parse_format0_kern_subtable(GdiFont *font,
6935 const struct TT_format0_kern_subtable *tt_f0_ks,
6936 const USHORT *glyph_to_char,
6937 KERNINGPAIR *kern_pair, DWORD cPairs)
6939 USHORT i, nPairs;
6940 const struct TT_kern_pair *tt_kern_pair;
6942 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6944 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6946 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6947 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6948 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6950 if (!kern_pair || !cPairs)
6951 return nPairs;
6953 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6955 nPairs = min(nPairs, cPairs);
6957 for (i = 0; i < nPairs; i++)
6959 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6960 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6961 /* this algorithm appears to better match what Windows does */
6962 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6963 if (kern_pair->iKernAmount < 0)
6965 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6966 kern_pair->iKernAmount -= font->ppem;
6968 else if (kern_pair->iKernAmount > 0)
6970 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6971 kern_pair->iKernAmount += font->ppem;
6973 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6975 TRACE("left %u right %u value %d\n",
6976 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6978 kern_pair++;
6980 TRACE("copied %u entries\n", nPairs);
6981 return nPairs;
6984 /*************************************************************
6985 * freetype_GetKerningPairs
6987 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
6989 DWORD length;
6990 void *buf;
6991 const struct TT_kern_table *tt_kern_table;
6992 const struct TT_kern_subtable *tt_kern_subtable;
6993 USHORT i, nTables;
6994 USHORT *glyph_to_char;
6995 GdiFont *font;
6996 struct freetype_physdev *physdev = get_freetype_dev( dev );
6998 if (!(font = physdev->font))
7000 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7001 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7004 GDI_CheckNotLock();
7005 EnterCriticalSection( &freetype_cs );
7006 if (font->total_kern_pairs != (DWORD)-1)
7008 if (cPairs && kern_pair)
7010 cPairs = min(cPairs, font->total_kern_pairs);
7011 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7013 else cPairs = font->total_kern_pairs;
7015 LeaveCriticalSection( &freetype_cs );
7016 return cPairs;
7019 font->total_kern_pairs = 0;
7021 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7023 if (length == GDI_ERROR)
7025 TRACE("no kerning data in the font\n");
7026 LeaveCriticalSection( &freetype_cs );
7027 return 0;
7030 buf = HeapAlloc(GetProcessHeap(), 0, length);
7031 if (!buf)
7033 WARN("Out of memory\n");
7034 LeaveCriticalSection( &freetype_cs );
7035 return 0;
7038 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7040 /* build a glyph index to char code map */
7041 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7042 if (!glyph_to_char)
7044 WARN("Out of memory allocating a glyph index to char code map\n");
7045 HeapFree(GetProcessHeap(), 0, buf);
7046 LeaveCriticalSection( &freetype_cs );
7047 return 0;
7050 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7052 FT_UInt glyph_code;
7053 FT_ULong char_code;
7055 glyph_code = 0;
7056 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7058 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7059 font->ft_face->num_glyphs, glyph_code, char_code);
7061 while (glyph_code)
7063 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7065 /* FIXME: This doesn't match what Windows does: it does some fancy
7066 * things with duplicate glyph index to char code mappings, while
7067 * we just avoid overriding existing entries.
7069 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7070 glyph_to_char[glyph_code] = (USHORT)char_code;
7072 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7075 else
7077 ULONG n;
7079 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7080 for (n = 0; n <= 65535; n++)
7081 glyph_to_char[n] = (USHORT)n;
7084 tt_kern_table = buf;
7085 nTables = GET_BE_WORD(tt_kern_table->nTables);
7086 TRACE("version %u, nTables %u\n",
7087 GET_BE_WORD(tt_kern_table->version), nTables);
7089 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7091 for (i = 0; i < nTables; i++)
7093 struct TT_kern_subtable tt_kern_subtable_copy;
7095 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7096 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7097 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7099 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7100 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7101 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7103 /* According to the TrueType specification this is the only format
7104 * that will be properly interpreted by Windows and OS/2
7106 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7108 DWORD new_chunk, old_total = font->total_kern_pairs;
7110 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7111 glyph_to_char, NULL, 0);
7112 font->total_kern_pairs += new_chunk;
7114 if (!font->kern_pairs)
7115 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7116 font->total_kern_pairs * sizeof(*font->kern_pairs));
7117 else
7118 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7119 font->total_kern_pairs * sizeof(*font->kern_pairs));
7121 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7122 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7124 else
7125 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7127 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7130 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7131 HeapFree(GetProcessHeap(), 0, buf);
7133 if (cPairs && kern_pair)
7135 cPairs = min(cPairs, font->total_kern_pairs);
7136 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7138 else cPairs = font->total_kern_pairs;
7140 LeaveCriticalSection( &freetype_cs );
7141 return cPairs;
7144 static const struct gdi_dc_funcs freetype_funcs =
7146 NULL, /* pAbortDoc */
7147 NULL, /* pAbortPath */
7148 NULL, /* pAlphaBlend */
7149 NULL, /* pAngleArc */
7150 NULL, /* pArc */
7151 NULL, /* pArcTo */
7152 NULL, /* pBeginPath */
7153 NULL, /* pBlendImage */
7154 NULL, /* pChoosePixelFormat */
7155 NULL, /* pChord */
7156 NULL, /* pCloseFigure */
7157 NULL, /* pCopyBitmap */
7158 NULL, /* pCreateBitmap */
7159 NULL, /* pCreateCompatibleDC */
7160 freetype_CreateDC, /* pCreateDC */
7161 NULL, /* pDeleteBitmap */
7162 freetype_DeleteDC, /* pDeleteDC */
7163 NULL, /* pDeleteObject */
7164 NULL, /* pDescribePixelFormat */
7165 NULL, /* pDeviceCapabilities */
7166 NULL, /* pEllipse */
7167 NULL, /* pEndDoc */
7168 NULL, /* pEndPage */
7169 NULL, /* pEndPath */
7170 freetype_EnumFonts, /* pEnumFonts */
7171 NULL, /* pEnumICMProfiles */
7172 NULL, /* pExcludeClipRect */
7173 NULL, /* pExtDeviceMode */
7174 NULL, /* pExtEscape */
7175 NULL, /* pExtFloodFill */
7176 NULL, /* pExtSelectClipRgn */
7177 NULL, /* pExtTextOut */
7178 NULL, /* pFillPath */
7179 NULL, /* pFillRgn */
7180 NULL, /* pFlattenPath */
7181 freetype_FontIsLinked, /* pFontIsLinked */
7182 NULL, /* pFrameRgn */
7183 NULL, /* pGdiComment */
7184 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7185 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7186 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7187 freetype_GetCharWidth, /* pGetCharWidth */
7188 NULL, /* pGetDeviceCaps */
7189 NULL, /* pGetDeviceGammaRamp */
7190 freetype_GetFontData, /* pGetFontData */
7191 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7192 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7193 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7194 NULL, /* pGetICMProfile */
7195 NULL, /* pGetImage */
7196 freetype_GetKerningPairs, /* pGetKerningPairs */
7197 NULL, /* pGetNearestColor */
7198 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7199 NULL, /* pGetPixel */
7200 NULL, /* pGetPixelFormat */
7201 NULL, /* pGetSystemPaletteEntries */
7202 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7203 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7204 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7205 freetype_GetTextFace, /* pGetTextFace */
7206 freetype_GetTextMetrics, /* pGetTextMetrics */
7207 NULL, /* pGradientFill */
7208 NULL, /* pIntersectClipRect */
7209 NULL, /* pInvertRgn */
7210 NULL, /* pLineTo */
7211 NULL, /* pModifyWorldTransform */
7212 NULL, /* pMoveTo */
7213 NULL, /* pOffsetClipRgn */
7214 NULL, /* pOffsetViewportOrg */
7215 NULL, /* pOffsetWindowOrg */
7216 NULL, /* pPaintRgn */
7217 NULL, /* pPatBlt */
7218 NULL, /* pPie */
7219 NULL, /* pPolyBezier */
7220 NULL, /* pPolyBezierTo */
7221 NULL, /* pPolyDraw */
7222 NULL, /* pPolyPolygon */
7223 NULL, /* pPolyPolyline */
7224 NULL, /* pPolygon */
7225 NULL, /* pPolyline */
7226 NULL, /* pPolylineTo */
7227 NULL, /* pPutImage */
7228 NULL, /* pRealizeDefaultPalette */
7229 NULL, /* pRealizePalette */
7230 NULL, /* pRectangle */
7231 NULL, /* pResetDC */
7232 NULL, /* pRestoreDC */
7233 NULL, /* pRoundRect */
7234 NULL, /* pSaveDC */
7235 NULL, /* pScaleViewportExt */
7236 NULL, /* pScaleWindowExt */
7237 NULL, /* pSelectBitmap */
7238 NULL, /* pSelectBrush */
7239 NULL, /* pSelectClipPath */
7240 freetype_SelectFont, /* pSelectFont */
7241 NULL, /* pSelectPalette */
7242 NULL, /* pSelectPen */
7243 NULL, /* pSetArcDirection */
7244 NULL, /* pSetBkColor */
7245 NULL, /* pSetBkMode */
7246 NULL, /* pSetDCBrushColor */
7247 NULL, /* pSetDCPenColor */
7248 NULL, /* pSetDIBColorTable */
7249 NULL, /* pSetDIBitsToDevice */
7250 NULL, /* pSetDeviceClipping */
7251 NULL, /* pSetDeviceGammaRamp */
7252 NULL, /* pSetLayout */
7253 NULL, /* pSetMapMode */
7254 NULL, /* pSetMapperFlags */
7255 NULL, /* pSetPixel */
7256 NULL, /* pSetPixelFormat */
7257 NULL, /* pSetPolyFillMode */
7258 NULL, /* pSetROP2 */
7259 NULL, /* pSetRelAbs */
7260 NULL, /* pSetStretchBltMode */
7261 NULL, /* pSetTextAlign */
7262 NULL, /* pSetTextCharacterExtra */
7263 NULL, /* pSetTextColor */
7264 NULL, /* pSetTextJustification */
7265 NULL, /* pSetViewportExt */
7266 NULL, /* pSetViewportOrg */
7267 NULL, /* pSetWindowExt */
7268 NULL, /* pSetWindowOrg */
7269 NULL, /* pSetWorldTransform */
7270 NULL, /* pStartDoc */
7271 NULL, /* pStartPage */
7272 NULL, /* pStretchBlt */
7273 NULL, /* pStretchDIBits */
7274 NULL, /* pStrokeAndFillPath */
7275 NULL, /* pStrokePath */
7276 NULL, /* pSwapBuffers */
7277 NULL, /* pUnrealizePalette */
7278 NULL, /* pWidenPath */
7279 /* OpenGL not supported */
7282 #else /* HAVE_FREETYPE */
7284 /*************************************************************************/
7286 BOOL WineEngInit(void)
7288 return FALSE;
7290 BOOL WineEngDestroyFontInstance(HFONT hfont)
7292 return FALSE;
7295 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7297 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7298 return 1;
7301 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7303 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7304 return TRUE;
7307 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7309 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7310 return NULL;
7313 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7315 return FALSE;
7318 /*************************************************************************
7319 * GetRasterizerCaps (GDI32.@)
7321 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7323 lprs->nSize = sizeof(RASTERIZER_STATUS);
7324 lprs->wFlags = 0;
7325 lprs->nLanguageID = 0;
7326 return TRUE;
7329 #endif /* HAVE_FREETYPE */