gdi32: Use find_family_from_any_name to find a replacement family.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob8caa44158af27293d949f231ed3ec763dfdc71f1
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 #include "resource.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FREETYPE
98 #ifdef HAVE_FT2BUILD_H
99 #include <ft2build.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
103 #endif
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
106 #endif
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
112 #endif
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
115 #endif
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
118 #endif
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
121 #endif
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
124 #endif
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
127 #endif
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
130 #endif
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
173 #else
174 MAKE_FUNCPTR(FT_MulFix);
175 #endif
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetString);
205 #endif
207 #undef MAKE_FUNCPTR
209 #ifndef FT_MAKE_TAG
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
213 #endif
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
217 #endif
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
220 #endif
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
223 #endif
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
226 #endif
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
230 #else
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
232 #endif
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
235 typedef struct {
236 FT_Short height;
237 FT_Short width;
238 FT_Pos size;
239 FT_Pos x_ppem;
240 FT_Pos y_ppem;
241 FT_Short internal_leading;
242 } Bitmap_Size;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
247 typedef struct {
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
250 } My_FT_Bitmap_Size;
252 struct enum_data
254 ENUMLOGFONTEXW elf;
255 NEWTEXTMETRICEXW ntm;
256 DWORD type;
259 typedef struct tagFace {
260 struct list entry;
261 WCHAR *StyleName;
262 WCHAR *FullName;
263 char *file;
264 void *font_data_ptr;
265 DWORD font_data_size;
266 FT_Long face_index;
267 FONTSIGNATURE fs;
268 FONTSIGNATURE fs_links;
269 DWORD ntmFlags;
270 FT_Fixed font_version;
271 BOOL scalable;
272 BOOL vertical;
273 Bitmap_Size size; /* set if face is a bitmap */
274 BOOL external; /* TRUE if we should manually add this font to the registry */
275 struct tagFamily *family;
276 /* Cached data for Enum */
277 struct enum_data *cached_enum_data;
278 } Face;
280 typedef struct tagFamily {
281 struct list entry;
282 const WCHAR *FamilyName;
283 const WCHAR *EnglishName;
284 struct list faces;
285 } Family;
287 typedef struct {
288 GLYPHMETRICS gm;
289 INT adv; /* These three hold to widths of the unrotated chars */
290 INT lsb;
291 INT bbx;
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct {
313 struct list entry;
314 Face *face;
315 GdiFont *font;
316 } CHILD_FONT;
318 struct tagGdiFont {
319 struct list entry;
320 GM **gm;
321 DWORD gmsize;
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
329 FT_Face ft_face;
330 struct font_mapping *mapping;
331 LPWSTR name;
332 int charset;
333 int codepage;
334 BOOL fake_italic;
335 BOOL fake_bold;
336 BYTE underline;
337 BYTE strikeout;
338 INT orientation;
339 FONT_DESC font_desc;
340 LONG aveWidth, ppem;
341 double scale_y;
342 SHORT yMax;
343 SHORT yMin;
344 DWORD ntmFlags;
345 FONTSIGNATURE fs;
346 GdiFont *base_font;
347 VOID *GSUB_Table;
348 DWORD cache_num;
351 typedef struct {
352 struct list entry;
353 const WCHAR *font_name;
354 struct list links;
355 } SYSTEM_LINKS;
357 struct enum_charset_element {
358 DWORD mask;
359 DWORD charset;
360 WCHAR name[LF_FACESIZE];
363 struct enum_charset_list {
364 DWORD total;
365 struct enum_charset_element element[32];
368 #define GM_BLOCK_SIZE 128
369 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
371 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
372 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
373 #define UNUSED_CACHE_SIZE 10
374 static struct list child_font_list = LIST_INIT(child_font_list);
375 static struct list system_links = LIST_INIT(system_links);
377 static struct list font_subst_list = LIST_INIT(font_subst_list);
379 static struct list font_list = LIST_INIT(font_list);
381 struct freetype_physdev
383 struct gdi_physdev dev;
384 GdiFont *font;
387 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
389 return (struct freetype_physdev *)dev;
392 static const struct gdi_dc_funcs freetype_funcs;
394 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
395 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
396 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
398 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
399 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
400 'W','i','n','d','o','w','s','\\',
401 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
402 'F','o','n','t','s','\0'};
404 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
405 'W','i','n','d','o','w','s',' ','N','T','\\',
406 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
407 'F','o','n','t','s','\0'};
409 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
410 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
411 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
412 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
414 static const WCHAR * const SystemFontValues[] = {
415 System_Value,
416 OEMFont_Value,
417 FixedSys_Value,
418 NULL
421 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
422 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
424 /* Interesting and well-known (frequently-assumed!) font names */
425 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
426 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
427 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
428 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
429 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
430 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
431 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
432 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
434 static const WCHAR arial[] = {'A','r','i','a','l',0};
435 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
436 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
437 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
438 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
439 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
440 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
441 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
442 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
443 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
445 static const WCHAR *default_serif_list[] =
447 times_new_roman,
448 liberation_serif,
449 bitstream_vera_serif,
450 NULL
453 static const WCHAR *default_fixed_list[] =
455 courier_new,
456 liberation_mono,
457 bitstream_vera_sans_mono,
458 NULL
461 static const WCHAR *default_sans_list[] =
463 arial,
464 liberation_sans,
465 bitstream_vera_sans,
466 NULL
469 typedef struct {
470 WCHAR *name;
471 INT charset;
472 } NameCs;
474 typedef struct tagFontSubst {
475 struct list entry;
476 NameCs from;
477 NameCs to;
478 } FontSubst;
480 /* Registry font cache key and value names */
481 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
482 'F','o','n','t','s',0};
483 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
484 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
485 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
486 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
487 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
488 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
489 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
490 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
491 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
492 static const WCHAR face_size_value[] = {'S','i','z','e',0};
493 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
494 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
495 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
496 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
497 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
500 struct font_mapping
502 struct list entry;
503 int refcount;
504 dev_t dev;
505 ino_t ino;
506 void *data;
507 size_t size;
510 static struct list mappings_list = LIST_INIT( mappings_list );
512 static CRITICAL_SECTION freetype_cs;
513 static CRITICAL_SECTION_DEBUG critsect_debug =
515 0, 0, &freetype_cs,
516 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
517 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
519 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
521 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
523 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
524 static BOOL use_default_fallback = FALSE;
526 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
527 static BOOL get_outline_text_metrics(GdiFont *font);
528 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
530 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
531 'W','i','n','d','o','w','s',' ','N','T','\\',
532 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
533 'S','y','s','t','e','m','L','i','n','k',0};
535 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
536 'F','o','n','t','L','i','n','k','\\',
537 'S','y','s','t','e','m','L','i','n','k',0};
539 /****************************************
540 * Notes on .fon files
542 * The fonts System, FixedSys and Terminal are special. There are typically multiple
543 * versions installed for different resolutions and codepages. Windows stores which one to use
544 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
545 * Key Meaning
546 * FIXEDFON.FON FixedSys
547 * FONTS.FON System
548 * OEMFONT.FON Terminal
549 * LogPixels Current dpi set by the display control panel applet
550 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
551 * also has a LogPixels value that appears to mirror this)
553 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
554 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
555 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
556 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
557 * so that makes sense.
559 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
560 * to be mapped into the registry on Windows 2000 at least).
561 * I have
562 * woafont=app850.fon
563 * ega80woa.fon=ega80850.fon
564 * ega40woa.fon=ega40850.fon
565 * cga80woa.fon=cga80850.fon
566 * cga40woa.fon=cga40850.fon
569 /* These are all structures needed for the GSUB table */
571 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
572 #define TATEGAKI_LOWER_BOUND 0x02F1
574 typedef struct {
575 DWORD version;
576 WORD ScriptList;
577 WORD FeatureList;
578 WORD LookupList;
579 } GSUB_Header;
581 typedef struct {
582 CHAR ScriptTag[4];
583 WORD Script;
584 } GSUB_ScriptRecord;
586 typedef struct {
587 WORD ScriptCount;
588 GSUB_ScriptRecord ScriptRecord[1];
589 } GSUB_ScriptList;
591 typedef struct {
592 CHAR LangSysTag[4];
593 WORD LangSys;
594 } GSUB_LangSysRecord;
596 typedef struct {
597 WORD DefaultLangSys;
598 WORD LangSysCount;
599 GSUB_LangSysRecord LangSysRecord[1];
600 } GSUB_Script;
602 typedef struct {
603 WORD LookupOrder; /* Reserved */
604 WORD ReqFeatureIndex;
605 WORD FeatureCount;
606 WORD FeatureIndex[1];
607 } GSUB_LangSys;
609 typedef struct {
610 CHAR FeatureTag[4];
611 WORD Feature;
612 } GSUB_FeatureRecord;
614 typedef struct {
615 WORD FeatureCount;
616 GSUB_FeatureRecord FeatureRecord[1];
617 } GSUB_FeatureList;
619 typedef struct {
620 WORD FeatureParams; /* Reserved */
621 WORD LookupCount;
622 WORD LookupListIndex[1];
623 } GSUB_Feature;
625 typedef struct {
626 WORD LookupCount;
627 WORD Lookup[1];
628 } GSUB_LookupList;
630 typedef struct {
631 WORD LookupType;
632 WORD LookupFlag;
633 WORD SubTableCount;
634 WORD SubTable[1];
635 } GSUB_LookupTable;
637 typedef struct {
638 WORD CoverageFormat;
639 WORD GlyphCount;
640 WORD GlyphArray[1];
641 } GSUB_CoverageFormat1;
643 typedef struct {
644 WORD Start;
645 WORD End;
646 WORD StartCoverageIndex;
647 } GSUB_RangeRecord;
649 typedef struct {
650 WORD CoverageFormat;
651 WORD RangeCount;
652 GSUB_RangeRecord RangeRecord[1];
653 } GSUB_CoverageFormat2;
655 typedef struct {
656 WORD SubstFormat; /* = 1 */
657 WORD Coverage;
658 WORD DeltaGlyphID;
659 } GSUB_SingleSubstFormat1;
661 typedef struct {
662 WORD SubstFormat; /* = 2 */
663 WORD Coverage;
664 WORD GlyphCount;
665 WORD Substitute[1];
666 }GSUB_SingleSubstFormat2;
668 #ifdef HAVE_CARBON_CARBON_H
669 static char *find_cache_dir(void)
671 FSRef ref;
672 OSErr err;
673 static char cached_path[MAX_PATH];
674 static const char *wine = "/Wine", *fonts = "/Fonts";
676 if(*cached_path) return cached_path;
678 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
679 if(err != noErr)
681 WARN("can't create cached data folder\n");
682 return NULL;
684 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
685 if(err != noErr)
687 WARN("can't create cached data path\n");
688 *cached_path = '\0';
689 return NULL;
691 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
693 ERR("Could not create full path\n");
694 *cached_path = '\0';
695 return NULL;
697 strcat(cached_path, wine);
699 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
701 WARN("Couldn't mkdir %s\n", cached_path);
702 *cached_path = '\0';
703 return NULL;
705 strcat(cached_path, fonts);
706 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
708 WARN("Couldn't mkdir %s\n", cached_path);
709 *cached_path = '\0';
710 return NULL;
712 return cached_path;
715 /******************************************************************
716 * expand_mac_font
718 * Extracts individual TrueType font files from a Mac suitcase font
719 * and saves them into the user's caches directory (see
720 * find_cache_dir()).
721 * Returns a NULL terminated array of filenames.
723 * We do this because they are apps that try to read ttf files
724 * themselves and they don't like Mac suitcase files.
726 static char **expand_mac_font(const char *path)
728 FSRef ref;
729 SInt16 res_ref;
730 OSStatus s;
731 unsigned int idx;
732 const char *out_dir;
733 const char *filename;
734 int output_len;
735 struct {
736 char **array;
737 unsigned int size, max_size;
738 } ret;
740 TRACE("path %s\n", path);
742 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
743 if(s != noErr)
745 WARN("failed to get ref\n");
746 return NULL;
749 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
750 if(s != noErr)
752 TRACE("no data fork, so trying resource fork\n");
753 res_ref = FSOpenResFile(&ref, fsRdPerm);
754 if(res_ref == -1)
756 TRACE("unable to open resource fork\n");
757 return NULL;
761 ret.size = 0;
762 ret.max_size = 10;
763 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
764 if(!ret.array)
766 CloseResFile(res_ref);
767 return NULL;
770 out_dir = find_cache_dir();
772 filename = strrchr(path, '/');
773 if(!filename) filename = path;
774 else filename++;
776 /* output filename has the form out_dir/filename_%04x.ttf */
777 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
779 UseResFile(res_ref);
780 idx = 1;
781 while(1)
783 FamRec *fam_rec;
784 unsigned short *num_faces_ptr, num_faces, face;
785 AsscEntry *assoc;
786 Handle fond;
787 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
789 fond = Get1IndResource(fond_res, idx);
790 if(!fond) break;
791 TRACE("got fond resource %d\n", idx);
792 HLock(fond);
794 fam_rec = *(FamRec**)fond;
795 num_faces_ptr = (unsigned short *)(fam_rec + 1);
796 num_faces = GET_BE_WORD(*num_faces_ptr);
797 num_faces++;
798 assoc = (AsscEntry*)(num_faces_ptr + 1);
799 TRACE("num faces %04x\n", num_faces);
800 for(face = 0; face < num_faces; face++, assoc++)
802 Handle sfnt;
803 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
804 unsigned short size, font_id;
805 char *output;
807 size = GET_BE_WORD(assoc->fontSize);
808 font_id = GET_BE_WORD(assoc->fontID);
809 if(size != 0)
811 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
812 continue;
815 TRACE("trying to load sfnt id %04x\n", font_id);
816 sfnt = GetResource(sfnt_res, font_id);
817 if(!sfnt)
819 TRACE("can't get sfnt resource %04x\n", font_id);
820 continue;
823 output = HeapAlloc(GetProcessHeap(), 0, output_len);
824 if(output)
826 int fd;
828 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
830 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
831 if(fd != -1 || errno == EEXIST)
833 if(fd != -1)
835 unsigned char *sfnt_data;
837 HLock(sfnt);
838 sfnt_data = *(unsigned char**)sfnt;
839 write(fd, sfnt_data, GetHandleSize(sfnt));
840 HUnlock(sfnt);
841 close(fd);
843 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
845 ret.max_size *= 2;
846 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
848 ret.array[ret.size++] = output;
850 else
852 WARN("unable to create %s\n", output);
853 HeapFree(GetProcessHeap(), 0, output);
856 ReleaseResource(sfnt);
858 HUnlock(fond);
859 ReleaseResource(fond);
860 idx++;
862 CloseResFile(res_ref);
864 return ret.array;
867 #endif /* HAVE_CARBON_CARBON_H */
869 static inline BOOL is_win9x(void)
871 return GetVersion() & 0x80000000;
874 This function builds an FT_Fixed from a double. It fails if the absolute
875 value of the float number is greater than 32768.
877 static inline FT_Fixed FT_FixedFromFloat(double f)
879 return f * 0x10000;
883 This function builds an FT_Fixed from a FIXED. It simply put f.value
884 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
886 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
888 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
892 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
894 Family *family;
895 Face *face;
896 const char *file;
897 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
898 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
900 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
901 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
903 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
905 if(face_name && strcmpiW(face_name, family->FamilyName))
906 continue;
907 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
909 if (!face->file)
910 continue;
911 file = strrchr(face->file, '/');
912 if(!file)
913 file = face->file;
914 else
915 file++;
916 if(!strcasecmp(file, file_nameA))
918 HeapFree(GetProcessHeap(), 0, file_nameA);
919 return face;
923 HeapFree(GetProcessHeap(), 0, file_nameA);
924 return NULL;
927 static Family *find_family_from_name(const WCHAR *name)
929 Family *family;
931 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
933 if(!strcmpiW(family->FamilyName, name))
934 return family;
937 return NULL;
940 static Family *find_family_from_any_name(const WCHAR *name)
942 Family *family;
944 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
946 if(!strcmpiW(family->FamilyName, name))
947 return family;
948 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
949 return family;
952 return NULL;
955 static void DumpSubstList(void)
957 FontSubst *psub;
959 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
961 if(psub->from.charset != -1 || psub->to.charset != -1)
962 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
963 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
964 else
965 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
966 debugstr_w(psub->to.name));
968 return;
971 static LPWSTR strdupW(LPCWSTR p)
973 LPWSTR ret;
974 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
975 ret = HeapAlloc(GetProcessHeap(), 0, len);
976 memcpy(ret, p, len);
977 return ret;
980 static LPSTR strdupA(LPCSTR p)
982 LPSTR ret;
983 DWORD len = (strlen(p) + 1);
984 ret = HeapAlloc(GetProcessHeap(), 0, len);
985 memcpy(ret, p, len);
986 return ret;
989 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
990 INT from_charset)
992 FontSubst *element;
994 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
996 if(!strcmpiW(element->from.name, from_name) &&
997 (element->from.charset == from_charset ||
998 element->from.charset == -1))
999 return element;
1002 return NULL;
1005 #define ADD_FONT_SUBST_FORCE 1
1007 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1009 FontSubst *from_exist, *to_exist;
1011 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1013 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1015 list_remove(&from_exist->entry);
1016 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1017 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1018 HeapFree(GetProcessHeap(), 0, from_exist);
1019 from_exist = NULL;
1022 if(!from_exist)
1024 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1026 if(to_exist)
1028 HeapFree(GetProcessHeap(), 0, subst->to.name);
1029 subst->to.name = strdupW(to_exist->to.name);
1032 list_add_tail(subst_list, &subst->entry);
1034 return TRUE;
1037 HeapFree(GetProcessHeap(), 0, subst->from.name);
1038 HeapFree(GetProcessHeap(), 0, subst->to.name);
1039 HeapFree(GetProcessHeap(), 0, subst);
1040 return FALSE;
1043 static WCHAR *towstr(UINT cp, const char *str)
1045 int len;
1046 WCHAR *wstr;
1048 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1049 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1050 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1051 return wstr;
1054 static void split_subst_info(NameCs *nc, LPSTR str)
1056 CHAR *p = strrchr(str, ',');
1058 nc->charset = -1;
1059 if(p && *(p+1)) {
1060 nc->charset = strtol(p+1, NULL, 10);
1061 *p = '\0';
1063 nc->name = towstr(CP_ACP, str);
1066 static void LoadSubstList(void)
1068 FontSubst *psub;
1069 HKEY hkey;
1070 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1071 LPSTR value;
1072 LPVOID data;
1074 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1075 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1076 &hkey) == ERROR_SUCCESS) {
1078 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1079 &valuelen, &datalen, NULL, NULL);
1081 valuelen++; /* returned value doesn't include room for '\0' */
1082 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1083 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1085 dlen = datalen;
1086 vlen = valuelen;
1087 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1088 &dlen) == ERROR_SUCCESS) {
1089 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1091 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1092 split_subst_info(&psub->from, value);
1093 split_subst_info(&psub->to, data);
1095 /* Win 2000 doesn't allow mapping between different charsets
1096 or mapping of DEFAULT_CHARSET */
1097 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1098 psub->to.charset == DEFAULT_CHARSET) {
1099 HeapFree(GetProcessHeap(), 0, psub->to.name);
1100 HeapFree(GetProcessHeap(), 0, psub->from.name);
1101 HeapFree(GetProcessHeap(), 0, psub);
1102 } else {
1103 add_font_subst(&font_subst_list, psub, 0);
1105 /* reset dlen and vlen */
1106 dlen = datalen;
1107 vlen = valuelen;
1109 HeapFree(GetProcessHeap(), 0, data);
1110 HeapFree(GetProcessHeap(), 0, value);
1111 RegCloseKey(hkey);
1116 /*****************************************************************
1117 * get_name_table_entry
1119 * Supply the platform, encoding, language and name ids in req
1120 * and if the name exists the function will fill in the string
1121 * and string_len members. The string is owned by FreeType so
1122 * don't free it. Returns TRUE if the name is found else FALSE.
1124 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1126 FT_SfntName name;
1127 FT_UInt num_names, name_index;
1129 if(FT_IS_SFNT(ft_face))
1131 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1133 for(name_index = 0; name_index < num_names; name_index++)
1135 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1137 if((name.platform_id == req->platform_id) &&
1138 (name.encoding_id == req->encoding_id) &&
1139 (name.language_id == req->language_id) &&
1140 (name.name_id == req->name_id))
1142 req->string = name.string;
1143 req->string_len = name.string_len;
1144 return TRUE;
1149 req->string = NULL;
1150 req->string_len = 0;
1151 return FALSE;
1154 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1156 WCHAR *ret = NULL;
1157 FT_SfntName name;
1159 name.platform_id = TT_PLATFORM_MICROSOFT;
1160 name.encoding_id = TT_MS_ID_UNICODE_CS;
1161 name.language_id = language_id;
1162 name.name_id = name_id;
1164 if(get_name_table_entry(ft_face, &name))
1166 FT_UInt i;
1168 /* String is not nul terminated and string_len is a byte length. */
1169 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1170 for(i = 0; i < name.string_len / 2; i++)
1172 WORD *tmp = (WORD *)&name.string[i * 2];
1173 ret[i] = GET_BE_WORD(*tmp);
1175 ret[i] = 0;
1176 TRACE("Got localised name %s\n", debugstr_w(ret));
1179 return ret;
1182 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1184 DWORD type, needed;
1185 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1186 if(r != ERROR_SUCCESS) return r;
1187 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1188 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1191 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1193 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1196 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1198 DWORD needed;
1199 DWORD num_strikes, max_strike_key_len;
1201 /* If we have a File Name key then this is a real font, not just the parent
1202 key of a bunch of non-scalable strikes */
1203 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1205 DWORD italic, bold;
1206 Face *face;
1207 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1208 face->cached_enum_data = NULL;
1210 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1211 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1213 face->StyleName = strdupW(face_name);
1214 face->family = family;
1215 face->vertical = (family->FamilyName[0] == '@');
1217 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1219 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1220 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1221 face->FullName = fullName;
1223 else
1224 face->FullName = NULL;
1226 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1227 reg_load_dword(hkey_face, face_italic_value, &italic);
1228 reg_load_dword(hkey_face, face_bold_value, &bold);
1229 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1230 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1232 needed = sizeof(face->fs);
1233 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1234 memset(&face->fs_links, 0, sizeof(face->fs_links));
1236 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1238 face->scalable = TRUE;
1239 memset(&face->size, 0, sizeof(face->size));
1241 else
1243 face->scalable = FALSE;
1244 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1245 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1246 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1247 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1248 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1250 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1251 face->size.height, face->size.width, face->size.size >> 6,
1252 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1255 face->ntmFlags = 0;
1256 if (italic) face->ntmFlags |= NTM_ITALIC;
1257 if (bold) face->ntmFlags |= NTM_BOLD;
1258 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1260 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1261 face->fs.fsCsb[0], face->fs.fsCsb[1],
1262 face->fs.fsUsb[0], face->fs.fsUsb[1],
1263 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1265 if(!italic && !bold)
1266 list_add_head(&family->faces, &face->entry);
1267 else
1268 list_add_tail(&family->faces, &face->entry);
1270 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1273 /* do we have any bitmap strikes? */
1274 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1275 NULL, NULL, NULL, NULL);
1276 if(num_strikes != 0)
1278 WCHAR strike_name[10];
1279 DWORD strike_index = 0;
1281 needed = sizeof(strike_name) / sizeof(WCHAR);
1282 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1283 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1285 HKEY hkey_strike;
1286 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1287 load_face(hkey_strike, face_name, family);
1288 RegCloseKey(hkey_strike);
1289 needed = sizeof(strike_name) / sizeof(WCHAR);
1294 static void load_font_list_from_cache(HKEY hkey_font_cache)
1296 DWORD max_family_key_len, size;
1297 WCHAR *family_name;
1298 DWORD family_index = 0;
1299 Family *family;
1300 HKEY hkey_family;
1302 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1303 NULL, NULL, NULL, NULL);
1304 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1306 size = max_family_key_len + 1;
1307 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1308 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1310 WCHAR *english_family = NULL;
1311 DWORD face_index = 0;
1312 WCHAR *face_name;
1313 DWORD max_face_key_len;
1315 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1316 TRACE("opened family key %s\n", debugstr_w(family_name));
1317 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1319 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1320 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1323 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1324 family->FamilyName = strdupW(family_name);
1325 family->EnglishName = english_family;
1326 list_init(&family->faces);
1327 list_add_tail(&font_list, &family->entry);
1329 if(english_family)
1331 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1332 subst->from.name = strdupW(english_family);
1333 subst->from.charset = -1;
1334 subst->to.name = strdupW(family_name);
1335 subst->to.charset = -1;
1336 add_font_subst(&font_subst_list, subst, 0);
1339 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1340 NULL, NULL, NULL, NULL);
1342 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1343 size = max_face_key_len + 1;
1344 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1345 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1347 HKEY hkey_face;
1349 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1350 load_face(hkey_face, face_name, family);
1351 RegCloseKey(hkey_face);
1352 size = max_face_key_len + 1;
1354 HeapFree(GetProcessHeap(), 0, face_name);
1355 RegCloseKey(hkey_family);
1356 size = max_family_key_len + 1;
1359 HeapFree(GetProcessHeap(), 0, family_name);
1362 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1364 LONG ret;
1365 HKEY hkey_wine_fonts;
1367 /* We don't want to create the fonts key as volatile, so open this first */
1368 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1369 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1370 if(ret != ERROR_SUCCESS)
1372 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1373 return ret;
1376 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1377 KEY_ALL_ACCESS, NULL, hkey, disposition);
1378 RegCloseKey(hkey_wine_fonts);
1379 return ret;
1382 static void add_face_to_cache(Face *face)
1384 HKEY hkey_font_cache, hkey_family, hkey_face;
1385 WCHAR *face_key_name;
1387 create_font_cache_key(&hkey_font_cache, NULL);
1389 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1390 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1391 if(face->family->EnglishName)
1392 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1393 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1395 if(face->scalable)
1396 face_key_name = face->StyleName;
1397 else
1399 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1400 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1401 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1403 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1404 &hkey_face, NULL);
1405 if(!face->scalable)
1406 HeapFree(GetProcessHeap(), 0, face_key_name);
1408 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1409 if (face->FullName)
1410 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1411 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1413 reg_save_dword(hkey_face, face_index_value, face->face_index);
1414 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1415 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1416 reg_save_dword(hkey_face, face_version_value, face->font_version);
1417 reg_save_dword(hkey_face, face_external_value, face->external);
1419 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1421 if(!face->scalable)
1423 reg_save_dword(hkey_face, face_height_value, face->size.height);
1424 reg_save_dword(hkey_face, face_width_value, face->size.width);
1425 reg_save_dword(hkey_face, face_size_value, face->size.size);
1426 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1427 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1428 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1430 RegCloseKey(hkey_face);
1431 RegCloseKey(hkey_family);
1432 RegCloseKey(hkey_font_cache);
1435 static inline int TestStyles(DWORD flags, DWORD styles)
1437 return (flags & styles) == styles;
1440 static int StyleOrdering(Face *face)
1442 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1443 return 3;
1444 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1445 return 2;
1446 if (TestStyles(face->ntmFlags, NTM_BOLD))
1447 return 1;
1448 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1449 return 0;
1451 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1452 debugstr_w(face->family->FamilyName),
1453 debugstr_w(face->StyleName),
1454 face->ntmFlags);
1456 return 9999;
1459 /* Add a style of face to a font family using an ordering of the list such
1460 that regular fonts come before bold and italic, and single styles come
1461 before compound styles. */
1462 static void AddFaceToFamily(Face *face, Family *family)
1464 struct list *entry;
1466 LIST_FOR_EACH( entry, &family->faces )
1468 Face *ent = LIST_ENTRY(entry, Face, entry);
1469 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1471 list_add_before( entry, &face->entry );
1474 static WCHAR *prepend_at(WCHAR *family)
1476 WCHAR *str;
1478 if (!family)
1479 return NULL;
1481 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1482 str[0] = '@';
1483 strcpyW(str + 1, family);
1484 HeapFree(GetProcessHeap(), 0, family);
1485 return str;
1488 #define ADDFONT_EXTERNAL_FONT 0x01
1489 #define ADDFONT_FORCE_BITMAP 0x02
1490 #define ADDFONT_ADD_TO_CACHE 0x04
1492 static void AddFaceToList(FT_Face ft_face, char *fake_family, const char *file, void *font_data_ptr, DWORD font_data_size, FT_Long face_index, DWORD flags, BOOL vertical)
1494 int bitmap_num = 0;
1495 Family *family;
1496 WCHAR *StyleW;
1498 do {
1499 TT_OS2 *pOS2;
1500 TT_Header *pHeader;
1501 WCHAR *english_family, *localised_family;
1502 Face *face;
1503 struct list *face_elem_ptr;
1504 FT_WinFNT_HeaderRec winfnt_header;
1505 int internal_leading;
1506 FONTSIGNATURE fs;
1507 My_FT_Bitmap_Size *size = NULL;
1508 FT_ULong tmp_size;
1510 if(!FT_IS_SCALABLE(ft_face))
1511 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1513 if (fake_family)
1515 english_family = towstr(CP_ACP, fake_family);
1516 localised_family = NULL;
1518 else
1520 english_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1521 if (!english_family)
1522 english_family = towstr(CP_ACP, ft_face->family_name);
1524 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1525 if (localised_family && !strcmpiW(localised_family, english_family))
1527 HeapFree(GetProcessHeap(), 0, localised_family);
1528 localised_family = NULL;
1532 if (vertical)
1534 english_family = prepend_at(english_family);
1535 localised_family = prepend_at(localised_family);
1538 family = find_family_from_name(localised_family ? localised_family : english_family);
1539 if(!family) {
1540 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1541 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1542 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1543 list_init(&family->faces);
1544 list_add_tail(&font_list, &family->entry);
1546 if(localised_family) {
1547 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1548 subst->from.name = strdupW(english_family);
1549 subst->from.charset = -1;
1550 subst->to.name = strdupW(localised_family);
1551 subst->to.charset = -1;
1552 add_font_subst(&font_subst_list, subst, 0);
1555 HeapFree(GetProcessHeap(), 0, localised_family);
1556 HeapFree(GetProcessHeap(), 0, english_family);
1558 StyleW = towstr(CP_ACP, ft_face->style_name);
1560 internal_leading = 0;
1561 memset(&fs, 0, sizeof(fs));
1563 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1564 if(pOS2) {
1565 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1566 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1567 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1568 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1569 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1570 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1571 if(pOS2->version == 0) {
1572 FT_UInt dummy;
1574 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1575 fs.fsCsb[0] |= FS_LATIN1;
1576 else
1577 fs.fsCsb[0] |= FS_SYMBOL;
1580 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1581 CHARSETINFO csi;
1582 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1583 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1584 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1585 fs = csi.fs;
1586 internal_leading = winfnt_header.internal_leading;
1589 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1590 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1591 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1592 if(!strcmpiW(face->StyleName, StyleW) &&
1593 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1594 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1595 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1596 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1598 if(fake_family) {
1599 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1600 HeapFree(GetProcessHeap(), 0, StyleW);
1601 return;
1603 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1604 TRACE("Original font is newer so skipping this one\n");
1605 HeapFree(GetProcessHeap(), 0, StyleW);
1606 return;
1607 } else {
1608 TRACE("Replacing original with this one\n");
1609 list_remove(&face->entry);
1610 HeapFree(GetProcessHeap(), 0, face->file);
1611 HeapFree(GetProcessHeap(), 0, face->StyleName);
1612 HeapFree(GetProcessHeap(), 0, face->FullName);
1613 HeapFree(GetProcessHeap(), 0, face);
1614 break;
1618 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1619 face->cached_enum_data = NULL;
1620 face->StyleName = StyleW;
1621 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1622 if (file)
1624 face->file = strdupA(file);
1625 face->font_data_ptr = NULL;
1626 face->font_data_size = 0;
1628 else
1630 face->file = NULL;
1631 face->font_data_ptr = font_data_ptr;
1632 face->font_data_size = font_data_size;
1634 face->face_index = face_index;
1635 face->ntmFlags = 0;
1636 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1637 face->ntmFlags |= NTM_ITALIC;
1638 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1639 face->ntmFlags |= NTM_BOLD;
1640 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1641 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1642 face->family = family;
1643 face->vertical = vertical;
1644 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1645 face->fs = fs;
1646 memset(&face->fs_links, 0, sizeof(face->fs_links));
1648 if(FT_IS_SCALABLE(ft_face)) {
1649 memset(&face->size, 0, sizeof(face->size));
1650 face->scalable = TRUE;
1651 } else {
1652 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1653 size->height, size->width, size->size >> 6,
1654 size->x_ppem >> 6, size->y_ppem >> 6);
1655 face->size.height = size->height;
1656 face->size.width = size->width;
1657 face->size.size = size->size;
1658 face->size.x_ppem = size->x_ppem;
1659 face->size.y_ppem = size->y_ppem;
1660 face->size.internal_leading = internal_leading;
1661 face->scalable = FALSE;
1664 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1665 tmp_size = 0;
1666 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1668 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1669 face->ntmFlags |= NTM_PS_OPENTYPE;
1672 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1673 face->fs.fsCsb[0], face->fs.fsCsb[1],
1674 face->fs.fsUsb[0], face->fs.fsUsb[1],
1675 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1677 if(face->fs.fsCsb[0] == 0)
1679 int i;
1681 /* let's see if we can find any interesting cmaps */
1682 for(i = 0; i < ft_face->num_charmaps; i++) {
1683 switch(ft_face->charmaps[i]->encoding) {
1684 case FT_ENCODING_UNICODE:
1685 case FT_ENCODING_APPLE_ROMAN:
1686 face->fs.fsCsb[0] |= FS_LATIN1;
1687 break;
1688 case FT_ENCODING_MS_SYMBOL:
1689 face->fs.fsCsb[0] |= FS_SYMBOL;
1690 break;
1691 default:
1692 break;
1697 if(flags & ADDFONT_ADD_TO_CACHE)
1698 add_face_to_cache(face);
1700 AddFaceToFamily(face, family);
1702 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1704 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1705 debugstr_w(StyleW));
1708 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1710 FT_Face ft_face;
1711 TT_OS2 *pOS2;
1712 TT_Header *pHeader = NULL;
1713 WCHAR *localised_family;
1714 FT_Error err;
1715 FT_Long face_index = 0, num_faces;
1716 INT ret = 0;
1718 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1719 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1721 #ifdef HAVE_CARBON_CARBON_H
1722 if(file && !fake_family)
1724 char **mac_list = expand_mac_font(file);
1725 if(mac_list)
1727 BOOL had_one = FALSE;
1728 char **cursor;
1729 for(cursor = mac_list; *cursor; cursor++)
1731 had_one = TRUE;
1732 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1733 HeapFree(GetProcessHeap(), 0, *cursor);
1735 HeapFree(GetProcessHeap(), 0, mac_list);
1736 if(had_one)
1737 return 1;
1740 #endif /* HAVE_CARBON_CARBON_H */
1742 do {
1743 if (file)
1745 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1746 err = pFT_New_Face(library, file, face_index, &ft_face);
1747 } else
1749 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1750 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1753 if(err != 0) {
1754 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1755 return 0;
1758 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1759 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1760 pFT_Done_Face(ft_face);
1761 return 0;
1764 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1765 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1766 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1767 pFT_Done_Face(ft_face);
1768 return 0;
1771 if(FT_IS_SFNT(ft_face))
1773 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1774 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1775 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1777 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1778 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1779 pFT_Done_Face(ft_face);
1780 return 0;
1783 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1784 we don't want to load these. */
1785 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1787 FT_ULong len = 0;
1789 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1791 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1792 pFT_Done_Face(ft_face);
1793 return 0;
1798 if(!ft_face->family_name || !ft_face->style_name) {
1799 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1800 pFT_Done_Face(ft_face);
1801 return 0;
1804 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1806 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1807 pFT_Done_Face(ft_face);
1808 return 0;
1811 if (target_family)
1813 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1814 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1816 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1817 HeapFree(GetProcessHeap(), 0, localised_family);
1818 num_faces = ft_face->num_faces;
1819 pFT_Done_Face(ft_face);
1820 continue;
1822 HeapFree(GetProcessHeap(), 0, localised_family);
1825 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1826 ++ret;
1828 if (FT_HAS_VERTICAL(ft_face))
1830 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1831 ++ret;
1834 num_faces = ft_face->num_faces;
1835 pFT_Done_Face(ft_face);
1836 } while(num_faces > ++face_index);
1837 return ret;
1840 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1842 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1845 static void DumpFontList(void)
1847 Family *family;
1848 Face *face;
1849 struct list *family_elem_ptr, *face_elem_ptr;
1851 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1852 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1853 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1854 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1855 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1856 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1857 if(!face->scalable)
1858 TRACE(" %d", face->size.height);
1859 TRACE("\n");
1862 return;
1865 /***********************************************************
1866 * The replacement list is a way to map an entire font
1867 * family onto another family. For example adding
1869 * [HKCU\Software\Wine\Fonts\Replacements]
1870 * "Wingdings"="Winedings"
1872 * would enumerate the Winedings font both as Winedings and
1873 * Wingdings. However if a real Wingdings font is present the
1874 * replacement does not take place.
1877 static void LoadReplaceList(void)
1879 HKEY hkey;
1880 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1881 LPWSTR value;
1882 LPVOID data;
1883 CHAR familyA[400];
1885 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1886 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1888 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1889 &valuelen, &datalen, NULL, NULL);
1891 valuelen++; /* returned value doesn't include room for '\0' */
1892 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1893 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1895 dlen = datalen;
1896 vlen = valuelen;
1897 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1898 &dlen) == ERROR_SUCCESS) {
1899 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1900 /* "NewName"="Oldname" */
1901 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1903 if(!find_family_from_any_name(value))
1905 /* Find the old family and hence all of the font files
1906 in that family */
1907 const Family * const family = find_family_from_any_name(data);
1908 if (family != NULL)
1910 const struct list *face_elem_ptr;
1911 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1912 const Face * const face = LIST_ENTRY(face_elem_ptr, Face, entry);
1913 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1914 debugstr_w(face->StyleName), familyA);
1915 /* Now add a new entry with the new family name */
1916 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1917 familyA, family->FamilyName,
1918 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1922 /* reset dlen and vlen */
1923 dlen = datalen;
1924 vlen = valuelen;
1926 HeapFree(GetProcessHeap(), 0, data);
1927 HeapFree(GetProcessHeap(), 0, value);
1928 RegCloseKey(hkey);
1932 static const WCHAR *font_links_list[] =
1934 Lucida_Sans_Unicode,
1935 Microsoft_Sans_Serif,
1936 Tahoma
1939 static const struct font_links_defaults_list
1941 /* Keyed off substitution for "MS Shell Dlg" */
1942 const WCHAR *shelldlg;
1943 /* Maximum of four substitutes, plus terminating NULL pointer */
1944 const WCHAR *substitutes[5];
1945 } font_links_defaults_list[] =
1947 /* Non East-Asian */
1948 { Tahoma, /* FIXME unverified ordering */
1949 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
1951 /* Below lists are courtesy of
1952 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1954 /* Japanese */
1955 { MS_UI_Gothic,
1956 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
1958 /* Chinese Simplified */
1959 { SimSun,
1960 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
1962 /* Korean */
1963 { Gulim,
1964 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
1966 /* Chinese Traditional */
1967 { PMingLiU,
1968 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
1973 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
1975 const WCHAR *value;
1976 int i;
1977 FontSubst *psub;
1978 Family *family;
1979 Face *face;
1980 const char *file;
1981 WCHAR *fileW;
1982 FONTSIGNATURE fs;
1984 if (values)
1986 SYSTEM_LINKS *font_link;
1987 BOOL existing = FALSE;
1989 memset(&fs, 0, sizeof(fs));
1990 psub = get_font_subst(&font_subst_list, name, -1);
1991 /* Don't store fonts that are only substitutes for other fonts */
1992 if(psub)
1994 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
1995 return;
1998 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2000 if(!strcmpiW(font_link->font_name, name))
2002 existing = TRUE;
2003 break;
2007 if (!existing)
2009 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2010 font_link->font_name = strdupW(name);
2011 list_init(&font_link->links);
2014 for (i = 0; values[i] != NULL; i++)
2016 CHILD_FONT *child_font;
2018 value = values[i];
2019 if (!strcmpiW(name,value))
2020 continue;
2021 psub = get_font_subst(&font_subst_list, value, -1);
2022 if(psub)
2023 value = psub->to.name;
2024 family = find_family_from_name(value);
2025 if (!family)
2026 continue;
2027 file = NULL;
2028 /* Use first extant filename for this Family */
2029 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2031 if (!face->file)
2032 continue;
2033 file = strrchr(face->file, '/');
2034 if (!file)
2035 file = face->file;
2036 else
2037 file++;
2038 break;
2040 if (!file)
2041 continue;
2042 fileW = towstr(CP_UNIXCP, file);
2044 face = find_face_from_filename(fileW, value);
2045 if(!face)
2047 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2048 continue;
2051 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2052 child_font->face = face;
2053 child_font->font = NULL;
2054 fs.fsCsb[0] |= face->fs.fsCsb[0];
2055 fs.fsCsb[1] |= face->fs.fsCsb[1];
2056 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2057 list_add_tail(&font_link->links, &child_font->entry);
2059 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2060 HeapFree(GetProcessHeap(), 0, fileW);
2063 family = find_family_from_name(font_link->font_name);
2064 if(family)
2066 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2068 face->fs_links = fs;
2071 if (!existing)
2072 list_add_tail(&system_links, &font_link->entry);
2077 /*************************************************************
2078 * init_system_links
2080 static BOOL init_system_links(void)
2082 HKEY hkey;
2083 BOOL ret = FALSE;
2084 DWORD type, max_val, max_data, val_len, data_len, index;
2085 WCHAR *value, *data;
2086 WCHAR *entry, *next;
2087 SYSTEM_LINKS *font_link, *system_font_link;
2088 CHILD_FONT *child_font;
2089 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2090 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2091 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2092 FONTSIGNATURE fs;
2093 Family *family;
2094 Face *face;
2095 FontSubst *psub;
2096 UINT i, j;
2098 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2100 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2101 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2102 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2103 val_len = max_val + 1;
2104 data_len = max_data;
2105 index = 0;
2106 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2108 memset(&fs, 0, sizeof(fs));
2109 psub = get_font_subst(&font_subst_list, value, -1);
2110 /* Don't store fonts that are only substitutes for other fonts */
2111 if(psub)
2113 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2114 goto next;
2116 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2117 font_link->font_name = strdupW(value);
2118 list_init(&font_link->links);
2119 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2121 WCHAR *face_name;
2122 CHILD_FONT *child_font;
2124 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2126 next = entry + strlenW(entry) + 1;
2128 face_name = strchrW(entry, ',');
2129 if(face_name)
2131 *face_name++ = 0;
2132 while(isspaceW(*face_name))
2133 face_name++;
2135 psub = get_font_subst(&font_subst_list, face_name, -1);
2136 if(psub)
2137 face_name = psub->to.name;
2139 face = find_face_from_filename(entry, face_name);
2140 if(!face)
2142 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2143 continue;
2146 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2147 child_font->face = face;
2148 child_font->font = NULL;
2149 fs.fsCsb[0] |= face->fs.fsCsb[0];
2150 fs.fsCsb[1] |= face->fs.fsCsb[1];
2151 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2152 list_add_tail(&font_link->links, &child_font->entry);
2154 family = find_family_from_name(font_link->font_name);
2155 if(family)
2157 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2159 face->fs_links = fs;
2162 list_add_tail(&system_links, &font_link->entry);
2163 next:
2164 val_len = max_val + 1;
2165 data_len = max_data;
2168 HeapFree(GetProcessHeap(), 0, value);
2169 HeapFree(GetProcessHeap(), 0, data);
2170 RegCloseKey(hkey);
2174 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2175 if (!psub) {
2176 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2177 goto skip_internal;
2180 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2182 const FontSubst *psub2;
2183 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2185 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2187 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2188 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2190 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2191 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2193 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2195 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2199 skip_internal:
2201 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2202 that Tahoma has */
2204 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2205 system_font_link->font_name = strdupW(System);
2206 list_init(&system_font_link->links);
2208 face = find_face_from_filename(tahoma_ttf, Tahoma);
2209 if(face)
2211 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2212 child_font->face = face;
2213 child_font->font = NULL;
2214 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2215 list_add_tail(&system_font_link->links, &child_font->entry);
2217 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2219 if(!strcmpiW(font_link->font_name, Tahoma))
2221 CHILD_FONT *font_link_entry;
2222 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2224 CHILD_FONT *new_child;
2225 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2226 new_child->face = font_link_entry->face;
2227 new_child->font = NULL;
2228 list_add_tail(&system_font_link->links, &new_child->entry);
2230 break;
2233 list_add_tail(&system_links, &system_font_link->entry);
2234 return ret;
2237 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2239 DIR *dir;
2240 struct dirent *dent;
2241 char path[MAX_PATH];
2243 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2245 dir = opendir(dirname);
2246 if(!dir) {
2247 WARN("Can't open directory %s\n", debugstr_a(dirname));
2248 return FALSE;
2250 while((dent = readdir(dir)) != NULL) {
2251 struct stat statbuf;
2253 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2254 continue;
2256 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2258 sprintf(path, "%s/%s", dirname, dent->d_name);
2260 if(stat(path, &statbuf) == -1)
2262 WARN("Can't stat %s\n", debugstr_a(path));
2263 continue;
2265 if(S_ISDIR(statbuf.st_mode))
2266 ReadFontDir(path, external_fonts);
2267 else
2269 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2270 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2271 AddFontFileToList(path, NULL, NULL, addfont_flags);
2274 closedir(dir);
2275 return TRUE;
2278 static void load_fontconfig_fonts(void)
2280 #ifdef SONAME_LIBFONTCONFIG
2281 void *fc_handle = NULL;
2282 FcConfig *config;
2283 FcPattern *pat;
2284 FcObjectSet *os;
2285 FcFontSet *fontset;
2286 int i, len;
2287 char *file;
2288 const char *ext;
2290 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2291 if(!fc_handle) {
2292 TRACE("Wine cannot find the fontconfig library (%s).\n",
2293 SONAME_LIBFONTCONFIG);
2294 return;
2296 #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;}
2297 LOAD_FUNCPTR(FcConfigGetCurrent);
2298 LOAD_FUNCPTR(FcFontList);
2299 LOAD_FUNCPTR(FcFontSetDestroy);
2300 LOAD_FUNCPTR(FcInit);
2301 LOAD_FUNCPTR(FcObjectSetAdd);
2302 LOAD_FUNCPTR(FcObjectSetCreate);
2303 LOAD_FUNCPTR(FcObjectSetDestroy);
2304 LOAD_FUNCPTR(FcPatternCreate);
2305 LOAD_FUNCPTR(FcPatternDestroy);
2306 LOAD_FUNCPTR(FcPatternGetBool);
2307 LOAD_FUNCPTR(FcPatternGetString);
2308 #undef LOAD_FUNCPTR
2310 if(!pFcInit()) return;
2312 config = pFcConfigGetCurrent();
2313 pat = pFcPatternCreate();
2314 os = pFcObjectSetCreate();
2315 pFcObjectSetAdd(os, FC_FILE);
2316 pFcObjectSetAdd(os, FC_SCALABLE);
2317 fontset = pFcFontList(config, pat, os);
2318 if(!fontset) return;
2319 for(i = 0; i < fontset->nfont; i++) {
2320 FcBool scalable;
2322 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2323 continue;
2324 TRACE("fontconfig: %s\n", file);
2326 /* We're just interested in OT/TT fonts for now, so this hack just
2327 picks up the scalable fonts without extensions .pf[ab] to save time
2328 loading every other font */
2330 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2332 TRACE("not scalable\n");
2333 continue;
2336 len = strlen( file );
2337 if(len < 4) continue;
2338 ext = &file[ len - 3 ];
2339 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2340 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2342 pFcFontSetDestroy(fontset);
2343 pFcObjectSetDestroy(os);
2344 pFcPatternDestroy(pat);
2345 sym_not_found:
2346 #endif
2347 return;
2350 static BOOL load_font_from_data_dir(LPCWSTR file)
2352 BOOL ret = FALSE;
2353 const char *data_dir = wine_get_data_dir();
2355 if (!data_dir) data_dir = wine_get_build_dir();
2357 if (data_dir)
2359 INT len;
2360 char *unix_name;
2362 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2364 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2366 strcpy(unix_name, data_dir);
2367 strcat(unix_name, "/fonts/");
2369 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2371 EnterCriticalSection( &freetype_cs );
2372 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2373 LeaveCriticalSection( &freetype_cs );
2374 HeapFree(GetProcessHeap(), 0, unix_name);
2376 return ret;
2379 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2381 static const WCHAR slashW[] = {'\\','\0'};
2382 BOOL ret = FALSE;
2383 WCHAR windowsdir[MAX_PATH];
2384 char *unixname;
2386 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2387 strcatW(windowsdir, fontsW);
2388 strcatW(windowsdir, slashW);
2389 strcatW(windowsdir, file);
2390 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2391 EnterCriticalSection( &freetype_cs );
2392 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2393 LeaveCriticalSection( &freetype_cs );
2394 HeapFree(GetProcessHeap(), 0, unixname);
2396 return ret;
2399 static void load_system_fonts(void)
2401 HKEY hkey;
2402 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2403 const WCHAR * const *value;
2404 DWORD dlen, type;
2405 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2406 char *unixname;
2408 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2409 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2410 strcatW(windowsdir, fontsW);
2411 for(value = SystemFontValues; *value; value++) {
2412 dlen = sizeof(data);
2413 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2414 type == REG_SZ) {
2415 BOOL added = FALSE;
2417 sprintfW(pathW, fmtW, windowsdir, data);
2418 if((unixname = wine_get_unix_file_name(pathW))) {
2419 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2420 HeapFree(GetProcessHeap(), 0, unixname);
2422 if (!added)
2423 load_font_from_data_dir(data);
2426 RegCloseKey(hkey);
2430 /*************************************************************
2432 * This adds registry entries for any externally loaded fonts
2433 * (fonts from fontconfig or FontDirs). It also deletes entries
2434 * of no longer existing fonts.
2437 static void update_reg_entries(void)
2439 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2440 LPWSTR valueW;
2441 DWORD len, len_fam;
2442 Family *family;
2443 Face *face;
2444 struct list *family_elem_ptr, *face_elem_ptr;
2445 WCHAR *file;
2446 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2447 static const WCHAR spaceW[] = {' ', '\0'};
2448 char *path;
2450 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2451 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2452 ERR("Can't create Windows font reg key\n");
2453 goto end;
2456 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2457 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2458 ERR("Can't create Windows font reg key\n");
2459 goto end;
2462 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2463 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2464 ERR("Can't create external font reg key\n");
2465 goto end;
2468 /* enumerate the fonts and add external ones to the two keys */
2470 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2471 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2472 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2473 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2474 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2475 if(!face->external) continue;
2476 len = len_fam;
2477 if (!(face->ntmFlags & NTM_REGULAR))
2478 len = len_fam + strlenW(face->StyleName) + 1;
2479 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2480 strcpyW(valueW, family->FamilyName);
2481 if(len != len_fam) {
2482 strcatW(valueW, spaceW);
2483 strcatW(valueW, face->StyleName);
2485 strcatW(valueW, TrueType);
2487 file = wine_get_dos_file_name(face->file);
2488 if(file)
2489 len = strlenW(file) + 1;
2490 else
2492 if((path = strrchr(face->file, '/')) == NULL)
2493 path = face->file;
2494 else
2495 path++;
2496 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2498 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2499 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2501 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2502 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2503 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2505 HeapFree(GetProcessHeap(), 0, file);
2506 HeapFree(GetProcessHeap(), 0, valueW);
2509 end:
2510 if(external_key) RegCloseKey(external_key);
2511 if(win9x_key) RegCloseKey(win9x_key);
2512 if(winnt_key) RegCloseKey(winnt_key);
2513 return;
2516 static void delete_external_font_keys(void)
2518 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2519 DWORD dlen, vlen, datalen, valuelen, i, type;
2520 LPWSTR valueW;
2521 LPVOID data;
2523 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2524 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2525 ERR("Can't create Windows font reg key\n");
2526 goto end;
2529 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2530 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2531 ERR("Can't create Windows font reg key\n");
2532 goto end;
2535 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2536 ERR("Can't create external font reg key\n");
2537 goto end;
2540 /* Delete all external fonts added last time */
2542 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2543 &valuelen, &datalen, NULL, NULL);
2544 valuelen++; /* returned value doesn't include room for '\0' */
2545 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2546 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2548 dlen = datalen * sizeof(WCHAR);
2549 vlen = valuelen;
2550 i = 0;
2551 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2552 &dlen) == ERROR_SUCCESS) {
2554 RegDeleteValueW(winnt_key, valueW);
2555 RegDeleteValueW(win9x_key, valueW);
2556 /* reset dlen and vlen */
2557 dlen = datalen;
2558 vlen = valuelen;
2560 HeapFree(GetProcessHeap(), 0, data);
2561 HeapFree(GetProcessHeap(), 0, valueW);
2563 /* Delete the old external fonts key */
2564 RegCloseKey(external_key);
2565 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2567 end:
2568 if(win9x_key) RegCloseKey(win9x_key);
2569 if(winnt_key) RegCloseKey(winnt_key);
2572 /*************************************************************
2573 * WineEngAddFontResourceEx
2576 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2578 INT ret = 0;
2580 GDI_CheckNotLock();
2582 if (ft_handle) /* do it only if we have freetype up and running */
2584 char *unixname;
2586 if(flags)
2587 FIXME("Ignoring flags %x\n", flags);
2589 if((unixname = wine_get_unix_file_name(file)))
2591 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2593 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2594 EnterCriticalSection( &freetype_cs );
2595 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2596 LeaveCriticalSection( &freetype_cs );
2597 HeapFree(GetProcessHeap(), 0, unixname);
2599 if (!ret && !strchrW(file, '\\')) {
2600 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2601 ret = load_font_from_winfonts_dir(file);
2602 if (!ret) {
2603 /* Try in datadir/fonts (or builddir/fonts),
2604 * needed for Magic the Gathering Online
2606 ret = load_font_from_data_dir(file);
2610 return ret;
2613 /*************************************************************
2614 * WineEngAddFontMemResourceEx
2617 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2619 GDI_CheckNotLock();
2621 if (ft_handle) /* do it only if we have freetype up and running */
2623 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2625 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2626 memcpy(pFontCopy, pbFont, cbFont);
2628 EnterCriticalSection( &freetype_cs );
2629 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2630 LeaveCriticalSection( &freetype_cs );
2632 if (*pcFonts == 0)
2634 TRACE("AddFontToList failed\n");
2635 HeapFree(GetProcessHeap(), 0, pFontCopy);
2636 return 0;
2638 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2639 * For now return something unique but quite random
2641 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2642 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2645 *pcFonts = 0;
2646 return 0;
2649 /*************************************************************
2650 * WineEngRemoveFontResourceEx
2653 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2655 GDI_CheckNotLock();
2656 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2657 return TRUE;
2660 static const struct nls_update_font_list
2662 UINT ansi_cp, oem_cp;
2663 const char *oem, *fixed, *system;
2664 const char *courier, *serif, *small, *sserif;
2665 /* these are for font substitutes */
2666 const char *shelldlg, *tmsrmn;
2667 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2668 *helv_0, *tmsrmn_0;
2669 const struct subst
2671 const char *from, *to;
2672 } arial_0, courier_new_0, times_new_roman_0;
2673 } nls_update_font_list[] =
2675 /* Latin 1 (United States) */
2676 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2677 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2678 "Tahoma","Times New Roman",
2679 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2680 { 0 }, { 0 }, { 0 }
2682 /* Latin 1 (Multilingual) */
2683 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2684 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2685 "Tahoma","Times New Roman", /* FIXME unverified */
2686 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2687 { 0 }, { 0 }, { 0 }
2689 /* Eastern Europe */
2690 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2691 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2692 "Tahoma","Times New Roman", /* FIXME unverified */
2693 "Fixedsys,238", "System,238",
2694 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2695 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2696 { "Arial CE,0", "Arial,238" },
2697 { "Courier New CE,0", "Courier New,238" },
2698 { "Times New Roman CE,0", "Times New Roman,238" }
2700 /* Cyrillic */
2701 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2702 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2703 "Tahoma","Times New Roman", /* FIXME unverified */
2704 "Fixedsys,204", "System,204",
2705 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2706 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2707 { "Arial Cyr,0", "Arial,204" },
2708 { "Courier New Cyr,0", "Courier New,204" },
2709 { "Times New Roman Cyr,0", "Times New Roman,204" }
2711 /* Greek */
2712 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2713 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2714 "Tahoma","Times New Roman", /* FIXME unverified */
2715 "Fixedsys,161", "System,161",
2716 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2717 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2718 { "Arial Greek,0", "Arial,161" },
2719 { "Courier New Greek,0", "Courier New,161" },
2720 { "Times New Roman Greek,0", "Times New Roman,161" }
2722 /* Turkish */
2723 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2724 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2725 "Tahoma","Times New Roman", /* FIXME unverified */
2726 "Fixedsys,162", "System,162",
2727 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2728 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2729 { "Arial Tur,0", "Arial,162" },
2730 { "Courier New Tur,0", "Courier New,162" },
2731 { "Times New Roman Tur,0", "Times New Roman,162" }
2733 /* Hebrew */
2734 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2735 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2736 "Tahoma","Times New Roman", /* FIXME unverified */
2737 "Fixedsys,177", "System,177",
2738 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2739 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2740 { 0 }, { 0 }, { 0 }
2742 /* Arabic */
2743 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2744 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2745 "Tahoma","Times New Roman", /* FIXME unverified */
2746 "Fixedsys,178", "System,178",
2747 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2748 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2749 { 0 }, { 0 }, { 0 }
2751 /* Baltic */
2752 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2753 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2754 "Tahoma","Times New Roman", /* FIXME unverified */
2755 "Fixedsys,186", "System,186",
2756 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2757 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2758 { "Arial Baltic,0", "Arial,186" },
2759 { "Courier New Baltic,0", "Courier New,186" },
2760 { "Times New Roman Baltic,0", "Times New Roman,186" }
2762 /* Vietnamese */
2763 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2764 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2765 "Tahoma","Times New Roman", /* FIXME unverified */
2766 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2767 { 0 }, { 0 }, { 0 }
2769 /* Thai */
2770 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2771 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2772 "Tahoma","Times New Roman", /* FIXME unverified */
2773 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2774 { 0 }, { 0 }, { 0 }
2776 /* Japanese */
2777 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2778 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2779 "MS UI Gothic","MS Serif",
2780 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2781 { 0 }, { 0 }, { 0 }
2783 /* Chinese Simplified */
2784 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2785 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2786 "SimSun", "NSimSun",
2787 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2788 { 0 }, { 0 }, { 0 }
2790 /* Korean */
2791 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2792 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2793 "Gulim", "Batang",
2794 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2795 { 0 }, { 0 }, { 0 }
2797 /* Chinese Traditional */
2798 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2799 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2800 "PMingLiU", "MingLiU",
2801 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2802 { 0 }, { 0 }, { 0 }
2806 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2808 return ( ansi_cp == 932 /* CP932 for Japanese */
2809 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2810 || ansi_cp == 949 /* CP949 for Korean */
2811 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2814 static inline HKEY create_fonts_NT_registry_key(void)
2816 HKEY hkey = 0;
2818 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2819 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2820 return hkey;
2823 static inline HKEY create_fonts_9x_registry_key(void)
2825 HKEY hkey = 0;
2827 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2828 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2829 return hkey;
2832 static inline HKEY create_config_fonts_registry_key(void)
2834 HKEY hkey = 0;
2836 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2837 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2838 return hkey;
2841 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2843 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2844 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2845 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2846 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2849 static void set_value_key(HKEY hkey, const char *name, const char *value)
2851 if (value)
2852 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2853 else if (name)
2854 RegDeleteValueA(hkey, name);
2857 static void update_font_info(void)
2859 char buf[40], cpbuf[40];
2860 DWORD len, type;
2861 HKEY hkey = 0;
2862 UINT i, ansi_cp = 0, oem_cp = 0;
2863 BOOL done = FALSE;
2865 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2866 return;
2868 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2869 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2870 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2871 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2872 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2874 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2875 if (is_dbcs_ansi_cp(ansi_cp))
2876 use_default_fallback = TRUE;
2878 len = sizeof(buf);
2879 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2881 if (!strcmp( buf, cpbuf )) /* already set correctly */
2883 RegCloseKey(hkey);
2884 return;
2886 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2888 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2890 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2891 RegCloseKey(hkey);
2893 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2895 HKEY hkey;
2897 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2898 nls_update_font_list[i].oem_cp == oem_cp)
2900 hkey = create_config_fonts_registry_key();
2901 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2902 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2903 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2904 RegCloseKey(hkey);
2906 hkey = create_fonts_NT_registry_key();
2907 add_font_list(hkey, &nls_update_font_list[i]);
2908 RegCloseKey(hkey);
2910 hkey = create_fonts_9x_registry_key();
2911 add_font_list(hkey, &nls_update_font_list[i]);
2912 RegCloseKey(hkey);
2914 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2916 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2917 strlen(nls_update_font_list[i].shelldlg)+1);
2918 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2919 strlen(nls_update_font_list[i].tmsrmn)+1);
2921 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2922 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2923 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2924 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2925 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2926 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2927 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2928 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2930 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2931 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2932 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2934 RegCloseKey(hkey);
2936 done = TRUE;
2938 else
2940 /* Delete the FontSubstitutes from other locales */
2941 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2943 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2944 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2945 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2946 RegCloseKey(hkey);
2950 if (!done)
2951 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2954 static BOOL init_freetype(void)
2956 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2957 if(!ft_handle) {
2958 WINE_MESSAGE(
2959 "Wine cannot find the FreeType font library. To enable Wine to\n"
2960 "use TrueType fonts please install a version of FreeType greater than\n"
2961 "or equal to 2.0.5.\n"
2962 "http://www.freetype.org\n");
2963 return FALSE;
2966 #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;}
2968 LOAD_FUNCPTR(FT_Done_Face)
2969 LOAD_FUNCPTR(FT_Get_Char_Index)
2970 LOAD_FUNCPTR(FT_Get_First_Char)
2971 LOAD_FUNCPTR(FT_Get_Module)
2972 LOAD_FUNCPTR(FT_Get_Next_Char)
2973 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2974 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2975 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2976 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2977 LOAD_FUNCPTR(FT_Init_FreeType)
2978 LOAD_FUNCPTR(FT_Library_Version)
2979 LOAD_FUNCPTR(FT_Load_Glyph)
2980 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2981 LOAD_FUNCPTR(FT_Matrix_Multiply)
2982 #ifndef FT_MULFIX_INLINED
2983 LOAD_FUNCPTR(FT_MulFix)
2984 #endif
2985 LOAD_FUNCPTR(FT_New_Face)
2986 LOAD_FUNCPTR(FT_New_Memory_Face)
2987 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2988 LOAD_FUNCPTR(FT_Outline_Transform)
2989 LOAD_FUNCPTR(FT_Outline_Translate)
2990 LOAD_FUNCPTR(FT_Render_Glyph)
2991 LOAD_FUNCPTR(FT_Select_Charmap)
2992 LOAD_FUNCPTR(FT_Set_Charmap)
2993 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2994 LOAD_FUNCPTR(FT_Vector_Transform)
2995 LOAD_FUNCPTR(FT_Vector_Unit)
2996 #undef LOAD_FUNCPTR
2997 /* Don't warn if these ones are missing */
2998 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2999 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3000 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3001 #endif
3003 if(pFT_Init_FreeType(&library) != 0) {
3004 ERR("Can't init FreeType library\n");
3005 wine_dlclose(ft_handle, NULL, 0);
3006 ft_handle = NULL;
3007 return FALSE;
3009 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3011 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3012 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3013 ((FT_Version.minor << 8) & 0x00ff00) |
3014 ((FT_Version.patch ) & 0x0000ff);
3016 font_driver = &freetype_funcs;
3017 return TRUE;
3019 sym_not_found:
3020 WINE_MESSAGE(
3021 "Wine cannot find certain functions that it needs inside the FreeType\n"
3022 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3023 "FreeType to at least version 2.1.4.\n"
3024 "http://www.freetype.org\n");
3025 wine_dlclose(ft_handle, NULL, 0);
3026 ft_handle = NULL;
3027 return FALSE;
3030 static void init_font_list(void)
3032 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3033 static const WCHAR pathW[] = {'P','a','t','h',0};
3034 HKEY hkey;
3035 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3036 WCHAR windowsdir[MAX_PATH];
3037 char *unixname;
3038 const char *home;
3039 const char *data_dir;
3041 delete_external_font_keys();
3043 /* load the system bitmap fonts */
3044 load_system_fonts();
3046 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3047 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3048 strcatW(windowsdir, fontsW);
3049 if((unixname = wine_get_unix_file_name(windowsdir)))
3051 ReadFontDir(unixname, FALSE);
3052 HeapFree(GetProcessHeap(), 0, unixname);
3055 /* load the system truetype fonts */
3056 data_dir = wine_get_data_dir();
3057 if (!data_dir) data_dir = wine_get_build_dir();
3058 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3060 strcpy(unixname, data_dir);
3061 strcat(unixname, "/fonts/");
3062 ReadFontDir(unixname, TRUE);
3063 HeapFree(GetProcessHeap(), 0, unixname);
3066 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3067 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3068 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3069 will skip these. */
3070 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3071 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3072 &hkey) == ERROR_SUCCESS)
3074 LPWSTR data, valueW;
3075 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3076 &valuelen, &datalen, NULL, NULL);
3078 valuelen++; /* returned value doesn't include room for '\0' */
3079 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3080 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3081 if (valueW && data)
3083 dlen = datalen * sizeof(WCHAR);
3084 vlen = valuelen;
3085 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3086 &dlen) == ERROR_SUCCESS)
3088 if(data[0] && (data[1] == ':'))
3090 if((unixname = wine_get_unix_file_name(data)))
3092 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3093 HeapFree(GetProcessHeap(), 0, unixname);
3096 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3098 WCHAR pathW[MAX_PATH];
3099 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3100 BOOL added = FALSE;
3102 sprintfW(pathW, fmtW, windowsdir, data);
3103 if((unixname = wine_get_unix_file_name(pathW)))
3105 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3106 HeapFree(GetProcessHeap(), 0, unixname);
3108 if (!added)
3109 load_font_from_data_dir(data);
3111 /* reset dlen and vlen */
3112 dlen = datalen;
3113 vlen = valuelen;
3116 HeapFree(GetProcessHeap(), 0, data);
3117 HeapFree(GetProcessHeap(), 0, valueW);
3118 RegCloseKey(hkey);
3121 load_fontconfig_fonts();
3123 /* then look in any directories that we've specified in the config file */
3124 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3125 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3127 DWORD len;
3128 LPWSTR valueW;
3129 LPSTR valueA, ptr;
3131 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3133 len += sizeof(WCHAR);
3134 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3135 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3137 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3138 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3139 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3140 TRACE( "got font path %s\n", debugstr_a(valueA) );
3141 ptr = valueA;
3142 while (ptr)
3144 LPSTR next = strchr( ptr, ':' );
3145 if (next) *next++ = 0;
3146 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3147 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3149 strcpy( unixname, home );
3150 strcat( unixname, ptr + 1 );
3151 ReadFontDir( unixname, TRUE );
3152 HeapFree( GetProcessHeap(), 0, unixname );
3154 else
3155 ReadFontDir( ptr, TRUE );
3156 ptr = next;
3158 HeapFree( GetProcessHeap(), 0, valueA );
3160 HeapFree( GetProcessHeap(), 0, valueW );
3162 RegCloseKey(hkey);
3165 #ifdef __APPLE__
3166 /* Mac default font locations. */
3167 ReadFontDir( "/Library/Fonts", TRUE );
3168 ReadFontDir( "/Network/Library/Fonts", TRUE );
3169 ReadFontDir( "/System/Library/Fonts", TRUE );
3170 if ((home = getenv( "HOME" )))
3172 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3173 strcpy( unixname, home );
3174 strcat( unixname, "/Library/Fonts" );
3175 ReadFontDir( unixname, TRUE);
3176 HeapFree( GetProcessHeap(), 0, unixname );
3178 #endif
3181 static BOOL move_to_front(const WCHAR *name)
3183 Family *family, *cursor2;
3184 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3186 if(!strcmpiW(family->FamilyName, name))
3188 list_remove(&family->entry);
3189 list_add_head(&font_list, &family->entry);
3190 return TRUE;
3193 return FALSE;
3196 static BOOL set_default(const WCHAR **name_list)
3198 while (*name_list)
3200 if (move_to_front(*name_list)) return TRUE;
3201 name_list++;
3204 return FALSE;
3207 static void reorder_font_list(void)
3209 set_default( default_serif_list );
3210 set_default( default_fixed_list );
3211 set_default( default_sans_list );
3214 /*************************************************************
3215 * WineEngInit
3217 * Initialize FreeType library and create a list of available faces
3219 BOOL WineEngInit(void)
3221 HKEY hkey_font_cache;
3222 DWORD disposition;
3223 HANDLE font_mutex;
3225 /* update locale dependent font info in registry */
3226 update_font_info();
3228 if(!init_freetype()) return FALSE;
3230 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3232 ERR("Failed to create font mutex\n");
3233 return FALSE;
3235 WaitForSingleObject(font_mutex, INFINITE);
3237 create_font_cache_key(&hkey_font_cache, &disposition);
3239 if(disposition == REG_CREATED_NEW_KEY)
3240 init_font_list();
3241 else
3242 load_font_list_from_cache(hkey_font_cache);
3244 RegCloseKey(hkey_font_cache);
3246 reorder_font_list();
3248 DumpFontList();
3249 LoadSubstList();
3250 DumpSubstList();
3251 LoadReplaceList();
3253 if(disposition == REG_CREATED_NEW_KEY)
3254 update_reg_entries();
3256 init_system_links();
3258 ReleaseMutex(font_mutex);
3259 return TRUE;
3263 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3265 TT_OS2 *pOS2;
3266 TT_HoriHeader *pHori;
3268 LONG ppem;
3270 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3271 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3273 if(height == 0) height = 16;
3275 /* Calc. height of EM square:
3277 * For +ve lfHeight we have
3278 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3279 * Re-arranging gives:
3280 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3282 * For -ve lfHeight we have
3283 * |lfHeight| = ppem
3284 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3285 * with il = winAscent + winDescent - units_per_em]
3289 if(height > 0) {
3290 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3291 ppem = MulDiv(ft_face->units_per_EM, height,
3292 pHori->Ascender - pHori->Descender);
3293 else
3294 ppem = MulDiv(ft_face->units_per_EM, height,
3295 pOS2->usWinAscent + pOS2->usWinDescent);
3297 else
3298 ppem = -height;
3300 return ppem;
3303 static struct font_mapping *map_font_file( const char *name )
3305 struct font_mapping *mapping;
3306 struct stat st;
3307 int fd;
3309 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3310 if (fstat( fd, &st ) == -1) goto error;
3312 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3314 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3316 mapping->refcount++;
3317 close( fd );
3318 return mapping;
3321 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3322 goto error;
3324 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3325 close( fd );
3327 if (mapping->data == MAP_FAILED)
3329 HeapFree( GetProcessHeap(), 0, mapping );
3330 return NULL;
3332 mapping->refcount = 1;
3333 mapping->dev = st.st_dev;
3334 mapping->ino = st.st_ino;
3335 mapping->size = st.st_size;
3336 list_add_tail( &mappings_list, &mapping->entry );
3337 return mapping;
3339 error:
3340 close( fd );
3341 return NULL;
3344 static void unmap_font_file( struct font_mapping *mapping )
3346 if (!--mapping->refcount)
3348 list_remove( &mapping->entry );
3349 munmap( mapping->data, mapping->size );
3350 HeapFree( GetProcessHeap(), 0, mapping );
3354 static LONG load_VDMX(GdiFont*, LONG);
3356 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3358 FT_Error err;
3359 FT_Face ft_face;
3360 void *data_ptr;
3361 DWORD data_size;
3363 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3365 if (face->file)
3367 if (!(font->mapping = map_font_file( face->file )))
3369 WARN("failed to map %s\n", debugstr_a(face->file));
3370 return 0;
3372 data_ptr = font->mapping->data;
3373 data_size = font->mapping->size;
3375 else
3377 data_ptr = face->font_data_ptr;
3378 data_size = face->font_data_size;
3381 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3382 if(err) {
3383 ERR("FT_New_Face rets %d\n", err);
3384 return 0;
3387 /* set it here, as load_VDMX needs it */
3388 font->ft_face = ft_face;
3390 if(FT_IS_SCALABLE(ft_face)) {
3391 /* load the VDMX table if we have one */
3392 font->ppem = load_VDMX(font, height);
3393 if(font->ppem == 0)
3394 font->ppem = calc_ppem_for_height(ft_face, height);
3395 TRACE("height %d => ppem %d\n", height, font->ppem);
3397 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3398 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3399 } else {
3400 font->ppem = height;
3401 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3402 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3404 return ft_face;
3408 static int get_nearest_charset(Face *face, int *cp)
3410 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3411 a single face with the requested charset. The idea is to check if
3412 the selected font supports the current ANSI codepage, if it does
3413 return the corresponding charset, else return the first charset */
3415 CHARSETINFO csi;
3416 int acp = GetACP(), i;
3417 DWORD fs0;
3419 *cp = acp;
3420 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3421 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3422 return csi.ciCharset;
3424 for(i = 0; i < 32; i++) {
3425 fs0 = 1L << i;
3426 if(face->fs.fsCsb[0] & fs0) {
3427 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3428 *cp = csi.ciACP;
3429 return csi.ciCharset;
3431 else
3432 FIXME("TCI failing on %x\n", fs0);
3436 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3437 face->fs.fsCsb[0], face->file);
3438 *cp = acp;
3439 return DEFAULT_CHARSET;
3442 static GdiFont *alloc_font(void)
3444 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3445 ret->gmsize = 1;
3446 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3447 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3448 ret->potm = NULL;
3449 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3450 ret->total_kern_pairs = (DWORD)-1;
3451 ret->kern_pairs = NULL;
3452 list_init(&ret->hfontlist);
3453 list_init(&ret->child_fonts);
3454 return ret;
3457 static void free_font(GdiFont *font)
3459 struct list *cursor, *cursor2;
3460 DWORD i;
3462 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3464 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3465 list_remove(cursor);
3466 if(child->font)
3467 free_font(child->font);
3468 HeapFree(GetProcessHeap(), 0, child);
3471 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3473 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3474 DeleteObject(hfontlist->hfont);
3475 list_remove(&hfontlist->entry);
3476 HeapFree(GetProcessHeap(), 0, hfontlist);
3479 if (font->ft_face) pFT_Done_Face(font->ft_face);
3480 if (font->mapping) unmap_font_file( font->mapping );
3481 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3482 HeapFree(GetProcessHeap(), 0, font->potm);
3483 HeapFree(GetProcessHeap(), 0, font->name);
3484 for (i = 0; i < font->gmsize; i++)
3485 HeapFree(GetProcessHeap(),0,font->gm[i]);
3486 HeapFree(GetProcessHeap(), 0, font->gm);
3487 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3488 HeapFree(GetProcessHeap(), 0, font);
3492 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3494 FT_Face ft_face = font->ft_face;
3495 FT_ULong len;
3496 FT_Error err;
3498 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3500 if(!buf)
3501 len = 0;
3502 else
3503 len = cbData;
3505 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3507 /* make sure value of len is the value freetype says it needs */
3508 if (buf && len)
3510 FT_ULong needed = 0;
3511 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3512 if( !err && needed < len) len = needed;
3514 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3515 if (err)
3517 TRACE("Can't find table %c%c%c%c\n",
3518 /* bytes were reversed */
3519 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3520 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3521 return GDI_ERROR;
3523 return len;
3526 /*************************************************************
3527 * load_VDMX
3529 * load the vdmx entry for the specified height
3532 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3533 ( ( (FT_ULong)_x4 << 24 ) | \
3534 ( (FT_ULong)_x3 << 16 ) | \
3535 ( (FT_ULong)_x2 << 8 ) | \
3536 (FT_ULong)_x1 )
3538 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3540 typedef struct {
3541 BYTE bCharSet;
3542 BYTE xRatio;
3543 BYTE yStartRatio;
3544 BYTE yEndRatio;
3545 } Ratios;
3547 typedef struct {
3548 WORD recs;
3549 BYTE startsz;
3550 BYTE endsz;
3551 } VDMX_group;
3553 static LONG load_VDMX(GdiFont *font, LONG height)
3555 WORD hdr[3], tmp;
3556 VDMX_group group;
3557 BYTE devXRatio, devYRatio;
3558 USHORT numRecs, numRatios;
3559 DWORD result, offset = -1;
3560 LONG ppem = 0;
3561 int i;
3563 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3565 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3566 return ppem;
3568 /* FIXME: need the real device aspect ratio */
3569 devXRatio = 1;
3570 devYRatio = 1;
3572 numRecs = GET_BE_WORD(hdr[1]);
3573 numRatios = GET_BE_WORD(hdr[2]);
3575 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3576 for(i = 0; i < numRatios; i++) {
3577 Ratios ratio;
3579 offset = (3 * 2) + (i * sizeof(Ratios));
3580 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3581 offset = -1;
3583 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3585 if((ratio.xRatio == 0 &&
3586 ratio.yStartRatio == 0 &&
3587 ratio.yEndRatio == 0) ||
3588 (devXRatio == ratio.xRatio &&
3589 devYRatio >= ratio.yStartRatio &&
3590 devYRatio <= ratio.yEndRatio))
3592 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3593 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3594 offset = GET_BE_WORD(tmp);
3595 break;
3599 if(offset == -1) {
3600 FIXME("No suitable ratio found\n");
3601 return ppem;
3604 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3605 USHORT recs;
3606 BYTE startsz, endsz;
3607 WORD *vTable;
3609 recs = GET_BE_WORD(group.recs);
3610 startsz = group.startsz;
3611 endsz = group.endsz;
3613 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3615 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3616 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3617 if(result == GDI_ERROR) {
3618 FIXME("Failed to retrieve vTable\n");
3619 goto end;
3622 if(height > 0) {
3623 for(i = 0; i < recs; i++) {
3624 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3625 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3626 ppem = GET_BE_WORD(vTable[i * 3]);
3628 if(yMax + -yMin == height) {
3629 font->yMax = yMax;
3630 font->yMin = yMin;
3631 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3632 break;
3634 if(yMax + -yMin > height) {
3635 if(--i < 0) {
3636 ppem = 0;
3637 goto end; /* failed */
3639 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3640 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3641 ppem = GET_BE_WORD(vTable[i * 3]);
3642 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3643 break;
3646 if(!font->yMax) {
3647 ppem = 0;
3648 TRACE("ppem not found for height %d\n", height);
3651 end:
3652 HeapFree(GetProcessHeap(), 0, vTable);
3655 return ppem;
3658 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3660 if(font->font_desc.hash != fd->hash) return TRUE;
3661 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3662 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3663 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3664 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3667 static void calc_hash(FONT_DESC *pfd)
3669 DWORD hash = 0, *ptr, two_chars;
3670 WORD *pwc;
3671 unsigned int i;
3673 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3674 hash ^= *ptr;
3675 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3676 hash ^= *ptr;
3677 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3678 two_chars = *ptr;
3679 pwc = (WCHAR *)&two_chars;
3680 if(!*pwc) break;
3681 *pwc = toupperW(*pwc);
3682 pwc++;
3683 *pwc = toupperW(*pwc);
3684 hash ^= two_chars;
3685 if(!*pwc) break;
3687 hash ^= !pfd->can_use_bitmap;
3688 pfd->hash = hash;
3689 return;
3692 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3694 GdiFont *ret;
3695 FONT_DESC fd;
3696 HFONTLIST *hflist;
3697 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3699 fd.lf = *plf;
3700 fd.matrix = *pmat;
3701 fd.can_use_bitmap = can_use_bitmap;
3702 calc_hash(&fd);
3704 /* try the child list */
3705 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3706 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3707 if(!fontcmp(ret, &fd)) {
3708 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3709 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3710 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3711 if(hflist->hfont == hfont)
3712 return ret;
3717 /* try the in-use list */
3718 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3719 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3720 if(!fontcmp(ret, &fd)) {
3721 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3722 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3723 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3724 if(hflist->hfont == hfont)
3725 return ret;
3727 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3728 hflist->hfont = hfont;
3729 list_add_head(&ret->hfontlist, &hflist->entry);
3730 return ret;
3734 /* then the unused list */
3735 font_elem_ptr = list_head(&unused_gdi_font_list);
3736 while(font_elem_ptr) {
3737 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3738 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3739 if(!fontcmp(ret, &fd)) {
3740 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3741 assert(list_empty(&ret->hfontlist));
3742 TRACE("Found %p in unused list\n", ret);
3743 list_remove(&ret->entry);
3744 list_add_head(&gdi_font_list, &ret->entry);
3745 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3746 hflist->hfont = hfont;
3747 list_add_head(&ret->hfontlist, &hflist->entry);
3748 return ret;
3751 return NULL;
3754 static void add_to_cache(GdiFont *font)
3756 static DWORD cache_num = 1;
3758 font->cache_num = cache_num++;
3759 list_add_head(&gdi_font_list, &font->entry);
3762 /*************************************************************
3763 * create_child_font_list
3765 static BOOL create_child_font_list(GdiFont *font)
3767 BOOL ret = FALSE;
3768 SYSTEM_LINKS *font_link;
3769 CHILD_FONT *font_link_entry, *new_child;
3770 FontSubst *psub;
3771 WCHAR* font_name;
3773 psub = get_font_subst(&font_subst_list, font->name, -1);
3774 font_name = psub ? psub->to.name : font->name;
3775 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3777 if(!strcmpiW(font_link->font_name, font_name))
3779 TRACE("found entry in system list\n");
3780 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3782 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3783 new_child->face = font_link_entry->face;
3784 new_child->font = NULL;
3785 list_add_tail(&font->child_fonts, &new_child->entry);
3786 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3788 ret = TRUE;
3789 break;
3793 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3794 * Sans Serif. This is how asian windows get default fallbacks for fonts
3796 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3797 font->charset != OEM_CHARSET &&
3798 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3799 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3801 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3803 TRACE("found entry in default fallback list\n");
3804 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3806 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3807 new_child->face = font_link_entry->face;
3808 new_child->font = NULL;
3809 list_add_tail(&font->child_fonts, &new_child->entry);
3810 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3812 ret = TRUE;
3813 break;
3817 return ret;
3820 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3822 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3824 if (pFT_Set_Charmap)
3826 FT_Int i;
3827 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3829 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3831 for (i = 0; i < ft_face->num_charmaps; i++)
3833 if (ft_face->charmaps[i]->encoding == encoding)
3835 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3836 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3838 switch (ft_face->charmaps[i]->platform_id)
3840 default:
3841 cmap_def = ft_face->charmaps[i];
3842 break;
3843 case 0: /* Apple Unicode */
3844 cmap0 = ft_face->charmaps[i];
3845 break;
3846 case 1: /* Macintosh */
3847 cmap1 = ft_face->charmaps[i];
3848 break;
3849 case 2: /* ISO */
3850 cmap2 = ft_face->charmaps[i];
3851 break;
3852 case 3: /* Microsoft */
3853 cmap3 = ft_face->charmaps[i];
3854 break;
3858 if (cmap3) /* prefer Microsoft cmap table */
3859 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3860 else if (cmap1)
3861 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3862 else if (cmap2)
3863 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3864 else if (cmap0)
3865 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3866 else if (cmap_def)
3867 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3869 return ft_err == FT_Err_Ok;
3872 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3876 /*************************************************************
3877 * freetype_CreateDC
3879 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3880 LPCWSTR output, const DEVMODEW *devmode )
3882 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3884 if (!physdev) return FALSE;
3885 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3886 return TRUE;
3890 /*************************************************************
3891 * freetype_DeleteDC
3893 static BOOL freetype_DeleteDC( PHYSDEV dev )
3895 struct freetype_physdev *physdev = get_freetype_dev( dev );
3896 HeapFree( GetProcessHeap(), 0, physdev );
3897 return TRUE;
3901 /*************************************************************
3902 * freetype_SelectFont
3904 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3906 struct freetype_physdev *physdev = get_freetype_dev( dev );
3907 GdiFont *ret;
3908 Face *face, *best, *best_bitmap;
3909 Family *family, *last_resort_family;
3910 struct list *family_elem_ptr, *face_elem_ptr;
3911 INT height, width = 0;
3912 unsigned int score = 0, new_score;
3913 signed int diff = 0, newdiff;
3914 BOOL bd, it, can_use_bitmap, want_vertical;
3915 LOGFONTW lf;
3916 CHARSETINFO csi;
3917 HFONTLIST *hflist;
3918 FMAT2 dcmat;
3919 FontSubst *psub = NULL;
3920 DC *dc = get_dc_ptr( dev->hdc );
3922 if (!hfont) /* notification that the font has been changed by another driver */
3924 dc->gdiFont = NULL;
3925 physdev->font = NULL;
3926 release_dc_ptr( dc );
3927 return 0;
3930 GetObjectW( hfont, sizeof(lf), &lf );
3931 lf.lfWidth = abs(lf.lfWidth);
3933 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3935 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3936 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3937 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3938 lf.lfEscapement);
3940 if(dc->GraphicsMode == GM_ADVANCED)
3941 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3942 else
3944 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3945 font scaling abilities. */
3946 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3947 dcmat.eM21 = dcmat.eM12 = 0;
3950 /* Try to avoid not necessary glyph transformations */
3951 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3953 lf.lfHeight *= fabs(dcmat.eM11);
3954 lf.lfWidth *= fabs(dcmat.eM11);
3955 dcmat.eM11 = dcmat.eM22 = 1.0;
3958 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3959 dcmat.eM21, dcmat.eM22);
3961 GDI_CheckNotLock();
3962 EnterCriticalSection( &freetype_cs );
3964 /* check the cache first */
3965 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3966 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3967 goto done;
3970 if(list_empty(&font_list)) /* No fonts installed */
3972 TRACE("No fonts installed\n");
3973 goto done;
3976 TRACE("not in cache\n");
3977 ret = alloc_font();
3979 ret->font_desc.matrix = dcmat;
3980 ret->font_desc.lf = lf;
3981 ret->font_desc.can_use_bitmap = can_use_bitmap;
3982 calc_hash(&ret->font_desc);
3983 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3984 hflist->hfont = hfont;
3985 list_add_head(&ret->hfontlist, &hflist->entry);
3987 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3988 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3989 original value lfCharSet. Note this is a special case for
3990 Symbol and doesn't happen at least for "Wingdings*" */
3992 if(!strcmpiW(lf.lfFaceName, SymbolW))
3993 lf.lfCharSet = SYMBOL_CHARSET;
3995 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3996 switch(lf.lfCharSet) {
3997 case DEFAULT_CHARSET:
3998 csi.fs.fsCsb[0] = 0;
3999 break;
4000 default:
4001 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4002 csi.fs.fsCsb[0] = 0;
4003 break;
4007 family = NULL;
4008 if(lf.lfFaceName[0] != '\0') {
4009 SYSTEM_LINKS *font_link;
4010 CHILD_FONT *font_link_entry;
4011 LPWSTR FaceName = lf.lfFaceName;
4013 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4015 if(psub) {
4016 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4017 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4018 if (psub->to.charset != -1)
4019 lf.lfCharSet = psub->to.charset;
4022 /* We want a match on name and charset or just name if
4023 charset was DEFAULT_CHARSET. If the latter then
4024 we fixup the returned charset later in get_nearest_charset
4025 where we'll either use the charset of the current ansi codepage
4026 or if that's unavailable the first charset that the font supports.
4028 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4029 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4030 if (!strcmpiW(family->FamilyName, FaceName) ||
4031 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4033 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4034 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4035 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4036 if(face->scalable || can_use_bitmap)
4037 goto found;
4042 /* Search by full face name. */
4043 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4044 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4045 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4046 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4047 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4048 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
4050 if(face->scalable || can_use_bitmap)
4051 goto found_face;
4057 * Try check the SystemLink list first for a replacement font.
4058 * We may find good replacements there.
4060 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4062 if(!strcmpiW(font_link->font_name, FaceName) ||
4063 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4065 TRACE("found entry in system list\n");
4066 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4068 face = font_link_entry->face;
4069 family = face->family;
4070 if(csi.fs.fsCsb[0] &
4071 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4073 if(face->scalable || can_use_bitmap)
4074 goto found;
4081 psub = NULL; /* substitution is no more relevant */
4083 /* If requested charset was DEFAULT_CHARSET then try using charset
4084 corresponding to the current ansi codepage */
4085 if (!csi.fs.fsCsb[0])
4087 INT acp = GetACP();
4088 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4089 FIXME("TCI failed on codepage %d\n", acp);
4090 csi.fs.fsCsb[0] = 0;
4091 } else
4092 lf.lfCharSet = csi.ciCharset;
4095 want_vertical = (lf.lfFaceName[0] == '@');
4097 /* Face families are in the top 4 bits of lfPitchAndFamily,
4098 so mask with 0xF0 before testing */
4100 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4101 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4102 strcpyW(lf.lfFaceName, defFixed);
4103 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4104 strcpyW(lf.lfFaceName, defSerif);
4105 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4106 strcpyW(lf.lfFaceName, defSans);
4107 else
4108 strcpyW(lf.lfFaceName, defSans);
4109 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4110 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4111 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4112 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4113 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4114 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4115 if(face->scalable || can_use_bitmap)
4116 goto found;
4121 last_resort_family = NULL;
4122 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4123 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4124 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4125 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4126 if(face->vertical == want_vertical &&
4127 (csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))) {
4128 if(face->scalable)
4129 goto found;
4130 if(can_use_bitmap && !last_resort_family)
4131 last_resort_family = family;
4136 if(last_resort_family) {
4137 family = last_resort_family;
4138 csi.fs.fsCsb[0] = 0;
4139 goto found;
4142 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4143 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4144 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4145 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4146 if(face->scalable && face->vertical == want_vertical) {
4147 csi.fs.fsCsb[0] = 0;
4148 WARN("just using first face for now\n");
4149 goto found;
4151 if(can_use_bitmap && !last_resort_family)
4152 last_resort_family = family;
4155 if(!last_resort_family) {
4156 FIXME("can't find a single appropriate font - bailing\n");
4157 free_font(ret);
4158 ret = NULL;
4159 goto done;
4162 WARN("could only find a bitmap font - this will probably look awful!\n");
4163 family = last_resort_family;
4164 csi.fs.fsCsb[0] = 0;
4166 found:
4167 it = lf.lfItalic ? 1 : 0;
4168 bd = lf.lfWeight > 550 ? 1 : 0;
4170 height = lf.lfHeight;
4172 face = best = best_bitmap = NULL;
4173 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4175 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4177 BOOL italic, bold;
4179 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4180 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4181 new_score = (italic ^ it) + (bold ^ bd);
4182 if(!best || new_score <= score)
4184 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4185 italic, bold, it, bd);
4186 score = new_score;
4187 best = face;
4188 if(best->scalable && score == 0) break;
4189 if(!best->scalable)
4191 if(height > 0)
4192 newdiff = height - (signed int)(best->size.height);
4193 else
4194 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4195 if(!best_bitmap || new_score < score ||
4196 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4198 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4199 diff = newdiff;
4200 best_bitmap = best;
4201 if(score == 0 && diff == 0) break;
4207 if(best)
4208 face = best->scalable ? best : best_bitmap;
4209 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4210 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4212 found_face:
4213 height = lf.lfHeight;
4215 ret->fs = face->fs;
4217 if(csi.fs.fsCsb[0]) {
4218 ret->charset = lf.lfCharSet;
4219 ret->codepage = csi.ciACP;
4221 else
4222 ret->charset = get_nearest_charset(face, &ret->codepage);
4224 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4225 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4227 ret->aveWidth = height ? lf.lfWidth : 0;
4229 if(!face->scalable) {
4230 /* Windows uses integer scaling factors for bitmap fonts */
4231 INT scale, scaled_height;
4232 GdiFont *cachedfont;
4234 /* FIXME: rotation of bitmap fonts is ignored */
4235 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4236 if (ret->aveWidth)
4237 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4238 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4239 dcmat.eM11 = dcmat.eM22 = 1.0;
4240 /* As we changed the matrix, we need to search the cache for the font again,
4241 * otherwise we might explode the cache. */
4242 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4243 TRACE("Found cached font after non-scalable matrix rescale!\n");
4244 free_font( ret );
4245 ret = cachedfont;
4246 goto done;
4248 calc_hash(&ret->font_desc);
4250 if (height != 0) height = diff;
4251 height += face->size.height;
4253 scale = (height + face->size.height - 1) / face->size.height;
4254 scaled_height = scale * face->size.height;
4255 /* Only jump to the next height if the difference <= 25% original height */
4256 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4257 /* The jump between unscaled and doubled is delayed by 1 */
4258 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4259 ret->scale_y = scale;
4261 width = face->size.x_ppem >> 6;
4262 height = face->size.y_ppem >> 6;
4264 else
4265 ret->scale_y = 1.0;
4266 TRACE("font scale y: %f\n", ret->scale_y);
4268 ret->ft_face = OpenFontFace(ret, face, width, height);
4270 if (!ret->ft_face)
4272 free_font( ret );
4273 ret = NULL;
4274 goto done;
4277 ret->ntmFlags = face->ntmFlags;
4279 if (ret->charset == SYMBOL_CHARSET &&
4280 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4281 /* No ops */
4283 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4284 /* No ops */
4286 else {
4287 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4290 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4291 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4292 ret->underline = lf.lfUnderline ? 0xff : 0;
4293 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4294 create_child_font_list(ret);
4296 if (face->vertical) /* We need to try to load the GSUB table */
4298 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4299 if (length != GDI_ERROR)
4301 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4302 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4303 TRACE("Loaded GSUB table of %i bytes\n",length);
4307 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4309 add_to_cache(ret);
4310 done:
4311 if (ret)
4313 dc->gdiFont = ret;
4314 physdev->font = ret;
4316 LeaveCriticalSection( &freetype_cs );
4317 release_dc_ptr( dc );
4318 return ret ? hfont : 0;
4321 static void dump_gdi_font_list(void)
4323 GdiFont *gdiFont;
4324 struct list *elem_ptr;
4326 TRACE("---------- gdiFont Cache ----------\n");
4327 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4328 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4329 TRACE("gdiFont=%p %s %d\n",
4330 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4333 TRACE("---------- Unused gdiFont Cache ----------\n");
4334 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4335 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4336 TRACE("gdiFont=%p %s %d\n",
4337 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4340 TRACE("---------- Child gdiFont Cache ----------\n");
4341 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4342 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4343 TRACE("gdiFont=%p %s %d\n",
4344 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4348 /*************************************************************
4349 * WineEngDestroyFontInstance
4351 * free the gdiFont associated with this handle
4354 BOOL WineEngDestroyFontInstance(HFONT handle)
4356 GdiFont *gdiFont;
4357 HFONTLIST *hflist;
4358 BOOL ret = FALSE;
4359 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4360 int i = 0;
4362 GDI_CheckNotLock();
4363 EnterCriticalSection( &freetype_cs );
4365 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4367 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4368 while(hfontlist_elem_ptr) {
4369 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4370 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4371 if(hflist->hfont == handle) {
4372 TRACE("removing child font %p from child list\n", gdiFont);
4373 list_remove(&gdiFont->entry);
4374 LeaveCriticalSection( &freetype_cs );
4375 return TRUE;
4380 TRACE("destroying hfont=%p\n", handle);
4381 if(TRACE_ON(font))
4382 dump_gdi_font_list();
4384 font_elem_ptr = list_head(&gdi_font_list);
4385 while(font_elem_ptr) {
4386 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4387 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4389 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4390 while(hfontlist_elem_ptr) {
4391 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4392 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4393 if(hflist->hfont == handle) {
4394 list_remove(&hflist->entry);
4395 HeapFree(GetProcessHeap(), 0, hflist);
4396 ret = TRUE;
4399 if(list_empty(&gdiFont->hfontlist)) {
4400 TRACE("Moving to Unused list\n");
4401 list_remove(&gdiFont->entry);
4402 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4407 font_elem_ptr = list_head(&unused_gdi_font_list);
4408 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4409 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4410 while(font_elem_ptr) {
4411 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4412 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4413 TRACE("freeing %p\n", gdiFont);
4414 list_remove(&gdiFont->entry);
4415 free_font(gdiFont);
4417 LeaveCriticalSection( &freetype_cs );
4418 return ret;
4421 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4423 HRSRC rsrc;
4424 HGLOBAL hMem;
4425 WCHAR *p;
4426 int i;
4428 id += IDS_FIRST_SCRIPT;
4429 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4430 if (!rsrc) return 0;
4431 hMem = LoadResource( gdi32_module, rsrc );
4432 if (!hMem) return 0;
4434 p = LockResource( hMem );
4435 id &= 0x000f;
4436 while (id--) p += *p + 1;
4438 i = min(LF_FACESIZE - 1, *p);
4439 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4440 buffer[i] = 0;
4441 return i;
4445 /***************************************************
4446 * create_enum_charset_list
4448 * This function creates charset enumeration list because in DEFAULT_CHARSET
4449 * case, the ANSI codepage's charset takes precedence over other charsets.
4450 * This function works as a filter other than DEFAULT_CHARSET case.
4452 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4454 CHARSETINFO csi;
4455 DWORD n = 0;
4457 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4458 csi.fs.fsCsb[0] != 0) {
4459 list->element[n].mask = csi.fs.fsCsb[0];
4460 list->element[n].charset = csi.ciCharset;
4461 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4462 n++;
4464 else { /* charset is DEFAULT_CHARSET or invalid. */
4465 INT acp, i;
4467 /* Set the current codepage's charset as the first element. */
4468 acp = GetACP();
4469 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4470 csi.fs.fsCsb[0] != 0) {
4471 list->element[n].mask = csi.fs.fsCsb[0];
4472 list->element[n].charset = csi.ciCharset;
4473 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4474 n++;
4477 /* Fill out left elements. */
4478 for (i = 0; i < 32; i++) {
4479 FONTSIGNATURE fs;
4480 fs.fsCsb[0] = 1L << i;
4481 fs.fsCsb[1] = 0;
4482 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4483 continue; /* skip, already added. */
4484 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4485 continue; /* skip, this is an invalid fsCsb bit. */
4487 list->element[n].mask = fs.fsCsb[0];
4488 list->element[n].charset = csi.ciCharset;
4489 load_script_name( i, list->element[n].name );
4490 n++;
4493 list->total = n;
4495 return n;
4498 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4499 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4501 GdiFont *font;
4502 LONG width, height;
4504 if (face->cached_enum_data)
4506 TRACE("Cached\n");
4507 *pelf = face->cached_enum_data->elf;
4508 *pntm = face->cached_enum_data->ntm;
4509 *ptype = face->cached_enum_data->type;
4510 return;
4513 font = alloc_font();
4515 if(face->scalable) {
4516 height = -2048; /* 2048 is the most common em size */
4517 width = 0;
4518 } else {
4519 height = face->size.y_ppem >> 6;
4520 width = face->size.x_ppem >> 6;
4522 font->scale_y = 1.0;
4524 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4526 free_font(font);
4527 return;
4530 font->name = strdupW(face->family->FamilyName);
4531 font->ntmFlags = face->ntmFlags;
4533 if (get_outline_text_metrics(font))
4535 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4537 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4539 lstrcpynW(pelf->elfLogFont.lfFaceName,
4540 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4541 LF_FACESIZE);
4542 lstrcpynW(pelf->elfFullName,
4543 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4544 LF_FULLFACESIZE);
4545 lstrcpynW(pelf->elfStyle,
4546 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4547 LF_FACESIZE);
4549 else
4551 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4553 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4555 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4556 if (face->FullName)
4557 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4558 else
4559 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4560 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4563 pntm->ntmTm.ntmFlags = face->ntmFlags;
4564 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4565 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4566 pntm->ntmFontSig = face->fs;
4568 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4570 pelf->elfLogFont.lfEscapement = 0;
4571 pelf->elfLogFont.lfOrientation = 0;
4572 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4573 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4574 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4575 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4576 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4577 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4578 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4579 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4580 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4581 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4582 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4584 *ptype = 0;
4585 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4586 *ptype |= TRUETYPE_FONTTYPE;
4587 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4588 *ptype |= DEVICE_FONTTYPE;
4589 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4590 *ptype |= RASTER_FONTTYPE;
4592 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4593 if (face->cached_enum_data)
4595 face->cached_enum_data->elf = *pelf;
4596 face->cached_enum_data->ntm = *pntm;
4597 face->cached_enum_data->type = *ptype;
4600 free_font(font);
4603 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4605 struct list *face_elem_ptr;
4607 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4609 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4611 static const WCHAR spaceW[] = { ' ',0 };
4612 WCHAR full_family_name[LF_FULLFACESIZE];
4613 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4615 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4617 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4618 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4619 continue;
4622 strcpyW(full_family_name, family->FamilyName);
4623 strcatW(full_family_name, spaceW);
4624 strcatW(full_family_name, face->StyleName);
4625 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4628 return FALSE;
4631 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4633 static const WCHAR spaceW[] = { ' ',0 };
4634 WCHAR full_family_name[LF_FULLFACESIZE];
4636 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4638 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4640 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4641 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4642 return FALSE;
4645 strcpyW(full_family_name, face->family->FamilyName);
4646 strcatW(full_family_name, spaceW);
4647 strcatW(full_family_name, face->StyleName);
4648 return !strcmpiW(lf->lfFaceName, full_family_name);
4651 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4652 FONTENUMPROCW proc, LPARAM lparam)
4654 ENUMLOGFONTEXW elf;
4655 NEWTEXTMETRICEXW ntm;
4656 DWORD type = 0;
4657 int i;
4659 GetEnumStructs(face, &elf, &ntm, &type);
4660 for(i = 0; i < list->total; i++) {
4661 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4662 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4663 load_script_name( IDS_OEM_DOS, elf.elfScript );
4664 i = list->total; /* break out of loop after enumeration */
4665 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4666 continue;
4667 else {
4668 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4669 strcpyW(elf.elfScript, list->element[i].name);
4670 if (!elf.elfScript[0])
4671 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4673 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4674 debugstr_w(elf.elfLogFont.lfFaceName),
4675 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4676 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4677 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4678 ntm.ntmTm.ntmFlags);
4679 /* release section before callback (FIXME) */
4680 LeaveCriticalSection( &freetype_cs );
4681 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4682 EnterCriticalSection( &freetype_cs );
4684 return TRUE;
4687 /*************************************************************
4688 * freetype_EnumFonts
4690 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4692 Family *family;
4693 Face *face;
4694 struct list *family_elem_ptr, *face_elem_ptr;
4695 LOGFONTW lf;
4696 struct enum_charset_list enum_charsets;
4698 if (!plf)
4700 lf.lfCharSet = DEFAULT_CHARSET;
4701 lf.lfPitchAndFamily = 0;
4702 lf.lfFaceName[0] = 0;
4703 plf = &lf;
4706 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4708 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4710 GDI_CheckNotLock();
4711 EnterCriticalSection( &freetype_cs );
4712 if(plf->lfFaceName[0]) {
4713 FontSubst *psub;
4714 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4716 if(psub) {
4717 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4718 debugstr_w(psub->to.name));
4719 lf = *plf;
4720 strcpyW(lf.lfFaceName, psub->to.name);
4721 plf = &lf;
4724 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4725 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4726 if(family_matches(family, plf)) {
4727 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4728 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4729 if (!face_matches(face, plf)) continue;
4730 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4734 } else {
4735 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4736 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4737 face_elem_ptr = list_head(&family->faces);
4738 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4739 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4742 LeaveCriticalSection( &freetype_cs );
4743 return TRUE;
4746 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4748 pt->x.value = vec->x >> 6;
4749 pt->x.fract = (vec->x & 0x3f) << 10;
4750 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4751 pt->y.value = vec->y >> 6;
4752 pt->y.fract = (vec->y & 0x3f) << 10;
4753 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4754 return;
4757 /***************************************************
4758 * According to the MSDN documentation on WideCharToMultiByte,
4759 * certain codepages cannot set the default_used parameter.
4760 * This returns TRUE if the codepage can set that parameter, false else
4761 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4763 static BOOL codepage_sets_default_used(UINT codepage)
4765 switch (codepage)
4767 case CP_UTF7:
4768 case CP_UTF8:
4769 case CP_SYMBOL:
4770 return FALSE;
4771 default:
4772 return TRUE;
4777 * GSUB Table handling functions
4780 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4782 const GSUB_CoverageFormat1* cf1;
4784 cf1 = table;
4786 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4788 int count = GET_BE_WORD(cf1->GlyphCount);
4789 int i;
4790 TRACE("Coverage Format 1, %i glyphs\n",count);
4791 for (i = 0; i < count; i++)
4792 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4793 return i;
4794 return -1;
4796 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4798 const GSUB_CoverageFormat2* cf2;
4799 int i;
4800 int count;
4801 cf2 = (const GSUB_CoverageFormat2*)cf1;
4803 count = GET_BE_WORD(cf2->RangeCount);
4804 TRACE("Coverage Format 2, %i ranges\n",count);
4805 for (i = 0; i < count; i++)
4807 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4808 return -1;
4809 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4810 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4812 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4813 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4816 return -1;
4818 else
4819 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4821 return -1;
4824 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4826 const GSUB_ScriptList *script;
4827 const GSUB_Script *deflt = NULL;
4828 int i;
4829 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4831 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4832 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4834 const GSUB_Script *scr;
4835 int offset;
4837 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4838 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4840 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4841 return scr;
4842 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4843 deflt = scr;
4845 return deflt;
4848 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4850 int i;
4851 int offset;
4852 const GSUB_LangSys *Lang;
4854 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4856 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4858 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4859 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4861 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4862 return Lang;
4864 offset = GET_BE_WORD(script->DefaultLangSys);
4865 if (offset)
4867 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4868 return Lang;
4870 return NULL;
4873 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4875 int i;
4876 const GSUB_FeatureList *feature;
4877 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4879 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4880 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4882 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4883 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4885 const GSUB_Feature *feat;
4886 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4887 return feat;
4890 return NULL;
4893 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4895 int i;
4896 int offset;
4897 const GSUB_LookupList *lookup;
4898 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4900 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4901 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4903 const GSUB_LookupTable *look;
4904 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4905 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4906 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4907 if (GET_BE_WORD(look->LookupType) != 1)
4908 FIXME("We only handle SubType 1\n");
4909 else
4911 int j;
4913 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4915 const GSUB_SingleSubstFormat1 *ssf1;
4916 offset = GET_BE_WORD(look->SubTable[j]);
4917 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4918 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4920 int offset = GET_BE_WORD(ssf1->Coverage);
4921 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4922 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4924 TRACE(" Glyph 0x%x ->",glyph);
4925 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4926 TRACE(" 0x%x\n",glyph);
4929 else
4931 const GSUB_SingleSubstFormat2 *ssf2;
4932 INT index;
4933 INT offset;
4935 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4936 offset = GET_BE_WORD(ssf1->Coverage);
4937 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4938 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4939 TRACE(" Coverage index %i\n",index);
4940 if (index != -1)
4942 TRACE(" Glyph is 0x%x ->",glyph);
4943 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4944 TRACE("0x%x\n",glyph);
4950 return glyph;
4953 static const char* get_opentype_script(const GdiFont *font)
4956 * I am not sure if this is the correct way to generate our script tag
4959 switch (font->charset)
4961 case ANSI_CHARSET: return "latn";
4962 case BALTIC_CHARSET: return "latn"; /* ?? */
4963 case CHINESEBIG5_CHARSET: return "hani";
4964 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4965 case GB2312_CHARSET: return "hani";
4966 case GREEK_CHARSET: return "grek";
4967 case HANGUL_CHARSET: return "hang";
4968 case RUSSIAN_CHARSET: return "cyrl";
4969 case SHIFTJIS_CHARSET: return "kana";
4970 case TURKISH_CHARSET: return "latn"; /* ?? */
4971 case VIETNAMESE_CHARSET: return "latn";
4972 case JOHAB_CHARSET: return "latn"; /* ?? */
4973 case ARABIC_CHARSET: return "arab";
4974 case HEBREW_CHARSET: return "hebr";
4975 case THAI_CHARSET: return "thai";
4976 default: return "latn";
4980 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4982 const GSUB_Header *header;
4983 const GSUB_Script *script;
4984 const GSUB_LangSys *language;
4985 const GSUB_Feature *feature;
4987 if (!font->GSUB_Table)
4988 return glyph;
4990 header = font->GSUB_Table;
4992 script = GSUB_get_script_table(header, get_opentype_script(font));
4993 if (!script)
4995 TRACE("Script not found\n");
4996 return glyph;
4998 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4999 if (!language)
5001 TRACE("Language not found\n");
5002 return glyph;
5004 feature = GSUB_get_feature(header, language, "vrt2");
5005 if (!feature)
5006 feature = GSUB_get_feature(header, language, "vert");
5007 if (!feature)
5009 TRACE("vrt2/vert feature not found\n");
5010 return glyph;
5012 return GSUB_apply_feature(header, feature, glyph);
5015 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5017 FT_UInt glyphId;
5019 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5020 WCHAR wc = (WCHAR)glyph;
5021 BOOL default_used;
5022 BOOL *default_used_pointer;
5023 FT_UInt ret;
5024 char buf;
5025 default_used_pointer = NULL;
5026 default_used = FALSE;
5027 if (codepage_sets_default_used(font->codepage))
5028 default_used_pointer = &default_used;
5029 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5030 ret = 0;
5031 else
5032 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5033 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5034 return ret;
5037 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5039 if (glyph < 0x100) glyph += 0xf000;
5040 /* there is a number of old pre-Unicode "broken" TTFs, which
5041 do have symbols at U+00XX instead of U+f0XX */
5042 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5043 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5045 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5047 return glyphId;
5050 /*************************************************************
5051 * freetype_GetGlyphIndices
5053 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5055 struct freetype_physdev *physdev = get_freetype_dev( dev );
5056 int i;
5057 WORD default_char;
5058 BOOL got_default = FALSE;
5060 if (!physdev->font)
5062 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5063 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5066 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5068 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5069 got_default = TRUE;
5072 GDI_CheckNotLock();
5073 EnterCriticalSection( &freetype_cs );
5075 for(i = 0; i < count; i++)
5077 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5078 if (pgi[i] == 0)
5080 if (!got_default)
5082 if (FT_IS_SFNT(physdev->font->ft_face))
5084 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5085 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5087 else
5089 TEXTMETRICW textm;
5090 get_text_metrics(physdev->font, &textm);
5091 default_char = textm.tmDefaultChar;
5093 got_default = TRUE;
5095 pgi[i] = default_char;
5098 LeaveCriticalSection( &freetype_cs );
5099 return count;
5102 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5104 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5105 return !memcmp(matrix, &identity, sizeof(FMAT2));
5108 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5110 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5111 return !memcmp(matrix, &identity, sizeof(MAT2));
5114 static inline BYTE get_max_level( UINT format )
5116 switch( format )
5118 case GGO_GRAY2_BITMAP: return 4;
5119 case GGO_GRAY4_BITMAP: return 16;
5120 case GGO_GRAY8_BITMAP: return 64;
5122 return 255;
5125 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5127 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5128 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5129 const MAT2* lpmat)
5131 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5132 FT_Face ft_face = incoming_font->ft_face;
5133 GdiFont *font = incoming_font;
5134 FT_UInt glyph_index;
5135 DWORD width, height, pitch, needed = 0;
5136 FT_Bitmap ft_bitmap;
5137 FT_Error err;
5138 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5139 FT_Angle angle = 0;
5140 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5141 double widthRatio = 1.0;
5142 FT_Matrix transMat = identityMat;
5143 FT_Matrix transMatUnrotated;
5144 BOOL needsTransform = FALSE;
5145 BOOL tategaki = (font->GSUB_Table != NULL);
5146 UINT original_index;
5148 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5149 buflen, buf, lpmat);
5151 TRACE("font transform %f %f %f %f\n",
5152 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5153 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5155 if(format & GGO_GLYPH_INDEX) {
5156 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5157 original_index = glyph;
5158 format &= ~GGO_GLYPH_INDEX;
5159 } else {
5160 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5161 ft_face = font->ft_face;
5162 original_index = glyph_index;
5165 if(format & GGO_UNHINTED) {
5166 load_flags |= FT_LOAD_NO_HINTING;
5167 format &= ~GGO_UNHINTED;
5170 /* tategaki never appears to happen to lower glyph index */
5171 if (glyph_index < TATEGAKI_LOWER_BOUND )
5172 tategaki = FALSE;
5174 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5175 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5176 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5177 font->gmsize * sizeof(GM*));
5178 } else {
5179 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5180 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5182 *lpgm = FONT_GM(font,original_index)->gm;
5183 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5184 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5185 lpgm->gmCellIncX, lpgm->gmCellIncY);
5186 return 1; /* FIXME */
5190 if (!font->gm[original_index / GM_BLOCK_SIZE])
5191 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5193 /* Scaling factor */
5194 if (font->aveWidth)
5196 TEXTMETRICW tm;
5198 get_text_metrics(font, &tm);
5200 widthRatio = (double)font->aveWidth;
5201 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5203 else
5204 widthRatio = font->scale_y;
5206 /* Scaling transform */
5207 if (widthRatio != 1.0 || font->scale_y != 1.0)
5209 FT_Matrix scaleMat;
5210 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5211 scaleMat.xy = 0;
5212 scaleMat.yx = 0;
5213 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5215 pFT_Matrix_Multiply(&scaleMat, &transMat);
5216 needsTransform = TRUE;
5219 /* Slant transform */
5220 if (font->fake_italic) {
5221 FT_Matrix slantMat;
5223 slantMat.xx = (1 << 16);
5224 slantMat.xy = ((1 << 16) >> 2);
5225 slantMat.yx = 0;
5226 slantMat.yy = (1 << 16);
5227 pFT_Matrix_Multiply(&slantMat, &transMat);
5228 needsTransform = TRUE;
5231 /* Rotation transform */
5232 transMatUnrotated = transMat;
5233 if(font->orientation && !tategaki) {
5234 FT_Matrix rotationMat;
5235 FT_Vector vecAngle;
5236 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5237 pFT_Vector_Unit(&vecAngle, angle);
5238 rotationMat.xx = vecAngle.x;
5239 rotationMat.xy = -vecAngle.y;
5240 rotationMat.yx = -rotationMat.xy;
5241 rotationMat.yy = rotationMat.xx;
5243 pFT_Matrix_Multiply(&rotationMat, &transMat);
5244 needsTransform = TRUE;
5247 /* World transform */
5248 if (!is_identity_FMAT2(&font->font_desc.matrix))
5250 FT_Matrix worldMat;
5251 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5252 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5253 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5254 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5255 pFT_Matrix_Multiply(&worldMat, &transMat);
5256 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5257 needsTransform = TRUE;
5260 /* Extra transformation specified by caller */
5261 if (!is_identity_MAT2(lpmat))
5263 FT_Matrix extraMat;
5264 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5265 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5266 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5267 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5268 pFT_Matrix_Multiply(&extraMat, &transMat);
5269 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5270 needsTransform = TRUE;
5273 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5274 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5275 format == GGO_GRAY8_BITMAP))
5277 load_flags |= FT_LOAD_NO_BITMAP;
5280 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5282 if(err) {
5283 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5284 return GDI_ERROR;
5287 if(!needsTransform) {
5288 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5289 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5290 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5292 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5293 bottom = (ft_face->glyph->metrics.horiBearingY -
5294 ft_face->glyph->metrics.height) & -64;
5295 lpgm->gmCellIncX = adv;
5296 lpgm->gmCellIncY = 0;
5297 } else {
5298 INT xc, yc;
5299 FT_Vector vec;
5301 left = right = 0;
5303 for(xc = 0; xc < 2; xc++) {
5304 for(yc = 0; yc < 2; yc++) {
5305 vec.x = (ft_face->glyph->metrics.horiBearingX +
5306 xc * ft_face->glyph->metrics.width);
5307 vec.y = ft_face->glyph->metrics.horiBearingY -
5308 yc * ft_face->glyph->metrics.height;
5309 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5310 pFT_Vector_Transform(&vec, &transMat);
5311 if(xc == 0 && yc == 0) {
5312 left = right = vec.x;
5313 top = bottom = vec.y;
5314 } else {
5315 if(vec.x < left) left = vec.x;
5316 else if(vec.x > right) right = vec.x;
5317 if(vec.y < bottom) bottom = vec.y;
5318 else if(vec.y > top) top = vec.y;
5322 left = left & -64;
5323 right = (right + 63) & -64;
5324 bottom = bottom & -64;
5325 top = (top + 63) & -64;
5327 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5328 vec.x = ft_face->glyph->metrics.horiAdvance;
5329 vec.y = 0;
5330 pFT_Vector_Transform(&vec, &transMat);
5331 lpgm->gmCellIncX = (vec.x+63) >> 6;
5332 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5334 vec.x = ft_face->glyph->metrics.horiAdvance;
5335 vec.y = 0;
5336 pFT_Vector_Transform(&vec, &transMatUnrotated);
5337 adv = (vec.x+63) >> 6;
5340 lsb = left >> 6;
5341 bbx = (right - left) >> 6;
5342 lpgm->gmBlackBoxX = (right - left) >> 6;
5343 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5344 lpgm->gmptGlyphOrigin.x = left >> 6;
5345 lpgm->gmptGlyphOrigin.y = top >> 6;
5347 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5348 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5349 lpgm->gmCellIncX, lpgm->gmCellIncY);
5351 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5352 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5354 FONT_GM(font,original_index)->gm = *lpgm;
5355 FONT_GM(font,original_index)->adv = adv;
5356 FONT_GM(font,original_index)->lsb = lsb;
5357 FONT_GM(font,original_index)->bbx = bbx;
5358 FONT_GM(font,original_index)->init = TRUE;
5361 if(format == GGO_METRICS)
5363 return 1; /* FIXME */
5366 if(ft_face->glyph->format != ft_glyph_format_outline &&
5367 (format == GGO_NATIVE || format == GGO_BEZIER))
5369 TRACE("loaded a bitmap\n");
5370 return GDI_ERROR;
5373 switch(format) {
5374 case GGO_BITMAP:
5375 width = lpgm->gmBlackBoxX;
5376 height = lpgm->gmBlackBoxY;
5377 pitch = ((width + 31) >> 5) << 2;
5378 needed = pitch * height;
5380 if(!buf || !buflen) break;
5382 switch(ft_face->glyph->format) {
5383 case ft_glyph_format_bitmap:
5385 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5386 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5387 INT h = ft_face->glyph->bitmap.rows;
5388 while(h--) {
5389 memcpy(dst, src, w);
5390 src += ft_face->glyph->bitmap.pitch;
5391 dst += pitch;
5393 break;
5396 case ft_glyph_format_outline:
5397 ft_bitmap.width = width;
5398 ft_bitmap.rows = height;
5399 ft_bitmap.pitch = pitch;
5400 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5401 ft_bitmap.buffer = buf;
5403 if(needsTransform)
5404 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5406 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5408 /* Note: FreeType will only set 'black' bits for us. */
5409 memset(buf, 0, needed);
5410 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5411 break;
5413 default:
5414 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5415 return GDI_ERROR;
5417 break;
5419 case GGO_GRAY2_BITMAP:
5420 case GGO_GRAY4_BITMAP:
5421 case GGO_GRAY8_BITMAP:
5422 case WINE_GGO_GRAY16_BITMAP:
5424 unsigned int max_level, row, col;
5425 BYTE *start, *ptr;
5427 width = lpgm->gmBlackBoxX;
5428 height = lpgm->gmBlackBoxY;
5429 pitch = (width + 3) / 4 * 4;
5430 needed = pitch * height;
5432 if(!buf || !buflen) break;
5434 max_level = get_max_level( format );
5436 switch(ft_face->glyph->format) {
5437 case ft_glyph_format_bitmap:
5439 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5440 INT h = ft_face->glyph->bitmap.rows;
5441 INT x;
5442 memset( buf, 0, needed );
5443 while(h--) {
5444 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5445 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5446 src += ft_face->glyph->bitmap.pitch;
5447 dst += pitch;
5449 return needed;
5451 case ft_glyph_format_outline:
5453 ft_bitmap.width = width;
5454 ft_bitmap.rows = height;
5455 ft_bitmap.pitch = pitch;
5456 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5457 ft_bitmap.buffer = buf;
5459 if(needsTransform)
5460 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5462 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5464 memset(ft_bitmap.buffer, 0, buflen);
5466 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5468 if (max_level != 255)
5470 for (row = 0, start = buf; row < height; row++)
5472 for (col = 0, ptr = start; col < width; col++, ptr++)
5473 *ptr = (((int)*ptr) * max_level + 128) / 256;
5474 start += pitch;
5477 return needed;
5480 default:
5481 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5482 return GDI_ERROR;
5484 break;
5487 case WINE_GGO_HRGB_BITMAP:
5488 case WINE_GGO_HBGR_BITMAP:
5489 case WINE_GGO_VRGB_BITMAP:
5490 case WINE_GGO_VBGR_BITMAP:
5491 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5493 switch (ft_face->glyph->format)
5495 case FT_GLYPH_FORMAT_BITMAP:
5497 BYTE *src, *dst;
5498 INT src_pitch, x;
5500 width = lpgm->gmBlackBoxX;
5501 height = lpgm->gmBlackBoxY;
5502 pitch = width * 4;
5503 needed = pitch * height;
5505 if (!buf || !buflen) break;
5507 memset(buf, 0, buflen);
5508 dst = buf;
5509 src = ft_face->glyph->bitmap.buffer;
5510 src_pitch = ft_face->glyph->bitmap.pitch;
5512 height = min( height, ft_face->glyph->bitmap.rows );
5513 while ( height-- )
5515 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5517 if ( src[x / 8] & masks[x % 8] )
5518 ((unsigned int *)dst)[x] = ~0u;
5520 src += src_pitch;
5521 dst += pitch;
5524 break;
5527 case FT_GLYPH_FORMAT_OUTLINE:
5529 unsigned int *dst;
5530 BYTE *src;
5531 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5532 INT x_shift, y_shift;
5533 BOOL rgb;
5534 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5535 FT_Render_Mode render_mode =
5536 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5537 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5539 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5541 if ( render_mode == FT_RENDER_MODE_LCD)
5543 lpgm->gmBlackBoxX += 2;
5544 lpgm->gmptGlyphOrigin.x -= 1;
5546 else
5548 lpgm->gmBlackBoxY += 2;
5549 lpgm->gmptGlyphOrigin.y += 1;
5553 width = lpgm->gmBlackBoxX;
5554 height = lpgm->gmBlackBoxY;
5555 pitch = width * 4;
5556 needed = pitch * height;
5558 if (!buf || !buflen) break;
5560 memset(buf, 0, buflen);
5561 dst = buf;
5562 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5564 if ( needsTransform )
5565 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5567 if ( pFT_Library_SetLcdFilter )
5568 pFT_Library_SetLcdFilter( library, lcdfilter );
5569 pFT_Render_Glyph (ft_face->glyph, render_mode);
5571 src = ft_face->glyph->bitmap.buffer;
5572 src_pitch = ft_face->glyph->bitmap.pitch;
5573 src_width = ft_face->glyph->bitmap.width;
5574 src_height = ft_face->glyph->bitmap.rows;
5576 if ( render_mode == FT_RENDER_MODE_LCD)
5578 rgb_interval = 1;
5579 hmul = 3;
5580 vmul = 1;
5582 else
5584 rgb_interval = src_pitch;
5585 hmul = 1;
5586 vmul = 3;
5589 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5590 if ( x_shift < 0 ) x_shift = 0;
5591 if ( x_shift + (src_width / hmul) > width )
5592 x_shift = width - (src_width / hmul);
5594 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5595 if ( y_shift < 0 ) y_shift = 0;
5596 if ( y_shift + (src_height / vmul) > height )
5597 y_shift = height - (src_height / vmul);
5599 dst += x_shift + y_shift * ( pitch / 4 );
5600 while ( src_height )
5602 for ( x = 0; x < src_width / hmul; x++ )
5604 if ( rgb )
5606 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5607 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5608 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5609 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5611 else
5613 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5614 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5615 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5616 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5619 src += src_pitch * vmul;
5620 dst += pitch / 4;
5621 src_height -= vmul;
5624 break;
5627 default:
5628 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5629 return GDI_ERROR;
5632 break;
5634 #else
5635 return GDI_ERROR;
5636 #endif
5638 case GGO_NATIVE:
5640 int contour, point = 0, first_pt;
5641 FT_Outline *outline = &ft_face->glyph->outline;
5642 TTPOLYGONHEADER *pph;
5643 TTPOLYCURVE *ppc;
5644 DWORD pph_start, cpfx, type;
5646 if(buflen == 0) buf = NULL;
5648 if (needsTransform && buf) {
5649 pFT_Outline_Transform(outline, &transMat);
5652 for(contour = 0; contour < outline->n_contours; contour++) {
5653 pph_start = needed;
5654 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5655 first_pt = point;
5656 if(buf) {
5657 pph->dwType = TT_POLYGON_TYPE;
5658 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5660 needed += sizeof(*pph);
5661 point++;
5662 while(point <= outline->contours[contour]) {
5663 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5664 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5665 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5666 cpfx = 0;
5667 do {
5668 if(buf)
5669 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5670 cpfx++;
5671 point++;
5672 } while(point <= outline->contours[contour] &&
5673 (outline->tags[point] & FT_Curve_Tag_On) ==
5674 (outline->tags[point-1] & FT_Curve_Tag_On));
5675 /* At the end of a contour Windows adds the start point, but
5676 only for Beziers */
5677 if(point > outline->contours[contour] &&
5678 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5679 if(buf)
5680 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5681 cpfx++;
5682 } else if(point <= outline->contours[contour] &&
5683 outline->tags[point] & FT_Curve_Tag_On) {
5684 /* add closing pt for bezier */
5685 if(buf)
5686 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5687 cpfx++;
5688 point++;
5690 if(buf) {
5691 ppc->wType = type;
5692 ppc->cpfx = cpfx;
5694 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5696 if(buf)
5697 pph->cb = needed - pph_start;
5699 break;
5701 case GGO_BEZIER:
5703 /* Convert the quadratic Beziers to cubic Beziers.
5704 The parametric eqn for a cubic Bezier is, from PLRM:
5705 r(t) = at^3 + bt^2 + ct + r0
5706 with the control points:
5707 r1 = r0 + c/3
5708 r2 = r1 + (c + b)/3
5709 r3 = r0 + c + b + a
5711 A quadratic Bezier has the form:
5712 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5714 So equating powers of t leads to:
5715 r1 = 2/3 p1 + 1/3 p0
5716 r2 = 2/3 p1 + 1/3 p2
5717 and of course r0 = p0, r3 = p2
5720 int contour, point = 0, first_pt;
5721 FT_Outline *outline = &ft_face->glyph->outline;
5722 TTPOLYGONHEADER *pph;
5723 TTPOLYCURVE *ppc;
5724 DWORD pph_start, cpfx, type;
5725 FT_Vector cubic_control[4];
5726 if(buflen == 0) buf = NULL;
5728 if (needsTransform && buf) {
5729 pFT_Outline_Transform(outline, &transMat);
5732 for(contour = 0; contour < outline->n_contours; contour++) {
5733 pph_start = needed;
5734 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5735 first_pt = point;
5736 if(buf) {
5737 pph->dwType = TT_POLYGON_TYPE;
5738 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5740 needed += sizeof(*pph);
5741 point++;
5742 while(point <= outline->contours[contour]) {
5743 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5744 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5745 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5746 cpfx = 0;
5747 do {
5748 if(type == TT_PRIM_LINE) {
5749 if(buf)
5750 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5751 cpfx++;
5752 point++;
5753 } else {
5754 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5755 so cpfx = 3n */
5757 /* FIXME: Possible optimization in endpoint calculation
5758 if there are two consecutive curves */
5759 cubic_control[0] = outline->points[point-1];
5760 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5761 cubic_control[0].x += outline->points[point].x + 1;
5762 cubic_control[0].y += outline->points[point].y + 1;
5763 cubic_control[0].x >>= 1;
5764 cubic_control[0].y >>= 1;
5766 if(point+1 > outline->contours[contour])
5767 cubic_control[3] = outline->points[first_pt];
5768 else {
5769 cubic_control[3] = outline->points[point+1];
5770 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5771 cubic_control[3].x += outline->points[point].x + 1;
5772 cubic_control[3].y += outline->points[point].y + 1;
5773 cubic_control[3].x >>= 1;
5774 cubic_control[3].y >>= 1;
5777 /* r1 = 1/3 p0 + 2/3 p1
5778 r2 = 1/3 p2 + 2/3 p1 */
5779 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5780 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5781 cubic_control[2] = cubic_control[1];
5782 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5783 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5784 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5785 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5786 if(buf) {
5787 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5788 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5789 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5791 cpfx += 3;
5792 point++;
5794 } while(point <= outline->contours[contour] &&
5795 (outline->tags[point] & FT_Curve_Tag_On) ==
5796 (outline->tags[point-1] & FT_Curve_Tag_On));
5797 /* At the end of a contour Windows adds the start point,
5798 but only for Beziers and we've already done that.
5800 if(point <= outline->contours[contour] &&
5801 outline->tags[point] & FT_Curve_Tag_On) {
5802 /* This is the closing pt of a bezier, but we've already
5803 added it, so just inc point and carry on */
5804 point++;
5806 if(buf) {
5807 ppc->wType = type;
5808 ppc->cpfx = cpfx;
5810 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5812 if(buf)
5813 pph->cb = needed - pph_start;
5815 break;
5818 default:
5819 FIXME("Unsupported format %d\n", format);
5820 return GDI_ERROR;
5822 return needed;
5825 static BOOL get_bitmap_text_metrics(GdiFont *font)
5827 FT_Face ft_face = font->ft_face;
5828 FT_WinFNT_HeaderRec winfnt_header;
5829 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5830 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5831 font->potm->otmSize = size;
5833 #define TM font->potm->otmTextMetrics
5834 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5836 TM.tmHeight = winfnt_header.pixel_height;
5837 TM.tmAscent = winfnt_header.ascent;
5838 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5839 TM.tmInternalLeading = winfnt_header.internal_leading;
5840 TM.tmExternalLeading = winfnt_header.external_leading;
5841 TM.tmAveCharWidth = winfnt_header.avg_width;
5842 TM.tmMaxCharWidth = winfnt_header.max_width;
5843 TM.tmWeight = winfnt_header.weight;
5844 TM.tmOverhang = 0;
5845 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5846 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5847 TM.tmFirstChar = winfnt_header.first_char;
5848 TM.tmLastChar = winfnt_header.last_char;
5849 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5850 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5851 TM.tmItalic = winfnt_header.italic;
5852 TM.tmUnderlined = font->underline;
5853 TM.tmStruckOut = font->strikeout;
5854 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5855 TM.tmCharSet = winfnt_header.charset;
5857 else
5859 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5860 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5861 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5862 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5863 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5864 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5865 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5866 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5867 TM.tmOverhang = 0;
5868 TM.tmDigitizedAspectX = 96; /* FIXME */
5869 TM.tmDigitizedAspectY = 96; /* FIXME */
5870 TM.tmFirstChar = 1;
5871 TM.tmLastChar = 255;
5872 TM.tmDefaultChar = 32;
5873 TM.tmBreakChar = 32;
5874 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5875 TM.tmUnderlined = font->underline;
5876 TM.tmStruckOut = font->strikeout;
5877 /* NB inverted meaning of TMPF_FIXED_PITCH */
5878 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5879 TM.tmCharSet = font->charset;
5881 #undef TM
5883 return TRUE;
5887 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5889 double scale_x, scale_y;
5891 if (font->aveWidth)
5893 scale_x = (double)font->aveWidth;
5894 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5896 else
5897 scale_x = font->scale_y;
5899 scale_x *= fabs(font->font_desc.matrix.eM11);
5900 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5902 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5903 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5905 SCALE_Y(ptm->tmHeight);
5906 SCALE_Y(ptm->tmAscent);
5907 SCALE_Y(ptm->tmDescent);
5908 SCALE_Y(ptm->tmInternalLeading);
5909 SCALE_Y(ptm->tmExternalLeading);
5910 SCALE_Y(ptm->tmOverhang);
5912 SCALE_X(ptm->tmAveCharWidth);
5913 SCALE_X(ptm->tmMaxCharWidth);
5915 #undef SCALE_X
5916 #undef SCALE_Y
5919 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5921 double scale_x, scale_y;
5923 if (font->aveWidth)
5925 scale_x = (double)font->aveWidth;
5926 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5928 else
5929 scale_x = font->scale_y;
5931 scale_x *= fabs(font->font_desc.matrix.eM11);
5932 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5934 scale_font_metrics(font, &potm->otmTextMetrics);
5936 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5937 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5939 SCALE_Y(potm->otmAscent);
5940 SCALE_Y(potm->otmDescent);
5941 SCALE_Y(potm->otmLineGap);
5942 SCALE_Y(potm->otmsCapEmHeight);
5943 SCALE_Y(potm->otmsXHeight);
5944 SCALE_Y(potm->otmrcFontBox.top);
5945 SCALE_Y(potm->otmrcFontBox.bottom);
5946 SCALE_X(potm->otmrcFontBox.left);
5947 SCALE_X(potm->otmrcFontBox.right);
5948 SCALE_Y(potm->otmMacAscent);
5949 SCALE_Y(potm->otmMacDescent);
5950 SCALE_Y(potm->otmMacLineGap);
5951 SCALE_X(potm->otmptSubscriptSize.x);
5952 SCALE_Y(potm->otmptSubscriptSize.y);
5953 SCALE_X(potm->otmptSubscriptOffset.x);
5954 SCALE_Y(potm->otmptSubscriptOffset.y);
5955 SCALE_X(potm->otmptSuperscriptSize.x);
5956 SCALE_Y(potm->otmptSuperscriptSize.y);
5957 SCALE_X(potm->otmptSuperscriptOffset.x);
5958 SCALE_Y(potm->otmptSuperscriptOffset.y);
5959 SCALE_Y(potm->otmsStrikeoutSize);
5960 SCALE_Y(potm->otmsStrikeoutPosition);
5961 SCALE_Y(potm->otmsUnderscoreSize);
5962 SCALE_Y(potm->otmsUnderscorePosition);
5964 #undef SCALE_X
5965 #undef SCALE_Y
5968 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5970 if(!font->potm)
5972 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
5974 /* Make sure that the font has sane width/height ratio */
5975 if (font->aveWidth)
5977 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5979 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5980 font->aveWidth = 0;
5984 *ptm = font->potm->otmTextMetrics;
5985 scale_font_metrics(font, ptm);
5986 return TRUE;
5989 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5991 int i;
5993 for(i = 0; i < ft_face->num_charmaps; i++)
5995 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5996 return TRUE;
5998 return FALSE;
6001 static BOOL get_outline_text_metrics(GdiFont *font)
6003 BOOL ret = FALSE;
6004 FT_Face ft_face = font->ft_face;
6005 UINT needed, lenfam, lensty;
6006 TT_OS2 *pOS2;
6007 TT_HoriHeader *pHori;
6008 TT_Postscript *pPost;
6009 FT_Fixed x_scale, y_scale;
6010 WCHAR *family_nameW, *style_nameW;
6011 static const WCHAR spaceW[] = {' ', '\0'};
6012 char *cp;
6013 INT ascent, descent;
6015 TRACE("font=%p\n", font);
6017 if(!FT_IS_SCALABLE(ft_face))
6018 return FALSE;
6020 needed = sizeof(*font->potm);
6022 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6023 family_nameW = strdupW(font->name);
6025 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6026 * sizeof(WCHAR);
6027 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6028 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6029 style_nameW, lensty/sizeof(WCHAR));
6031 /* These names should be read from the TT name table */
6033 /* length of otmpFamilyName */
6034 needed += lenfam;
6036 /* length of otmpFaceName */
6037 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6038 needed += lenfam; /* just the family name */
6039 } else {
6040 needed += lenfam + lensty; /* family + " " + style */
6043 /* length of otmpStyleName */
6044 needed += lensty;
6046 /* length of otmpFullName */
6047 needed += lenfam + lensty;
6050 x_scale = ft_face->size->metrics.x_scale;
6051 y_scale = ft_face->size->metrics.y_scale;
6053 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6054 if(!pOS2) {
6055 FIXME("Can't find OS/2 table - not TT font?\n");
6056 goto end;
6059 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6060 if(!pHori) {
6061 FIXME("Can't find HHEA table - not TT font?\n");
6062 goto end;
6065 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6067 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",
6068 pOS2->usWinAscent, pOS2->usWinDescent,
6069 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6070 ft_face->ascender, ft_face->descender, ft_face->height,
6071 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6072 ft_face->bbox.yMax, ft_face->bbox.yMin);
6074 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6075 font->potm->otmSize = needed;
6077 #define TM font->potm->otmTextMetrics
6079 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6080 ascent = pHori->Ascender;
6081 descent = -pHori->Descender;
6082 } else {
6083 ascent = pOS2->usWinAscent;
6084 descent = pOS2->usWinDescent;
6087 if(font->yMax) {
6088 TM.tmAscent = font->yMax;
6089 TM.tmDescent = -font->yMin;
6090 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6091 } else {
6092 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6093 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6094 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6095 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6098 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6100 /* MSDN says:
6101 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6103 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6104 ((ascent + descent) -
6105 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6107 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6108 if (TM.tmAveCharWidth == 0) {
6109 TM.tmAveCharWidth = 1;
6111 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6112 TM.tmWeight = FW_REGULAR;
6113 if (font->fake_bold)
6114 TM.tmWeight = FW_BOLD;
6115 else
6117 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6119 if (pOS2->usWeightClass > FW_MEDIUM)
6120 TM.tmWeight = pOS2->usWeightClass;
6122 else if (pOS2->usWeightClass <= FW_MEDIUM)
6123 TM.tmWeight = pOS2->usWeightClass;
6125 TM.tmOverhang = 0;
6126 TM.tmDigitizedAspectX = 300;
6127 TM.tmDigitizedAspectY = 300;
6128 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6129 * symbol range to 0 - f0ff
6132 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6134 TM.tmFirstChar = 0;
6135 switch(GetACP())
6137 case 1257: /* Baltic */
6138 TM.tmLastChar = 0xf8fd;
6139 break;
6140 default:
6141 TM.tmLastChar = 0xf0ff;
6143 TM.tmBreakChar = 0x20;
6144 TM.tmDefaultChar = 0x1f;
6146 else
6148 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6149 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6151 if(pOS2->usFirstCharIndex <= 1)
6152 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6153 else if (pOS2->usFirstCharIndex > 0xff)
6154 TM.tmBreakChar = 0x20;
6155 else
6156 TM.tmBreakChar = pOS2->usFirstCharIndex;
6157 TM.tmDefaultChar = TM.tmBreakChar - 1;
6159 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6160 TM.tmUnderlined = font->underline;
6161 TM.tmStruckOut = font->strikeout;
6163 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6164 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6165 (pOS2->version == 0xFFFFU ||
6166 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6167 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6168 else
6169 TM.tmPitchAndFamily = 0;
6171 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6173 case PAN_FAMILY_SCRIPT:
6174 TM.tmPitchAndFamily |= FF_SCRIPT;
6175 break;
6177 case PAN_FAMILY_DECORATIVE:
6178 TM.tmPitchAndFamily |= FF_DECORATIVE;
6179 break;
6181 case PAN_ANY:
6182 case PAN_NO_FIT:
6183 case PAN_FAMILY_TEXT_DISPLAY:
6184 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6185 /* which is clearly not what the panose spec says. */
6186 default:
6187 if(TM.tmPitchAndFamily == 0 || /* fixed */
6188 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6189 TM.tmPitchAndFamily = FF_MODERN;
6190 else
6192 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6194 case PAN_ANY:
6195 case PAN_NO_FIT:
6196 default:
6197 TM.tmPitchAndFamily |= FF_DONTCARE;
6198 break;
6200 case PAN_SERIF_COVE:
6201 case PAN_SERIF_OBTUSE_COVE:
6202 case PAN_SERIF_SQUARE_COVE:
6203 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6204 case PAN_SERIF_SQUARE:
6205 case PAN_SERIF_THIN:
6206 case PAN_SERIF_BONE:
6207 case PAN_SERIF_EXAGGERATED:
6208 case PAN_SERIF_TRIANGLE:
6209 TM.tmPitchAndFamily |= FF_ROMAN;
6210 break;
6212 case PAN_SERIF_NORMAL_SANS:
6213 case PAN_SERIF_OBTUSE_SANS:
6214 case PAN_SERIF_PERP_SANS:
6215 case PAN_SERIF_FLARED:
6216 case PAN_SERIF_ROUNDED:
6217 TM.tmPitchAndFamily |= FF_SWISS;
6218 break;
6221 break;
6224 if(FT_IS_SCALABLE(ft_face))
6225 TM.tmPitchAndFamily |= TMPF_VECTOR;
6227 if(FT_IS_SFNT(ft_face))
6229 if (font->ntmFlags & NTM_PS_OPENTYPE)
6230 TM.tmPitchAndFamily |= TMPF_DEVICE;
6231 else
6232 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6235 TM.tmCharSet = font->charset;
6237 font->potm->otmFiller = 0;
6238 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6239 font->potm->otmfsSelection = pOS2->fsSelection;
6240 font->potm->otmfsType = pOS2->fsType;
6241 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6242 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6243 font->potm->otmItalicAngle = 0; /* POST table */
6244 font->potm->otmEMSquare = ft_face->units_per_EM;
6245 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6246 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6247 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6248 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6249 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6250 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6251 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6252 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6253 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6254 font->potm->otmMacAscent = TM.tmAscent;
6255 font->potm->otmMacDescent = -TM.tmDescent;
6256 font->potm->otmMacLineGap = font->potm->otmLineGap;
6257 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6258 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6259 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6260 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6261 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6262 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6263 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6264 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6265 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6266 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6267 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6268 if(!pPost) {
6269 font->potm->otmsUnderscoreSize = 0;
6270 font->potm->otmsUnderscorePosition = 0;
6271 } else {
6272 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6273 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6275 #undef TM
6277 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6278 cp = (char*)font->potm + sizeof(*font->potm);
6279 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6280 strcpyW((WCHAR*)cp, family_nameW);
6281 cp += lenfam;
6282 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6283 strcpyW((WCHAR*)cp, style_nameW);
6284 cp += lensty;
6285 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6286 strcpyW((WCHAR*)cp, family_nameW);
6287 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6288 strcatW((WCHAR*)cp, spaceW);
6289 strcatW((WCHAR*)cp, style_nameW);
6290 cp += lenfam + lensty;
6291 } else
6292 cp += lenfam;
6293 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6294 strcpyW((WCHAR*)cp, family_nameW);
6295 strcatW((WCHAR*)cp, spaceW);
6296 strcatW((WCHAR*)cp, style_nameW);
6297 ret = TRUE;
6299 end:
6300 HeapFree(GetProcessHeap(), 0, style_nameW);
6301 HeapFree(GetProcessHeap(), 0, family_nameW);
6302 return ret;
6305 /*************************************************************
6306 * freetype_GetGlyphOutline
6308 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6309 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6311 struct freetype_physdev *physdev = get_freetype_dev( dev );
6312 DWORD ret;
6314 if (!physdev->font)
6316 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6317 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6320 GDI_CheckNotLock();
6321 EnterCriticalSection( &freetype_cs );
6322 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6323 LeaveCriticalSection( &freetype_cs );
6324 return ret;
6327 /*************************************************************
6328 * freetype_GetTextMetrics
6330 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6332 struct freetype_physdev *physdev = get_freetype_dev( dev );
6333 BOOL ret;
6335 if (!physdev->font)
6337 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6338 return dev->funcs->pGetTextMetrics( dev, metrics );
6341 GDI_CheckNotLock();
6342 EnterCriticalSection( &freetype_cs );
6343 ret = get_text_metrics( physdev->font, metrics );
6344 LeaveCriticalSection( &freetype_cs );
6345 return ret;
6348 /*************************************************************
6349 * freetype_GetOutlineTextMetrics
6351 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6353 struct freetype_physdev *physdev = get_freetype_dev( dev );
6354 UINT ret = 0;
6356 if (!physdev->font)
6358 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6359 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6362 TRACE("font=%p\n", physdev->font);
6364 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6366 GDI_CheckNotLock();
6367 EnterCriticalSection( &freetype_cs );
6369 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6371 if(cbSize >= physdev->font->potm->otmSize)
6373 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6374 scale_outline_font_metrics(physdev->font, potm);
6376 ret = physdev->font->potm->otmSize;
6378 LeaveCriticalSection( &freetype_cs );
6379 return ret;
6382 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6384 HFONTLIST *hfontlist;
6385 child->font = alloc_font();
6386 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6387 if(!child->font->ft_face)
6389 free_font(child->font);
6390 child->font = NULL;
6391 return FALSE;
6394 child->font->font_desc = font->font_desc;
6395 child->font->ntmFlags = child->face->ntmFlags;
6396 child->font->orientation = font->orientation;
6397 child->font->scale_y = font->scale_y;
6398 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6399 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6400 child->font->name = strdupW(child->face->family->FamilyName);
6401 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6402 child->font->base_font = font;
6403 list_add_head(&child_font_list, &child->font->entry);
6404 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6405 return TRUE;
6408 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6410 FT_UInt g;
6411 CHILD_FONT *child_font;
6413 if(font->base_font)
6414 font = font->base_font;
6416 *linked_font = font;
6418 if((*glyph = get_glyph_index(font, c)))
6420 *glyph = get_GSUB_vert_glyph(font, *glyph);
6421 return TRUE;
6424 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6426 if(!child_font->font)
6427 if(!load_child_font(font, child_font))
6428 continue;
6430 if(!child_font->font->ft_face)
6431 continue;
6432 g = get_glyph_index(child_font->font, c);
6433 g = get_GSUB_vert_glyph(child_font->font, g);
6434 if(g)
6436 *glyph = g;
6437 *linked_font = child_font->font;
6438 return TRUE;
6441 return FALSE;
6444 /*************************************************************
6445 * freetype_GetCharWidth
6447 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6449 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6450 UINT c;
6451 GLYPHMETRICS gm;
6452 FT_UInt glyph_index;
6453 GdiFont *linked_font;
6454 struct freetype_physdev *physdev = get_freetype_dev( dev );
6456 if (!physdev->font)
6458 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6459 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6462 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6464 GDI_CheckNotLock();
6465 EnterCriticalSection( &freetype_cs );
6466 for(c = firstChar; c <= lastChar; c++) {
6467 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6468 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6469 &gm, 0, NULL, &identity);
6470 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6472 LeaveCriticalSection( &freetype_cs );
6473 return TRUE;
6476 /*************************************************************
6477 * freetype_GetCharABCWidths
6479 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6481 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6482 UINT c;
6483 GLYPHMETRICS gm;
6484 FT_UInt glyph_index;
6485 GdiFont *linked_font;
6486 struct freetype_physdev *physdev = get_freetype_dev( dev );
6488 if (!physdev->font)
6490 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6491 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6494 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6496 GDI_CheckNotLock();
6497 EnterCriticalSection( &freetype_cs );
6499 for(c = firstChar; c <= lastChar; c++) {
6500 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6501 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6502 &gm, 0, NULL, &identity);
6503 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6504 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6505 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6506 FONT_GM(linked_font,glyph_index)->bbx;
6508 LeaveCriticalSection( &freetype_cs );
6509 return TRUE;
6512 /*************************************************************
6513 * freetype_GetCharABCWidthsI
6515 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6517 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6518 UINT c;
6519 GLYPHMETRICS gm;
6520 FT_UInt glyph_index;
6521 GdiFont *linked_font;
6522 struct freetype_physdev *physdev = get_freetype_dev( dev );
6524 if (!physdev->font)
6526 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6527 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6530 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6531 return FALSE;
6533 GDI_CheckNotLock();
6534 EnterCriticalSection( &freetype_cs );
6536 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6537 if (!pgi)
6538 for(c = firstChar; c < firstChar+count; c++) {
6539 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6540 &gm, 0, NULL, &identity);
6541 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6542 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6543 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6544 - FONT_GM(linked_font,c)->bbx;
6546 else
6547 for(c = 0; c < count; c++) {
6548 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6549 &gm, 0, NULL, &identity);
6550 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6551 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6552 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6553 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6556 LeaveCriticalSection( &freetype_cs );
6557 return TRUE;
6560 /*************************************************************
6561 * freetype_GetTextExtentExPoint
6563 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6564 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6566 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6567 INT idx;
6568 INT nfit = 0, ext;
6569 GLYPHMETRICS gm;
6570 TEXTMETRICW tm;
6571 FT_UInt glyph_index;
6572 GdiFont *linked_font;
6573 struct freetype_physdev *physdev = get_freetype_dev( dev );
6575 if (!physdev->font)
6577 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6578 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6581 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6583 GDI_CheckNotLock();
6584 EnterCriticalSection( &freetype_cs );
6586 size->cx = 0;
6587 get_text_metrics( physdev->font, &tm );
6588 size->cy = tm.tmHeight;
6590 for(idx = 0; idx < count; idx++) {
6591 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6592 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6593 &gm, 0, NULL, &identity);
6594 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6595 ext = size->cx;
6596 if (! pnfit || ext <= max_ext) {
6597 ++nfit;
6598 if (dxs)
6599 dxs[idx] = ext;
6603 if (pnfit)
6604 *pnfit = nfit;
6606 LeaveCriticalSection( &freetype_cs );
6607 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6608 return TRUE;
6611 /*************************************************************
6612 * freetype_GetTextExtentExPointI
6614 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6615 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6617 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6618 INT idx;
6619 INT nfit = 0, ext;
6620 GLYPHMETRICS gm;
6621 TEXTMETRICW tm;
6622 struct freetype_physdev *physdev = get_freetype_dev( dev );
6624 if (!physdev->font)
6626 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6627 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6630 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6632 GDI_CheckNotLock();
6633 EnterCriticalSection( &freetype_cs );
6635 size->cx = 0;
6636 get_text_metrics(physdev->font, &tm);
6637 size->cy = tm.tmHeight;
6639 for(idx = 0; idx < count; idx++) {
6640 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6641 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6642 ext = size->cx;
6643 if (! pnfit || ext <= max_ext) {
6644 ++nfit;
6645 if (dxs)
6646 dxs[idx] = ext;
6650 if (pnfit)
6651 *pnfit = nfit;
6653 LeaveCriticalSection( &freetype_cs );
6654 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6655 return TRUE;
6658 /*************************************************************
6659 * freetype_GetFontData
6661 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6663 struct freetype_physdev *physdev = get_freetype_dev( dev );
6665 if (!physdev->font)
6667 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6668 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6671 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6672 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6673 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6675 return get_font_data( physdev->font, table, offset, buf, cbData );
6678 /*************************************************************
6679 * freetype_GetTextFace
6681 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6683 INT n;
6684 struct freetype_physdev *physdev = get_freetype_dev( dev );
6686 if (!physdev->font)
6688 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6689 return dev->funcs->pGetTextFace( dev, count, str );
6692 n = strlenW(physdev->font->name) + 1;
6693 if (str)
6695 lstrcpynW(str, physdev->font->name, count);
6696 n = min(count, n);
6698 return n;
6701 /*************************************************************
6702 * freetype_GetTextCharsetInfo
6704 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6706 struct freetype_physdev *physdev = get_freetype_dev( dev );
6708 if (!physdev->font)
6710 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6711 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6713 if (fs) *fs = physdev->font->fs;
6714 return physdev->font->charset;
6717 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6719 GdiFont *font = dc->gdiFont, *linked_font;
6720 struct list *first_hfont;
6721 BOOL ret;
6723 GDI_CheckNotLock();
6724 EnterCriticalSection( &freetype_cs );
6725 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6726 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6727 if(font == linked_font)
6728 *new_hfont = dc->hFont;
6729 else
6731 first_hfont = list_head(&linked_font->hfontlist);
6732 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6734 LeaveCriticalSection( &freetype_cs );
6735 return ret;
6738 /* Retrieve a list of supported Unicode ranges for a given font.
6739 * Can be called with NULL gs to calculate the buffer size. Returns
6740 * the number of ranges found.
6742 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6744 DWORD num_ranges = 0;
6746 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6748 FT_UInt glyph_code;
6749 FT_ULong char_code, char_code_prev;
6751 glyph_code = 0;
6752 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6754 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6755 face->num_glyphs, glyph_code, char_code);
6757 if (!glyph_code) return 0;
6759 if (gs)
6761 gs->ranges[0].wcLow = (USHORT)char_code;
6762 gs->ranges[0].cGlyphs = 0;
6763 gs->cGlyphsSupported = 0;
6766 num_ranges = 1;
6767 while (glyph_code)
6769 if (char_code < char_code_prev)
6771 ERR("expected increasing char code from FT_Get_Next_Char\n");
6772 return 0;
6774 if (char_code - char_code_prev > 1)
6776 num_ranges++;
6777 if (gs)
6779 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6780 gs->ranges[num_ranges - 1].cGlyphs = 1;
6781 gs->cGlyphsSupported++;
6784 else if (gs)
6786 gs->ranges[num_ranges - 1].cGlyphs++;
6787 gs->cGlyphsSupported++;
6789 char_code_prev = char_code;
6790 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6793 else
6794 FIXME("encoding %u not supported\n", face->charmap->encoding);
6796 return num_ranges;
6799 /*************************************************************
6800 * freetype_GetFontUnicodeRanges
6802 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6804 struct freetype_physdev *physdev = get_freetype_dev( dev );
6805 DWORD size, num_ranges;
6807 if (!physdev->font)
6809 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6810 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6813 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6814 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6815 if (glyphset)
6817 glyphset->cbThis = size;
6818 glyphset->cRanges = num_ranges;
6819 glyphset->flAccel = 0;
6821 return size;
6824 /*************************************************************
6825 * freetype_FontIsLinked
6827 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6829 struct freetype_physdev *physdev = get_freetype_dev( dev );
6830 BOOL ret;
6832 if (!physdev->font)
6834 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6835 return dev->funcs->pFontIsLinked( dev );
6838 GDI_CheckNotLock();
6839 EnterCriticalSection( &freetype_cs );
6840 ret = !list_empty(&physdev->font->child_fonts);
6841 LeaveCriticalSection( &freetype_cs );
6842 return ret;
6845 static BOOL is_hinting_enabled(void)
6847 /* Use the >= 2.2.0 function if available */
6848 if(pFT_Get_TrueType_Engine_Type)
6850 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6851 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6853 #ifdef FT_DRIVER_HAS_HINTER
6854 else
6856 FT_Module mod;
6858 /* otherwise if we've been compiled with < 2.2.0 headers
6859 use the internal macro */
6860 mod = pFT_Get_Module(library, "truetype");
6861 if(mod && FT_DRIVER_HAS_HINTER(mod))
6862 return TRUE;
6864 #endif
6866 return FALSE;
6869 static BOOL is_subpixel_rendering_enabled( void )
6871 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6872 return pFT_Library_SetLcdFilter &&
6873 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6874 #else
6875 return FALSE;
6876 #endif
6879 /*************************************************************************
6880 * GetRasterizerCaps (GDI32.@)
6882 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6884 static int hinting = -1;
6885 static int subpixel = -1;
6887 if(hinting == -1)
6889 hinting = is_hinting_enabled();
6890 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6893 if ( subpixel == -1 )
6895 subpixel = is_subpixel_rendering_enabled();
6896 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6899 lprs->nSize = sizeof(RASTERIZER_STATUS);
6900 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6901 if ( subpixel )
6902 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6903 lprs->nLanguageID = 0;
6904 return TRUE;
6907 /*************************************************************
6908 * freetype_GdiRealizationInfo
6910 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6912 struct freetype_physdev *physdev = get_freetype_dev( dev );
6913 realization_info_t *info = ptr;
6915 if (!physdev->font)
6917 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6918 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6921 FIXME("(%p, %p): stub!\n", physdev->font, info);
6923 info->flags = 1;
6924 if(FT_IS_SCALABLE(physdev->font->ft_face))
6925 info->flags |= 2;
6927 info->cache_num = physdev->font->cache_num;
6928 info->unknown2 = -1;
6929 return TRUE;
6932 /*************************************************************************
6933 * Kerning support for TrueType fonts
6935 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6937 struct TT_kern_table
6939 USHORT version;
6940 USHORT nTables;
6943 struct TT_kern_subtable
6945 USHORT version;
6946 USHORT length;
6947 union
6949 USHORT word;
6950 struct
6952 USHORT horizontal : 1;
6953 USHORT minimum : 1;
6954 USHORT cross_stream: 1;
6955 USHORT override : 1;
6956 USHORT reserved1 : 4;
6957 USHORT format : 8;
6958 } bits;
6959 } coverage;
6962 struct TT_format0_kern_subtable
6964 USHORT nPairs;
6965 USHORT searchRange;
6966 USHORT entrySelector;
6967 USHORT rangeShift;
6970 struct TT_kern_pair
6972 USHORT left;
6973 USHORT right;
6974 short value;
6977 static DWORD parse_format0_kern_subtable(GdiFont *font,
6978 const struct TT_format0_kern_subtable *tt_f0_ks,
6979 const USHORT *glyph_to_char,
6980 KERNINGPAIR *kern_pair, DWORD cPairs)
6982 USHORT i, nPairs;
6983 const struct TT_kern_pair *tt_kern_pair;
6985 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6987 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6989 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6990 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6991 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6993 if (!kern_pair || !cPairs)
6994 return nPairs;
6996 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6998 nPairs = min(nPairs, cPairs);
7000 for (i = 0; i < nPairs; i++)
7002 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7003 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7004 /* this algorithm appears to better match what Windows does */
7005 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7006 if (kern_pair->iKernAmount < 0)
7008 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7009 kern_pair->iKernAmount -= font->ppem;
7011 else if (kern_pair->iKernAmount > 0)
7013 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7014 kern_pair->iKernAmount += font->ppem;
7016 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7018 TRACE("left %u right %u value %d\n",
7019 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7021 kern_pair++;
7023 TRACE("copied %u entries\n", nPairs);
7024 return nPairs;
7027 /*************************************************************
7028 * freetype_GetKerningPairs
7030 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7032 DWORD length;
7033 void *buf;
7034 const struct TT_kern_table *tt_kern_table;
7035 const struct TT_kern_subtable *tt_kern_subtable;
7036 USHORT i, nTables;
7037 USHORT *glyph_to_char;
7038 GdiFont *font;
7039 struct freetype_physdev *physdev = get_freetype_dev( dev );
7041 if (!(font = physdev->font))
7043 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7044 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7047 GDI_CheckNotLock();
7048 EnterCriticalSection( &freetype_cs );
7049 if (font->total_kern_pairs != (DWORD)-1)
7051 if (cPairs && kern_pair)
7053 cPairs = min(cPairs, font->total_kern_pairs);
7054 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7056 else cPairs = font->total_kern_pairs;
7058 LeaveCriticalSection( &freetype_cs );
7059 return cPairs;
7062 font->total_kern_pairs = 0;
7064 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7066 if (length == GDI_ERROR)
7068 TRACE("no kerning data in the font\n");
7069 LeaveCriticalSection( &freetype_cs );
7070 return 0;
7073 buf = HeapAlloc(GetProcessHeap(), 0, length);
7074 if (!buf)
7076 WARN("Out of memory\n");
7077 LeaveCriticalSection( &freetype_cs );
7078 return 0;
7081 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7083 /* build a glyph index to char code map */
7084 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7085 if (!glyph_to_char)
7087 WARN("Out of memory allocating a glyph index to char code map\n");
7088 HeapFree(GetProcessHeap(), 0, buf);
7089 LeaveCriticalSection( &freetype_cs );
7090 return 0;
7093 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7095 FT_UInt glyph_code;
7096 FT_ULong char_code;
7098 glyph_code = 0;
7099 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7101 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7102 font->ft_face->num_glyphs, glyph_code, char_code);
7104 while (glyph_code)
7106 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7108 /* FIXME: This doesn't match what Windows does: it does some fancy
7109 * things with duplicate glyph index to char code mappings, while
7110 * we just avoid overriding existing entries.
7112 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7113 glyph_to_char[glyph_code] = (USHORT)char_code;
7115 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7118 else
7120 ULONG n;
7122 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7123 for (n = 0; n <= 65535; n++)
7124 glyph_to_char[n] = (USHORT)n;
7127 tt_kern_table = buf;
7128 nTables = GET_BE_WORD(tt_kern_table->nTables);
7129 TRACE("version %u, nTables %u\n",
7130 GET_BE_WORD(tt_kern_table->version), nTables);
7132 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7134 for (i = 0; i < nTables; i++)
7136 struct TT_kern_subtable tt_kern_subtable_copy;
7138 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7139 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7140 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7142 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7143 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7144 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7146 /* According to the TrueType specification this is the only format
7147 * that will be properly interpreted by Windows and OS/2
7149 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7151 DWORD new_chunk, old_total = font->total_kern_pairs;
7153 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7154 glyph_to_char, NULL, 0);
7155 font->total_kern_pairs += new_chunk;
7157 if (!font->kern_pairs)
7158 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7159 font->total_kern_pairs * sizeof(*font->kern_pairs));
7160 else
7161 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7162 font->total_kern_pairs * sizeof(*font->kern_pairs));
7164 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7165 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7167 else
7168 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7170 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7173 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7174 HeapFree(GetProcessHeap(), 0, buf);
7176 if (cPairs && kern_pair)
7178 cPairs = min(cPairs, font->total_kern_pairs);
7179 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7181 else cPairs = font->total_kern_pairs;
7183 LeaveCriticalSection( &freetype_cs );
7184 return cPairs;
7187 static const struct gdi_dc_funcs freetype_funcs =
7189 NULL, /* pAbortDoc */
7190 NULL, /* pAbortPath */
7191 NULL, /* pAlphaBlend */
7192 NULL, /* pAngleArc */
7193 NULL, /* pArc */
7194 NULL, /* pArcTo */
7195 NULL, /* pBeginPath */
7196 NULL, /* pBlendImage */
7197 NULL, /* pChoosePixelFormat */
7198 NULL, /* pChord */
7199 NULL, /* pCloseFigure */
7200 NULL, /* pCopyBitmap */
7201 NULL, /* pCreateBitmap */
7202 NULL, /* pCreateCompatibleDC */
7203 freetype_CreateDC, /* pCreateDC */
7204 NULL, /* pDeleteBitmap */
7205 freetype_DeleteDC, /* pDeleteDC */
7206 NULL, /* pDeleteObject */
7207 NULL, /* pDescribePixelFormat */
7208 NULL, /* pDeviceCapabilities */
7209 NULL, /* pEllipse */
7210 NULL, /* pEndDoc */
7211 NULL, /* pEndPage */
7212 NULL, /* pEndPath */
7213 freetype_EnumFonts, /* pEnumFonts */
7214 NULL, /* pEnumICMProfiles */
7215 NULL, /* pExcludeClipRect */
7216 NULL, /* pExtDeviceMode */
7217 NULL, /* pExtEscape */
7218 NULL, /* pExtFloodFill */
7219 NULL, /* pExtSelectClipRgn */
7220 NULL, /* pExtTextOut */
7221 NULL, /* pFillPath */
7222 NULL, /* pFillRgn */
7223 NULL, /* pFlattenPath */
7224 freetype_FontIsLinked, /* pFontIsLinked */
7225 NULL, /* pFrameRgn */
7226 NULL, /* pGdiComment */
7227 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7228 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7229 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7230 freetype_GetCharWidth, /* pGetCharWidth */
7231 NULL, /* pGetDeviceCaps */
7232 NULL, /* pGetDeviceGammaRamp */
7233 freetype_GetFontData, /* pGetFontData */
7234 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7235 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7236 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7237 NULL, /* pGetICMProfile */
7238 NULL, /* pGetImage */
7239 freetype_GetKerningPairs, /* pGetKerningPairs */
7240 NULL, /* pGetNearestColor */
7241 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7242 NULL, /* pGetPixel */
7243 NULL, /* pGetPixelFormat */
7244 NULL, /* pGetSystemPaletteEntries */
7245 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7246 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7247 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7248 freetype_GetTextFace, /* pGetTextFace */
7249 freetype_GetTextMetrics, /* pGetTextMetrics */
7250 NULL, /* pGradientFill */
7251 NULL, /* pIntersectClipRect */
7252 NULL, /* pInvertRgn */
7253 NULL, /* pLineTo */
7254 NULL, /* pModifyWorldTransform */
7255 NULL, /* pMoveTo */
7256 NULL, /* pOffsetClipRgn */
7257 NULL, /* pOffsetViewportOrg */
7258 NULL, /* pOffsetWindowOrg */
7259 NULL, /* pPaintRgn */
7260 NULL, /* pPatBlt */
7261 NULL, /* pPie */
7262 NULL, /* pPolyBezier */
7263 NULL, /* pPolyBezierTo */
7264 NULL, /* pPolyDraw */
7265 NULL, /* pPolyPolygon */
7266 NULL, /* pPolyPolyline */
7267 NULL, /* pPolygon */
7268 NULL, /* pPolyline */
7269 NULL, /* pPolylineTo */
7270 NULL, /* pPutImage */
7271 NULL, /* pRealizeDefaultPalette */
7272 NULL, /* pRealizePalette */
7273 NULL, /* pRectangle */
7274 NULL, /* pResetDC */
7275 NULL, /* pRestoreDC */
7276 NULL, /* pRoundRect */
7277 NULL, /* pSaveDC */
7278 NULL, /* pScaleViewportExt */
7279 NULL, /* pScaleWindowExt */
7280 NULL, /* pSelectBitmap */
7281 NULL, /* pSelectBrush */
7282 NULL, /* pSelectClipPath */
7283 freetype_SelectFont, /* pSelectFont */
7284 NULL, /* pSelectPalette */
7285 NULL, /* pSelectPen */
7286 NULL, /* pSetArcDirection */
7287 NULL, /* pSetBkColor */
7288 NULL, /* pSetBkMode */
7289 NULL, /* pSetDCBrushColor */
7290 NULL, /* pSetDCPenColor */
7291 NULL, /* pSetDIBColorTable */
7292 NULL, /* pSetDIBitsToDevice */
7293 NULL, /* pSetDeviceClipping */
7294 NULL, /* pSetDeviceGammaRamp */
7295 NULL, /* pSetLayout */
7296 NULL, /* pSetMapMode */
7297 NULL, /* pSetMapperFlags */
7298 NULL, /* pSetPixel */
7299 NULL, /* pSetPixelFormat */
7300 NULL, /* pSetPolyFillMode */
7301 NULL, /* pSetROP2 */
7302 NULL, /* pSetRelAbs */
7303 NULL, /* pSetStretchBltMode */
7304 NULL, /* pSetTextAlign */
7305 NULL, /* pSetTextCharacterExtra */
7306 NULL, /* pSetTextColor */
7307 NULL, /* pSetTextJustification */
7308 NULL, /* pSetViewportExt */
7309 NULL, /* pSetViewportOrg */
7310 NULL, /* pSetWindowExt */
7311 NULL, /* pSetWindowOrg */
7312 NULL, /* pSetWorldTransform */
7313 NULL, /* pStartDoc */
7314 NULL, /* pStartPage */
7315 NULL, /* pStretchBlt */
7316 NULL, /* pStretchDIBits */
7317 NULL, /* pStrokeAndFillPath */
7318 NULL, /* pStrokePath */
7319 NULL, /* pSwapBuffers */
7320 NULL, /* pUnrealizePalette */
7321 NULL, /* pWidenPath */
7322 /* OpenGL not supported */
7325 #else /* HAVE_FREETYPE */
7327 /*************************************************************************/
7329 BOOL WineEngInit(void)
7331 return FALSE;
7333 BOOL WineEngDestroyFontInstance(HFONT hfont)
7335 return FALSE;
7338 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7340 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7341 return 1;
7344 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7346 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7347 return TRUE;
7350 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7352 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7353 return NULL;
7356 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7358 return FALSE;
7361 /*************************************************************************
7362 * GetRasterizerCaps (GDI32.@)
7364 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7366 lprs->nSize = sizeof(RASTERIZER_STATUS);
7367 lprs->wFlags = 0;
7368 lprs->nLanguageID = 0;
7369 return TRUE;
7372 #endif /* HAVE_FREETYPE */