gdi32: Add a helper to retrieve the family pointer.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob1b38a8e542204a6f0fae879cae1b87ea6e45bb79
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 #include "resource.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FREETYPE
98 #ifdef HAVE_FT2BUILD_H
99 #include <ft2build.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
103 #endif
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
106 #endif
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
112 #endif
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
115 #endif
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
118 #endif
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
121 #endif
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
124 #endif
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
127 #endif
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
130 #endif
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
173 #else
174 MAKE_FUNCPTR(FT_MulFix);
175 #endif
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetString);
205 #endif
207 #undef MAKE_FUNCPTR
209 #ifndef FT_MAKE_TAG
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
213 #endif
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
217 #endif
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
220 #endif
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
223 #endif
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
226 #endif
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
230 #else
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
232 #endif
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
235 typedef struct {
236 FT_Short height;
237 FT_Short width;
238 FT_Pos size;
239 FT_Pos x_ppem;
240 FT_Pos y_ppem;
241 FT_Short internal_leading;
242 } Bitmap_Size;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
247 typedef struct {
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
250 } My_FT_Bitmap_Size;
252 struct enum_data
254 ENUMLOGFONTEXW elf;
255 NEWTEXTMETRICEXW ntm;
256 DWORD type;
259 typedef struct tagFace {
260 struct list entry;
261 WCHAR *StyleName;
262 WCHAR *FullName;
263 char *file;
264 void *font_data_ptr;
265 DWORD font_data_size;
266 FT_Long face_index;
267 FONTSIGNATURE fs;
268 DWORD ntmFlags;
269 FT_Fixed font_version;
270 BOOL scalable;
271 BOOL vertical;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
277 } Face;
279 typedef struct tagFamily {
280 struct list entry;
281 const WCHAR *FamilyName;
282 const WCHAR *EnglishName;
283 struct list faces;
284 struct list *replacement;
285 } Family;
287 typedef struct {
288 GLYPHMETRICS gm;
289 INT adv; /* These three hold to widths of the unrotated chars */
290 INT lsb;
291 INT bbx;
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct {
313 struct list entry;
314 Face *face;
315 GdiFont *font;
316 } CHILD_FONT;
318 struct tagGdiFont {
319 struct list entry;
320 GM **gm;
321 DWORD gmsize;
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
329 FT_Face ft_face;
330 struct font_mapping *mapping;
331 LPWSTR name;
332 int charset;
333 int codepage;
334 BOOL fake_italic;
335 BOOL fake_bold;
336 BYTE underline;
337 BYTE strikeout;
338 INT orientation;
339 FONT_DESC font_desc;
340 LONG aveWidth, ppem;
341 double scale_y;
342 SHORT yMax;
343 SHORT yMin;
344 DWORD ntmFlags;
345 FONTSIGNATURE fs;
346 GdiFont *base_font;
347 VOID *GSUB_Table;
348 DWORD cache_num;
351 typedef struct {
352 struct list entry;
353 const WCHAR *font_name;
354 FONTSIGNATURE fs;
355 struct list links;
356 } SYSTEM_LINKS;
358 struct enum_charset_element {
359 DWORD mask;
360 DWORD charset;
361 WCHAR name[LF_FACESIZE];
364 struct enum_charset_list {
365 DWORD total;
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 struct freetype_physdev
384 struct gdi_physdev dev;
385 GdiFont *font;
388 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
390 return (struct freetype_physdev *)dev;
393 static const struct gdi_dc_funcs freetype_funcs;
395 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR * const SystemFontValues[] = {
416 System_Value,
417 OEMFont_Value,
418 FixedSys_Value,
419 NULL
422 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
428 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
438 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
439 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR *default_serif_list[] =
448 times_new_roman,
449 liberation_serif,
450 bitstream_vera_serif,
451 NULL
454 static const WCHAR *default_fixed_list[] =
456 courier_new,
457 liberation_mono,
458 bitstream_vera_sans_mono,
459 NULL
462 static const WCHAR *default_sans_list[] =
464 arial,
465 liberation_sans,
466 bitstream_vera_sans,
467 NULL
470 typedef struct {
471 WCHAR *name;
472 INT charset;
473 } NameCs;
475 typedef struct tagFontSubst {
476 struct list entry;
477 NameCs from;
478 NameCs to;
479 } FontSubst;
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
487 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
488 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
489 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
491 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
501 struct font_mapping
503 struct list entry;
504 int refcount;
505 dev_t dev;
506 ino_t ino;
507 void *data;
508 size_t size;
511 static struct list mappings_list = LIST_INIT( mappings_list );
513 static CRITICAL_SECTION freetype_cs;
514 static CRITICAL_SECTION_DEBUG critsect_debug =
516 0, 0, &freetype_cs,
517 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
518 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback = FALSE;
527 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
528 static BOOL get_outline_text_metrics(GdiFont *font);
529 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
531 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
546 * Key Meaning
547 * FIXEDFON.FON FixedSys
548 * FONTS.FON System
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
562 * I have
563 * woafont=app850.fon
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
575 typedef struct {
576 DWORD version;
577 WORD ScriptList;
578 WORD FeatureList;
579 WORD LookupList;
580 } GSUB_Header;
582 typedef struct {
583 CHAR ScriptTag[4];
584 WORD Script;
585 } GSUB_ScriptRecord;
587 typedef struct {
588 WORD ScriptCount;
589 GSUB_ScriptRecord ScriptRecord[1];
590 } GSUB_ScriptList;
592 typedef struct {
593 CHAR LangSysTag[4];
594 WORD LangSys;
595 } GSUB_LangSysRecord;
597 typedef struct {
598 WORD DefaultLangSys;
599 WORD LangSysCount;
600 GSUB_LangSysRecord LangSysRecord[1];
601 } GSUB_Script;
603 typedef struct {
604 WORD LookupOrder; /* Reserved */
605 WORD ReqFeatureIndex;
606 WORD FeatureCount;
607 WORD FeatureIndex[1];
608 } GSUB_LangSys;
610 typedef struct {
611 CHAR FeatureTag[4];
612 WORD Feature;
613 } GSUB_FeatureRecord;
615 typedef struct {
616 WORD FeatureCount;
617 GSUB_FeatureRecord FeatureRecord[1];
618 } GSUB_FeatureList;
620 typedef struct {
621 WORD FeatureParams; /* Reserved */
622 WORD LookupCount;
623 WORD LookupListIndex[1];
624 } GSUB_Feature;
626 typedef struct {
627 WORD LookupCount;
628 WORD Lookup[1];
629 } GSUB_LookupList;
631 typedef struct {
632 WORD LookupType;
633 WORD LookupFlag;
634 WORD SubTableCount;
635 WORD SubTable[1];
636 } GSUB_LookupTable;
638 typedef struct {
639 WORD CoverageFormat;
640 WORD GlyphCount;
641 WORD GlyphArray[1];
642 } GSUB_CoverageFormat1;
644 typedef struct {
645 WORD Start;
646 WORD End;
647 WORD StartCoverageIndex;
648 } GSUB_RangeRecord;
650 typedef struct {
651 WORD CoverageFormat;
652 WORD RangeCount;
653 GSUB_RangeRecord RangeRecord[1];
654 } GSUB_CoverageFormat2;
656 typedef struct {
657 WORD SubstFormat; /* = 1 */
658 WORD Coverage;
659 WORD DeltaGlyphID;
660 } GSUB_SingleSubstFormat1;
662 typedef struct {
663 WORD SubstFormat; /* = 2 */
664 WORD Coverage;
665 WORD GlyphCount;
666 WORD Substitute[1];
667 }GSUB_SingleSubstFormat2;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
672 FSRef ref;
673 OSErr err;
674 static char cached_path[MAX_PATH];
675 static const char *wine = "/Wine", *fonts = "/Fonts";
677 if(*cached_path) return cached_path;
679 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
680 if(err != noErr)
682 WARN("can't create cached data folder\n");
683 return NULL;
685 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
686 if(err != noErr)
688 WARN("can't create cached data path\n");
689 *cached_path = '\0';
690 return NULL;
692 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
694 ERR("Could not create full path\n");
695 *cached_path = '\0';
696 return NULL;
698 strcat(cached_path, wine);
700 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
702 WARN("Couldn't mkdir %s\n", cached_path);
703 *cached_path = '\0';
704 return NULL;
706 strcat(cached_path, fonts);
707 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
709 WARN("Couldn't mkdir %s\n", cached_path);
710 *cached_path = '\0';
711 return NULL;
713 return cached_path;
716 /******************************************************************
717 * expand_mac_font
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
721 * find_cache_dir()).
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path)
729 FSRef ref;
730 SInt16 res_ref;
731 OSStatus s;
732 unsigned int idx;
733 const char *out_dir;
734 const char *filename;
735 int output_len;
736 struct {
737 char **array;
738 unsigned int size, max_size;
739 } ret;
741 TRACE("path %s\n", path);
743 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
744 if(s != noErr)
746 WARN("failed to get ref\n");
747 return NULL;
750 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
751 if(s != noErr)
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref = FSOpenResFile(&ref, fsRdPerm);
755 if(res_ref == -1)
757 TRACE("unable to open resource fork\n");
758 return NULL;
762 ret.size = 0;
763 ret.max_size = 10;
764 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
765 if(!ret.array)
767 CloseResFile(res_ref);
768 return NULL;
771 out_dir = find_cache_dir();
773 filename = strrchr(path, '/');
774 if(!filename) filename = path;
775 else filename++;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
780 UseResFile(res_ref);
781 idx = 1;
782 while(1)
784 FamRec *fam_rec;
785 unsigned short *num_faces_ptr, num_faces, face;
786 AsscEntry *assoc;
787 Handle fond;
788 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
790 fond = Get1IndResource(fond_res, idx);
791 if(!fond) break;
792 TRACE("got fond resource %d\n", idx);
793 HLock(fond);
795 fam_rec = *(FamRec**)fond;
796 num_faces_ptr = (unsigned short *)(fam_rec + 1);
797 num_faces = GET_BE_WORD(*num_faces_ptr);
798 num_faces++;
799 assoc = (AsscEntry*)(num_faces_ptr + 1);
800 TRACE("num faces %04x\n", num_faces);
801 for(face = 0; face < num_faces; face++, assoc++)
803 Handle sfnt;
804 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
805 unsigned short size, font_id;
806 char *output;
808 size = GET_BE_WORD(assoc->fontSize);
809 font_id = GET_BE_WORD(assoc->fontID);
810 if(size != 0)
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
813 continue;
816 TRACE("trying to load sfnt id %04x\n", font_id);
817 sfnt = GetResource(sfnt_res, font_id);
818 if(!sfnt)
820 TRACE("can't get sfnt resource %04x\n", font_id);
821 continue;
824 output = HeapAlloc(GetProcessHeap(), 0, output_len);
825 if(output)
827 int fd;
829 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
831 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
832 if(fd != -1 || errno == EEXIST)
834 if(fd != -1)
836 unsigned char *sfnt_data;
838 HLock(sfnt);
839 sfnt_data = *(unsigned char**)sfnt;
840 write(fd, sfnt_data, GetHandleSize(sfnt));
841 HUnlock(sfnt);
842 close(fd);
844 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
846 ret.max_size *= 2;
847 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
849 ret.array[ret.size++] = output;
851 else
853 WARN("unable to create %s\n", output);
854 HeapFree(GetProcessHeap(), 0, output);
857 ReleaseResource(sfnt);
859 HUnlock(fond);
860 ReleaseResource(fond);
861 idx++;
863 CloseResFile(res_ref);
865 return ret.array;
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed FT_FixedFromFloat(double f)
880 return f * 0x10000;
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
889 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
893 static const struct list *get_face_list_from_family(const Family *family)
895 if (!list_empty(&family->faces))
896 return &family->faces;
897 else
898 return family->replacement;
901 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
903 Family *family;
904 Face *face;
905 const char *file;
906 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
907 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
909 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
912 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
914 const struct list *face_list;
915 if(face_name && strcmpiW(face_name, family->FamilyName))
916 continue;
917 face_list = get_face_list_from_family(family);
918 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
920 if (!face->file)
921 continue;
922 file = strrchr(face->file, '/');
923 if(!file)
924 file = face->file;
925 else
926 file++;
927 if(!strcasecmp(file, file_nameA))
929 HeapFree(GetProcessHeap(), 0, file_nameA);
930 return face;
934 HeapFree(GetProcessHeap(), 0, file_nameA);
935 return NULL;
938 static Family *find_family_from_name(const WCHAR *name)
940 Family *family;
942 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
944 if(!strcmpiW(family->FamilyName, name))
945 return family;
948 return NULL;
951 static Family *find_family_from_any_name(const WCHAR *name)
953 Family *family;
955 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
957 if(!strcmpiW(family->FamilyName, name))
958 return family;
959 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
960 return family;
963 return NULL;
966 static void DumpSubstList(void)
968 FontSubst *psub;
970 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
972 if(psub->from.charset != -1 || psub->to.charset != -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
974 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
975 else
976 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
977 debugstr_w(psub->to.name));
979 return;
982 static LPWSTR strdupW(LPCWSTR p)
984 LPWSTR ret;
985 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
986 ret = HeapAlloc(GetProcessHeap(), 0, len);
987 memcpy(ret, p, len);
988 return ret;
991 static LPSTR strdupA(LPCSTR p)
993 LPSTR ret;
994 DWORD len = (strlen(p) + 1);
995 ret = HeapAlloc(GetProcessHeap(), 0, len);
996 memcpy(ret, p, len);
997 return ret;
1000 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1001 INT from_charset)
1003 FontSubst *element;
1005 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1007 if(!strcmpiW(element->from.name, from_name) &&
1008 (element->from.charset == from_charset ||
1009 element->from.charset == -1))
1010 return element;
1013 return NULL;
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1020 FontSubst *from_exist, *to_exist;
1022 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1024 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1026 list_remove(&from_exist->entry);
1027 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1028 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1029 HeapFree(GetProcessHeap(), 0, from_exist);
1030 from_exist = NULL;
1033 if(!from_exist)
1035 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1037 if(to_exist)
1039 HeapFree(GetProcessHeap(), 0, subst->to.name);
1040 subst->to.name = strdupW(to_exist->to.name);
1043 list_add_tail(subst_list, &subst->entry);
1045 return TRUE;
1048 HeapFree(GetProcessHeap(), 0, subst->from.name);
1049 HeapFree(GetProcessHeap(), 0, subst->to.name);
1050 HeapFree(GetProcessHeap(), 0, subst);
1051 return FALSE;
1054 static WCHAR *towstr(UINT cp, const char *str)
1056 int len;
1057 WCHAR *wstr;
1059 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1060 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1061 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1062 return wstr;
1065 static void split_subst_info(NameCs *nc, LPSTR str)
1067 CHAR *p = strrchr(str, ',');
1069 nc->charset = -1;
1070 if(p && *(p+1)) {
1071 nc->charset = strtol(p+1, NULL, 10);
1072 *p = '\0';
1074 nc->name = towstr(CP_ACP, str);
1077 static void LoadSubstList(void)
1079 FontSubst *psub;
1080 HKEY hkey;
1081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1082 LPSTR value;
1083 LPVOID data;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey) == ERROR_SUCCESS) {
1089 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1090 &valuelen, &datalen, NULL, NULL);
1092 valuelen++; /* returned value doesn't include room for '\0' */
1093 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1094 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1096 dlen = datalen;
1097 vlen = valuelen;
1098 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1099 &dlen) == ERROR_SUCCESS) {
1100 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1102 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1103 split_subst_info(&psub->from, value);
1104 split_subst_info(&psub->to, data);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1109 psub->to.charset == DEFAULT_CHARSET) {
1110 HeapFree(GetProcessHeap(), 0, psub->to.name);
1111 HeapFree(GetProcessHeap(), 0, psub->from.name);
1112 HeapFree(GetProcessHeap(), 0, psub);
1113 } else {
1114 add_font_subst(&font_subst_list, psub, 0);
1116 /* reset dlen and vlen */
1117 dlen = datalen;
1118 vlen = valuelen;
1120 HeapFree(GetProcessHeap(), 0, data);
1121 HeapFree(GetProcessHeap(), 0, value);
1122 RegCloseKey(hkey);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1137 FT_SfntName name;
1138 FT_UInt num_names, name_index;
1140 if(FT_IS_SFNT(ft_face))
1142 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1144 for(name_index = 0; name_index < num_names; name_index++)
1146 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1148 if((name.platform_id == req->platform_id) &&
1149 (name.encoding_id == req->encoding_id) &&
1150 (name.language_id == req->language_id) &&
1151 (name.name_id == req->name_id))
1153 req->string = name.string;
1154 req->string_len = name.string_len;
1155 return TRUE;
1160 req->string = NULL;
1161 req->string_len = 0;
1162 return FALSE;
1165 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1167 WCHAR *ret = NULL;
1168 FT_SfntName name;
1170 name.platform_id = TT_PLATFORM_MICROSOFT;
1171 name.encoding_id = TT_MS_ID_UNICODE_CS;
1172 name.language_id = language_id;
1173 name.name_id = name_id;
1175 if(get_name_table_entry(ft_face, &name))
1177 FT_UInt i;
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1181 for(i = 0; i < name.string_len / 2; i++)
1183 WORD *tmp = (WORD *)&name.string[i * 2];
1184 ret[i] = GET_BE_WORD(*tmp);
1186 ret[i] = 0;
1187 TRACE("Got localised name %s\n", debugstr_w(ret));
1190 return ret;
1193 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1195 DWORD type, needed;
1196 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1197 if(r != ERROR_SUCCESS) return r;
1198 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1199 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1202 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1204 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1207 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1209 DWORD needed;
1210 DWORD num_strikes, max_strike_key_len;
1212 /* If we have a File Name key then this is a real font, not just the parent
1213 key of a bunch of non-scalable strikes */
1214 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1216 DWORD italic, bold;
1217 Face *face;
1218 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1219 face->cached_enum_data = NULL;
1221 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1222 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1224 face->StyleName = strdupW(face_name);
1225 face->family = family;
1226 face->vertical = (family->FamilyName[0] == '@');
1228 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1230 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1231 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1232 face->FullName = fullName;
1234 else
1235 face->FullName = NULL;
1237 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1238 reg_load_dword(hkey_face, face_italic_value, &italic);
1239 reg_load_dword(hkey_face, face_bold_value, &bold);
1240 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1241 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1243 needed = sizeof(face->fs);
1244 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1246 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1248 face->scalable = TRUE;
1249 memset(&face->size, 0, sizeof(face->size));
1251 else
1253 face->scalable = FALSE;
1254 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1255 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1256 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1257 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1258 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1260 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1261 face->size.height, face->size.width, face->size.size >> 6,
1262 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1265 face->ntmFlags = 0;
1266 if (italic) face->ntmFlags |= NTM_ITALIC;
1267 if (bold) face->ntmFlags |= NTM_BOLD;
1268 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1270 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1271 face->fs.fsCsb[0], face->fs.fsCsb[1],
1272 face->fs.fsUsb[0], face->fs.fsUsb[1],
1273 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1275 if(!italic && !bold)
1276 list_add_head(&family->faces, &face->entry);
1277 else
1278 list_add_tail(&family->faces, &face->entry);
1280 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1283 /* do we have any bitmap strikes? */
1284 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1285 NULL, NULL, NULL, NULL);
1286 if(num_strikes != 0)
1288 WCHAR strike_name[10];
1289 DWORD strike_index = 0;
1291 needed = sizeof(strike_name) / sizeof(WCHAR);
1292 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1293 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1295 HKEY hkey_strike;
1296 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1297 load_face(hkey_strike, face_name, family);
1298 RegCloseKey(hkey_strike);
1299 needed = sizeof(strike_name) / sizeof(WCHAR);
1304 static void load_font_list_from_cache(HKEY hkey_font_cache)
1306 DWORD max_family_key_len, size;
1307 WCHAR *family_name;
1308 DWORD family_index = 0;
1309 Family *family;
1310 HKEY hkey_family;
1312 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1313 NULL, NULL, NULL, NULL);
1314 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1316 size = max_family_key_len + 1;
1317 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1318 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1320 WCHAR *english_family = NULL;
1321 DWORD face_index = 0;
1322 WCHAR *face_name;
1323 DWORD max_face_key_len;
1325 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1326 TRACE("opened family key %s\n", debugstr_w(family_name));
1327 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1329 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1330 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1333 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1334 family->FamilyName = strdupW(family_name);
1335 family->EnglishName = english_family;
1336 list_init(&family->faces);
1337 family->replacement = &family->faces;
1338 list_add_tail(&font_list, &family->entry);
1340 if(english_family)
1342 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1343 subst->from.name = strdupW(english_family);
1344 subst->from.charset = -1;
1345 subst->to.name = strdupW(family_name);
1346 subst->to.charset = -1;
1347 add_font_subst(&font_subst_list, subst, 0);
1350 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1351 NULL, NULL, NULL, NULL);
1353 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1354 size = max_face_key_len + 1;
1355 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1356 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1358 HKEY hkey_face;
1360 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1361 load_face(hkey_face, face_name, family);
1362 RegCloseKey(hkey_face);
1363 size = max_face_key_len + 1;
1365 HeapFree(GetProcessHeap(), 0, face_name);
1366 RegCloseKey(hkey_family);
1367 size = max_family_key_len + 1;
1370 HeapFree(GetProcessHeap(), 0, family_name);
1373 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1375 LONG ret;
1376 HKEY hkey_wine_fonts;
1378 /* We don't want to create the fonts key as volatile, so open this first */
1379 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1380 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1381 if(ret != ERROR_SUCCESS)
1383 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1384 return ret;
1387 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1388 KEY_ALL_ACCESS, NULL, hkey, disposition);
1389 RegCloseKey(hkey_wine_fonts);
1390 return ret;
1393 static void add_face_to_cache(Face *face)
1395 HKEY hkey_font_cache, hkey_family, hkey_face;
1396 WCHAR *face_key_name;
1398 create_font_cache_key(&hkey_font_cache, NULL);
1400 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1401 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1402 if(face->family->EnglishName)
1403 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1404 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1406 if(face->scalable)
1407 face_key_name = face->StyleName;
1408 else
1410 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1411 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1412 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1414 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1415 &hkey_face, NULL);
1416 if(!face->scalable)
1417 HeapFree(GetProcessHeap(), 0, face_key_name);
1419 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1420 if (face->FullName)
1421 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1422 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1424 reg_save_dword(hkey_face, face_index_value, face->face_index);
1425 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1426 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1427 reg_save_dword(hkey_face, face_version_value, face->font_version);
1428 reg_save_dword(hkey_face, face_external_value, face->external);
1430 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1432 if(!face->scalable)
1434 reg_save_dword(hkey_face, face_height_value, face->size.height);
1435 reg_save_dword(hkey_face, face_width_value, face->size.width);
1436 reg_save_dword(hkey_face, face_size_value, face->size.size);
1437 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1438 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1439 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1441 RegCloseKey(hkey_face);
1442 RegCloseKey(hkey_family);
1443 RegCloseKey(hkey_font_cache);
1446 static inline int TestStyles(DWORD flags, DWORD styles)
1448 return (flags & styles) == styles;
1451 static int StyleOrdering(Face *face)
1453 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1454 return 3;
1455 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1456 return 2;
1457 if (TestStyles(face->ntmFlags, NTM_BOLD))
1458 return 1;
1459 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1460 return 0;
1462 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1463 debugstr_w(face->family->FamilyName),
1464 debugstr_w(face->StyleName),
1465 face->ntmFlags);
1467 return 9999;
1470 /* Add a style of face to a font family using an ordering of the list such
1471 that regular fonts come before bold and italic, and single styles come
1472 before compound styles. */
1473 static void AddFaceToFamily(Face *face, Family *family)
1475 struct list *entry;
1477 LIST_FOR_EACH( entry, &family->faces )
1479 Face *ent = LIST_ENTRY(entry, Face, entry);
1480 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1482 list_add_before( entry, &face->entry );
1485 static WCHAR *prepend_at(WCHAR *family)
1487 WCHAR *str;
1489 if (!family)
1490 return NULL;
1492 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1493 str[0] = '@';
1494 strcpyW(str + 1, family);
1495 HeapFree(GetProcessHeap(), 0, family);
1496 return str;
1499 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1501 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1502 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1504 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1505 if (!*name)
1507 *name = *english;
1508 *english = NULL;
1510 else if (!strcmpiW( *name, *english ))
1512 HeapFree( GetProcessHeap(), 0, *english );
1513 *english = NULL;
1516 if (vertical)
1518 *name = prepend_at( *name );
1519 *english = prepend_at( *english );
1523 static Family *get_family( FT_Face ft_face, BOOL vertical )
1525 Family *family;
1526 WCHAR *name, *english_name;
1528 get_family_names( ft_face, &name, &english_name, vertical );
1530 family = find_family_from_name( name );
1532 if (!family)
1534 family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1535 family->FamilyName = strdupW( name );
1536 family->EnglishName = english_name ? strdupW( english_name ) : NULL;
1537 list_init( &family->faces );
1538 family->replacement = &family->faces;
1539 list_add_tail( &font_list, &family->entry );
1541 if (english_name)
1543 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1544 subst->from.name = strdupW( english_name );
1545 subst->from.charset = -1;
1546 subst->to.name = strdupW( name );
1547 subst->to.charset = -1;
1548 add_font_subst( &font_subst_list, subst, 0 );
1551 HeapFree( GetProcessHeap(), 0, name );
1552 HeapFree( GetProcessHeap(), 0, english_name );
1554 return family;
1558 #define ADDFONT_EXTERNAL_FONT 0x01
1559 #define ADDFONT_FORCE_BITMAP 0x02
1560 #define ADDFONT_ADD_TO_CACHE 0x04
1562 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size, FT_Long face_index, DWORD flags, BOOL vertical)
1564 int bitmap_num = 0;
1565 Family *family;
1566 WCHAR *StyleW;
1568 do {
1569 TT_OS2 *pOS2;
1570 TT_Header *pHeader;
1571 Face *face;
1572 struct list *face_elem_ptr;
1573 FT_WinFNT_HeaderRec winfnt_header;
1574 int internal_leading;
1575 FONTSIGNATURE fs;
1576 My_FT_Bitmap_Size *size = NULL;
1577 FT_ULong tmp_size;
1579 if(!FT_IS_SCALABLE(ft_face))
1580 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1582 family = get_family( ft_face, vertical );
1584 StyleW = towstr(CP_ACP, ft_face->style_name);
1586 internal_leading = 0;
1587 memset(&fs, 0, sizeof(fs));
1589 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1590 if(pOS2) {
1591 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1592 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1593 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1594 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1595 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1596 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1597 if(pOS2->version == 0) {
1598 FT_UInt dummy;
1600 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1601 fs.fsCsb[0] |= FS_LATIN1;
1602 else
1603 fs.fsCsb[0] |= FS_SYMBOL;
1606 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1607 CHARSETINFO csi;
1608 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1609 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1610 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1611 fs = csi.fs;
1612 internal_leading = winfnt_header.internal_leading;
1615 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1616 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1617 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1618 if(!strcmpiW(face->StyleName, StyleW) &&
1619 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1620 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1621 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1622 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1624 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1625 TRACE("Original font is newer so skipping this one\n");
1626 HeapFree(GetProcessHeap(), 0, StyleW);
1627 return;
1628 } else {
1629 TRACE("Replacing original with this one\n");
1630 list_remove(&face->entry);
1631 HeapFree(GetProcessHeap(), 0, face->file);
1632 HeapFree(GetProcessHeap(), 0, face->StyleName);
1633 HeapFree(GetProcessHeap(), 0, face->FullName);
1634 HeapFree(GetProcessHeap(), 0, face);
1635 break;
1639 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1640 face->cached_enum_data = NULL;
1641 face->StyleName = StyleW;
1642 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1643 if (file)
1645 face->file = strdupA(file);
1646 face->font_data_ptr = NULL;
1647 face->font_data_size = 0;
1649 else
1651 face->file = NULL;
1652 face->font_data_ptr = font_data_ptr;
1653 face->font_data_size = font_data_size;
1655 face->face_index = face_index;
1656 face->ntmFlags = 0;
1657 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1658 face->ntmFlags |= NTM_ITALIC;
1659 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1660 face->ntmFlags |= NTM_BOLD;
1661 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1662 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1663 face->family = family;
1664 face->vertical = vertical;
1665 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1666 face->fs = fs;
1668 if(FT_IS_SCALABLE(ft_face)) {
1669 memset(&face->size, 0, sizeof(face->size));
1670 face->scalable = TRUE;
1671 } else {
1672 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1673 size->height, size->width, size->size >> 6,
1674 size->x_ppem >> 6, size->y_ppem >> 6);
1675 face->size.height = size->height;
1676 face->size.width = size->width;
1677 face->size.size = size->size;
1678 face->size.x_ppem = size->x_ppem;
1679 face->size.y_ppem = size->y_ppem;
1680 face->size.internal_leading = internal_leading;
1681 face->scalable = FALSE;
1684 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1685 tmp_size = 0;
1686 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1688 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1689 face->ntmFlags |= NTM_PS_OPENTYPE;
1692 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1693 face->fs.fsCsb[0], face->fs.fsCsb[1],
1694 face->fs.fsUsb[0], face->fs.fsUsb[1],
1695 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1697 if(face->fs.fsCsb[0] == 0)
1699 int i;
1701 /* let's see if we can find any interesting cmaps */
1702 for(i = 0; i < ft_face->num_charmaps; i++) {
1703 switch(ft_face->charmaps[i]->encoding) {
1704 case FT_ENCODING_UNICODE:
1705 case FT_ENCODING_APPLE_ROMAN:
1706 face->fs.fsCsb[0] |= FS_LATIN1;
1707 break;
1708 case FT_ENCODING_MS_SYMBOL:
1709 face->fs.fsCsb[0] |= FS_SYMBOL;
1710 break;
1711 default:
1712 break;
1717 if(flags & ADDFONT_ADD_TO_CACHE)
1718 add_face_to_cache(face);
1720 AddFaceToFamily(face, family);
1722 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1724 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1725 debugstr_w(StyleW));
1728 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1730 FT_Face ft_face;
1731 TT_OS2 *pOS2;
1732 FT_Error err;
1733 FT_Long face_index = 0, num_faces;
1734 INT ret = 0;
1736 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1737 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1739 #ifdef HAVE_CARBON_CARBON_H
1740 if(file)
1742 char **mac_list = expand_mac_font(file);
1743 if(mac_list)
1745 BOOL had_one = FALSE;
1746 char **cursor;
1747 for(cursor = mac_list; *cursor; cursor++)
1749 had_one = TRUE;
1750 AddFontToList(*cursor, NULL, 0, flags);
1751 HeapFree(GetProcessHeap(), 0, *cursor);
1753 HeapFree(GetProcessHeap(), 0, mac_list);
1754 if(had_one)
1755 return 1;
1758 #endif /* HAVE_CARBON_CARBON_H */
1760 do {
1761 if (file)
1763 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1764 err = pFT_New_Face(library, file, face_index, &ft_face);
1765 } else
1767 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1768 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1771 if(err != 0) {
1772 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1773 return 0;
1776 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*/
1777 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1778 pFT_Done_Face(ft_face);
1779 return 0;
1782 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1783 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1784 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1785 pFT_Done_Face(ft_face);
1786 return 0;
1789 if(FT_IS_SFNT(ft_face))
1791 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1792 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1793 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))
1795 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1796 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1797 pFT_Done_Face(ft_face);
1798 return 0;
1801 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1802 we don't want to load these. */
1803 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1805 FT_ULong len = 0;
1807 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1809 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1810 pFT_Done_Face(ft_face);
1811 return 0;
1816 if(!ft_face->family_name || !ft_face->style_name) {
1817 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1818 pFT_Done_Face(ft_face);
1819 return 0;
1822 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1824 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1825 pFT_Done_Face(ft_face);
1826 return 0;
1829 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1830 ++ret;
1832 if (FT_HAS_VERTICAL(ft_face))
1834 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1835 ++ret;
1838 num_faces = ft_face->num_faces;
1839 pFT_Done_Face(ft_face);
1840 } while(num_faces > ++face_index);
1841 return ret;
1844 static void DumpFontList(void)
1846 Family *family;
1847 Face *face;
1848 struct list *family_elem_ptr, *face_elem_ptr;
1850 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1851 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1852 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1853 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1854 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1855 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1856 if(!face->scalable)
1857 TRACE(" %d", face->size.height);
1858 TRACE("\n");
1861 return;
1864 /***********************************************************
1865 * The replacement list is a way to map an entire font
1866 * family onto another family. For example adding
1868 * [HKCU\Software\Wine\Fonts\Replacements]
1869 * "Wingdings"="Winedings"
1871 * would enumerate the Winedings font both as Winedings and
1872 * Wingdings. However if a real Wingdings font is present the
1873 * replacement does not take place.
1876 static void LoadReplaceList(void)
1878 HKEY hkey;
1879 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1880 LPWSTR value;
1881 LPVOID data;
1882 CHAR familyA[400];
1884 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1885 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1887 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1888 &valuelen, &datalen, NULL, NULL);
1890 valuelen++; /* returned value doesn't include room for '\0' */
1891 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1892 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1894 dlen = datalen;
1895 vlen = valuelen;
1896 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1897 &dlen) == ERROR_SUCCESS) {
1898 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1899 /* "NewName"="Oldname" */
1900 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1902 if(!find_family_from_any_name(value))
1904 Family * const family = find_family_from_any_name(data);
1905 if (family != NULL)
1907 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1908 if (new_family != NULL)
1910 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1911 new_family->FamilyName = strdupW(value);
1912 new_family->EnglishName = NULL;
1913 list_init(&new_family->faces);
1914 new_family->replacement = &family->faces;
1915 list_add_tail(&font_list, &new_family->entry);
1918 else
1920 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1923 else
1925 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1927 /* reset dlen and vlen */
1928 dlen = datalen;
1929 vlen = valuelen;
1931 HeapFree(GetProcessHeap(), 0, data);
1932 HeapFree(GetProcessHeap(), 0, value);
1933 RegCloseKey(hkey);
1937 static const WCHAR *font_links_list[] =
1939 Lucida_Sans_Unicode,
1940 Microsoft_Sans_Serif,
1941 Tahoma
1944 static const struct font_links_defaults_list
1946 /* Keyed off substitution for "MS Shell Dlg" */
1947 const WCHAR *shelldlg;
1948 /* Maximum of four substitutes, plus terminating NULL pointer */
1949 const WCHAR *substitutes[5];
1950 } font_links_defaults_list[] =
1952 /* Non East-Asian */
1953 { Tahoma, /* FIXME unverified ordering */
1954 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
1956 /* Below lists are courtesy of
1957 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1959 /* Japanese */
1960 { MS_UI_Gothic,
1961 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
1963 /* Chinese Simplified */
1964 { SimSun,
1965 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
1967 /* Korean */
1968 { Gulim,
1969 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
1971 /* Chinese Traditional */
1972 { PMingLiU,
1973 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
1978 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
1980 SYSTEM_LINKS *font_link;
1982 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1984 if(!strcmpiW(font_link->font_name, name))
1985 return font_link;
1988 return NULL;
1991 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
1993 const WCHAR *value;
1994 int i;
1995 FontSubst *psub;
1996 Family *family;
1997 Face *face;
1998 const char *file;
1999 WCHAR *fileW;
2001 if (values)
2003 SYSTEM_LINKS *font_link;
2005 psub = get_font_subst(&font_subst_list, name, -1);
2006 /* Don't store fonts that are only substitutes for other fonts */
2007 if(psub)
2009 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2010 return;
2013 font_link = find_font_link(name);
2014 if (font_link == NULL)
2016 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2017 font_link->font_name = strdupW(name);
2018 list_init(&font_link->links);
2019 list_add_tail(&system_links, &font_link->entry);
2022 memset(&font_link->fs, 0, sizeof font_link->fs);
2023 for (i = 0; values[i] != NULL; i++)
2025 const struct list *face_list;
2026 CHILD_FONT *child_font;
2028 value = values[i];
2029 if (!strcmpiW(name,value))
2030 continue;
2031 psub = get_font_subst(&font_subst_list, value, -1);
2032 if(psub)
2033 value = psub->to.name;
2034 family = find_family_from_name(value);
2035 if (!family)
2036 continue;
2037 file = NULL;
2038 /* Use first extant filename for this Family */
2039 face_list = get_face_list_from_family(family);
2040 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2042 if (!face->file)
2043 continue;
2044 file = strrchr(face->file, '/');
2045 if (!file)
2046 file = face->file;
2047 else
2048 file++;
2049 break;
2051 if (!file)
2052 continue;
2053 fileW = towstr(CP_UNIXCP, file);
2055 face = find_face_from_filename(fileW, value);
2056 if(!face)
2058 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2059 continue;
2062 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2063 child_font->face = face;
2064 child_font->font = NULL;
2065 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2066 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2067 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2068 list_add_tail(&font_link->links, &child_font->entry);
2070 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2071 HeapFree(GetProcessHeap(), 0, fileW);
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 Face *face;
2093 FontSubst *psub;
2094 UINT i, j;
2096 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2098 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2099 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2100 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2101 val_len = max_val + 1;
2102 data_len = max_data;
2103 index = 0;
2104 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2106 psub = get_font_subst(&font_subst_list, value, -1);
2107 /* Don't store fonts that are only substitutes for other fonts */
2108 if(psub)
2110 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2111 goto next;
2113 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2114 font_link->font_name = strdupW(value);
2115 memset(&font_link->fs, 0, sizeof font_link->fs);
2116 list_init(&font_link->links);
2117 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2119 WCHAR *face_name;
2120 CHILD_FONT *child_font;
2122 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2124 next = entry + strlenW(entry) + 1;
2126 face_name = strchrW(entry, ',');
2127 if(face_name)
2129 *face_name++ = 0;
2130 while(isspaceW(*face_name))
2131 face_name++;
2133 psub = get_font_subst(&font_subst_list, face_name, -1);
2134 if(psub)
2135 face_name = psub->to.name;
2137 face = find_face_from_filename(entry, face_name);
2138 if(!face)
2140 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2141 continue;
2144 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2145 child_font->face = face;
2146 child_font->font = NULL;
2147 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2148 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2149 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2150 list_add_tail(&font_link->links, &child_font->entry);
2152 list_add_tail(&system_links, &font_link->entry);
2153 next:
2154 val_len = max_val + 1;
2155 data_len = max_data;
2158 HeapFree(GetProcessHeap(), 0, value);
2159 HeapFree(GetProcessHeap(), 0, data);
2160 RegCloseKey(hkey);
2164 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2165 if (!psub) {
2166 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2167 goto skip_internal;
2170 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2172 const FontSubst *psub2;
2173 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2175 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2177 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2178 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2180 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2181 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2183 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2185 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2189 skip_internal:
2191 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2192 that Tahoma has */
2194 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2195 system_font_link->font_name = strdupW(System);
2196 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2197 list_init(&system_font_link->links);
2199 face = find_face_from_filename(tahoma_ttf, Tahoma);
2200 if(face)
2202 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2203 child_font->face = face;
2204 child_font->font = NULL;
2205 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2206 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2207 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2208 list_add_tail(&system_font_link->links, &child_font->entry);
2210 font_link = find_font_link(Tahoma);
2211 if (font_link != NULL)
2213 CHILD_FONT *font_link_entry;
2214 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2216 CHILD_FONT *new_child;
2217 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2218 new_child->face = font_link_entry->face;
2219 new_child->font = NULL;
2220 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2221 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2222 list_add_tail(&system_font_link->links, &new_child->entry);
2225 list_add_tail(&system_links, &system_font_link->entry);
2226 return ret;
2229 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2231 DIR *dir;
2232 struct dirent *dent;
2233 char path[MAX_PATH];
2235 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2237 dir = opendir(dirname);
2238 if(!dir) {
2239 WARN("Can't open directory %s\n", debugstr_a(dirname));
2240 return FALSE;
2242 while((dent = readdir(dir)) != NULL) {
2243 struct stat statbuf;
2245 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2246 continue;
2248 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2250 sprintf(path, "%s/%s", dirname, dent->d_name);
2252 if(stat(path, &statbuf) == -1)
2254 WARN("Can't stat %s\n", debugstr_a(path));
2255 continue;
2257 if(S_ISDIR(statbuf.st_mode))
2258 ReadFontDir(path, external_fonts);
2259 else
2261 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2262 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2263 AddFontToList(path, NULL, 0, addfont_flags);
2266 closedir(dir);
2267 return TRUE;
2270 static void load_fontconfig_fonts(void)
2272 #ifdef SONAME_LIBFONTCONFIG
2273 void *fc_handle = NULL;
2274 FcConfig *config;
2275 FcPattern *pat;
2276 FcObjectSet *os;
2277 FcFontSet *fontset;
2278 int i, len;
2279 char *file;
2280 const char *ext;
2282 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2283 if(!fc_handle) {
2284 TRACE("Wine cannot find the fontconfig library (%s).\n",
2285 SONAME_LIBFONTCONFIG);
2286 return;
2288 #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;}
2289 LOAD_FUNCPTR(FcConfigGetCurrent);
2290 LOAD_FUNCPTR(FcFontList);
2291 LOAD_FUNCPTR(FcFontSetDestroy);
2292 LOAD_FUNCPTR(FcInit);
2293 LOAD_FUNCPTR(FcObjectSetAdd);
2294 LOAD_FUNCPTR(FcObjectSetCreate);
2295 LOAD_FUNCPTR(FcObjectSetDestroy);
2296 LOAD_FUNCPTR(FcPatternCreate);
2297 LOAD_FUNCPTR(FcPatternDestroy);
2298 LOAD_FUNCPTR(FcPatternGetBool);
2299 LOAD_FUNCPTR(FcPatternGetString);
2300 #undef LOAD_FUNCPTR
2302 if(!pFcInit()) return;
2304 config = pFcConfigGetCurrent();
2305 pat = pFcPatternCreate();
2306 os = pFcObjectSetCreate();
2307 pFcObjectSetAdd(os, FC_FILE);
2308 pFcObjectSetAdd(os, FC_SCALABLE);
2309 fontset = pFcFontList(config, pat, os);
2310 if(!fontset) return;
2311 for(i = 0; i < fontset->nfont; i++) {
2312 FcBool scalable;
2314 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2315 continue;
2316 TRACE("fontconfig: %s\n", file);
2318 /* We're just interested in OT/TT fonts for now, so this hack just
2319 picks up the scalable fonts without extensions .pf[ab] to save time
2320 loading every other font */
2322 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2324 TRACE("not scalable\n");
2325 continue;
2328 len = strlen( file );
2329 if(len < 4) continue;
2330 ext = &file[ len - 3 ];
2331 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2332 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2334 pFcFontSetDestroy(fontset);
2335 pFcObjectSetDestroy(os);
2336 pFcPatternDestroy(pat);
2337 sym_not_found:
2338 #endif
2339 return;
2342 static BOOL load_font_from_data_dir(LPCWSTR file)
2344 BOOL ret = FALSE;
2345 const char *data_dir = wine_get_data_dir();
2347 if (!data_dir) data_dir = wine_get_build_dir();
2349 if (data_dir)
2351 INT len;
2352 char *unix_name;
2354 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2356 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2358 strcpy(unix_name, data_dir);
2359 strcat(unix_name, "/fonts/");
2361 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2363 EnterCriticalSection( &freetype_cs );
2364 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2365 LeaveCriticalSection( &freetype_cs );
2366 HeapFree(GetProcessHeap(), 0, unix_name);
2368 return ret;
2371 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2373 static const WCHAR slashW[] = {'\\','\0'};
2374 BOOL ret = FALSE;
2375 WCHAR windowsdir[MAX_PATH];
2376 char *unixname;
2378 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2379 strcatW(windowsdir, fontsW);
2380 strcatW(windowsdir, slashW);
2381 strcatW(windowsdir, file);
2382 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2383 EnterCriticalSection( &freetype_cs );
2384 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2385 LeaveCriticalSection( &freetype_cs );
2386 HeapFree(GetProcessHeap(), 0, unixname);
2388 return ret;
2391 static void load_system_fonts(void)
2393 HKEY hkey;
2394 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2395 const WCHAR * const *value;
2396 DWORD dlen, type;
2397 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2398 char *unixname;
2400 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2401 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2402 strcatW(windowsdir, fontsW);
2403 for(value = SystemFontValues; *value; value++) {
2404 dlen = sizeof(data);
2405 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2406 type == REG_SZ) {
2407 BOOL added = FALSE;
2409 sprintfW(pathW, fmtW, windowsdir, data);
2410 if((unixname = wine_get_unix_file_name(pathW))) {
2411 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2412 HeapFree(GetProcessHeap(), 0, unixname);
2414 if (!added)
2415 load_font_from_data_dir(data);
2418 RegCloseKey(hkey);
2422 /*************************************************************
2424 * This adds registry entries for any externally loaded fonts
2425 * (fonts from fontconfig or FontDirs). It also deletes entries
2426 * of no longer existing fonts.
2429 static void update_reg_entries(void)
2431 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2432 LPWSTR valueW;
2433 DWORD len, len_fam;
2434 Family *family;
2435 Face *face;
2436 struct list *family_elem_ptr, *face_elem_ptr;
2437 WCHAR *file;
2438 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2439 static const WCHAR spaceW[] = {' ', '\0'};
2440 char *path;
2442 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2443 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2444 ERR("Can't create Windows font reg key\n");
2445 goto end;
2448 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2449 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2450 ERR("Can't create Windows font reg key\n");
2451 goto end;
2454 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2455 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2456 ERR("Can't create external font reg key\n");
2457 goto end;
2460 /* enumerate the fonts and add external ones to the two keys */
2462 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2463 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2464 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2465 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2466 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2467 if(!face->external) continue;
2468 len = len_fam;
2469 if (!(face->ntmFlags & NTM_REGULAR))
2470 len = len_fam + strlenW(face->StyleName) + 1;
2471 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2472 strcpyW(valueW, family->FamilyName);
2473 if(len != len_fam) {
2474 strcatW(valueW, spaceW);
2475 strcatW(valueW, face->StyleName);
2477 strcatW(valueW, TrueType);
2479 file = wine_get_dos_file_name(face->file);
2480 if(file)
2481 len = strlenW(file) + 1;
2482 else
2484 if((path = strrchr(face->file, '/')) == NULL)
2485 path = face->file;
2486 else
2487 path++;
2488 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2490 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2491 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2493 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2494 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2495 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2497 HeapFree(GetProcessHeap(), 0, file);
2498 HeapFree(GetProcessHeap(), 0, valueW);
2501 end:
2502 if(external_key) RegCloseKey(external_key);
2503 if(win9x_key) RegCloseKey(win9x_key);
2504 if(winnt_key) RegCloseKey(winnt_key);
2505 return;
2508 static void delete_external_font_keys(void)
2510 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2511 DWORD dlen, vlen, datalen, valuelen, i, type;
2512 LPWSTR valueW;
2513 LPVOID data;
2515 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2516 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2517 ERR("Can't create Windows font reg key\n");
2518 goto end;
2521 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2522 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2523 ERR("Can't create Windows font reg key\n");
2524 goto end;
2527 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2528 ERR("Can't create external font reg key\n");
2529 goto end;
2532 /* Delete all external fonts added last time */
2534 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2535 &valuelen, &datalen, NULL, NULL);
2536 valuelen++; /* returned value doesn't include room for '\0' */
2537 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2538 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2540 dlen = datalen * sizeof(WCHAR);
2541 vlen = valuelen;
2542 i = 0;
2543 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2544 &dlen) == ERROR_SUCCESS) {
2546 RegDeleteValueW(winnt_key, valueW);
2547 RegDeleteValueW(win9x_key, valueW);
2548 /* reset dlen and vlen */
2549 dlen = datalen;
2550 vlen = valuelen;
2552 HeapFree(GetProcessHeap(), 0, data);
2553 HeapFree(GetProcessHeap(), 0, valueW);
2555 /* Delete the old external fonts key */
2556 RegCloseKey(external_key);
2557 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2559 end:
2560 if(win9x_key) RegCloseKey(win9x_key);
2561 if(winnt_key) RegCloseKey(winnt_key);
2564 /*************************************************************
2565 * WineEngAddFontResourceEx
2568 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2570 INT ret = 0;
2572 GDI_CheckNotLock();
2574 if (ft_handle) /* do it only if we have freetype up and running */
2576 char *unixname;
2578 if(flags)
2579 FIXME("Ignoring flags %x\n", flags);
2581 if((unixname = wine_get_unix_file_name(file)))
2583 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2585 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2586 EnterCriticalSection( &freetype_cs );
2587 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2588 LeaveCriticalSection( &freetype_cs );
2589 HeapFree(GetProcessHeap(), 0, unixname);
2591 if (!ret && !strchrW(file, '\\')) {
2592 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2593 ret = load_font_from_winfonts_dir(file);
2594 if (!ret) {
2595 /* Try in datadir/fonts (or builddir/fonts),
2596 * needed for Magic the Gathering Online
2598 ret = load_font_from_data_dir(file);
2602 return ret;
2605 /*************************************************************
2606 * WineEngAddFontMemResourceEx
2609 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2611 GDI_CheckNotLock();
2613 if (ft_handle) /* do it only if we have freetype up and running */
2615 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2617 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2618 memcpy(pFontCopy, pbFont, cbFont);
2620 EnterCriticalSection( &freetype_cs );
2621 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2622 LeaveCriticalSection( &freetype_cs );
2624 if (*pcFonts == 0)
2626 TRACE("AddFontToList failed\n");
2627 HeapFree(GetProcessHeap(), 0, pFontCopy);
2628 return 0;
2630 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2631 * For now return something unique but quite random
2633 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2634 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2637 *pcFonts = 0;
2638 return 0;
2641 /*************************************************************
2642 * WineEngRemoveFontResourceEx
2645 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2647 GDI_CheckNotLock();
2648 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2649 return TRUE;
2652 static const struct nls_update_font_list
2654 UINT ansi_cp, oem_cp;
2655 const char *oem, *fixed, *system;
2656 const char *courier, *serif, *small, *sserif;
2657 /* these are for font substitutes */
2658 const char *shelldlg, *tmsrmn;
2659 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2660 *helv_0, *tmsrmn_0;
2661 const struct subst
2663 const char *from, *to;
2664 } arial_0, courier_new_0, times_new_roman_0;
2665 } nls_update_font_list[] =
2667 /* Latin 1 (United States) */
2668 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2669 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2670 "Tahoma","Times New Roman",
2671 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2672 { 0 }, { 0 }, { 0 }
2674 /* Latin 1 (Multilingual) */
2675 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2676 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2677 "Tahoma","Times New Roman", /* FIXME unverified */
2678 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2679 { 0 }, { 0 }, { 0 }
2681 /* Eastern Europe */
2682 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2683 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2684 "Tahoma","Times New Roman", /* FIXME unverified */
2685 "Fixedsys,238", "System,238",
2686 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2687 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2688 { "Arial CE,0", "Arial,238" },
2689 { "Courier New CE,0", "Courier New,238" },
2690 { "Times New Roman CE,0", "Times New Roman,238" }
2692 /* Cyrillic */
2693 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2694 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2695 "Tahoma","Times New Roman", /* FIXME unverified */
2696 "Fixedsys,204", "System,204",
2697 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2698 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2699 { "Arial Cyr,0", "Arial,204" },
2700 { "Courier New Cyr,0", "Courier New,204" },
2701 { "Times New Roman Cyr,0", "Times New Roman,204" }
2703 /* Greek */
2704 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2705 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2706 "Tahoma","Times New Roman", /* FIXME unverified */
2707 "Fixedsys,161", "System,161",
2708 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2709 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2710 { "Arial Greek,0", "Arial,161" },
2711 { "Courier New Greek,0", "Courier New,161" },
2712 { "Times New Roman Greek,0", "Times New Roman,161" }
2714 /* Turkish */
2715 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2716 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2717 "Tahoma","Times New Roman", /* FIXME unverified */
2718 "Fixedsys,162", "System,162",
2719 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2720 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2721 { "Arial Tur,0", "Arial,162" },
2722 { "Courier New Tur,0", "Courier New,162" },
2723 { "Times New Roman Tur,0", "Times New Roman,162" }
2725 /* Hebrew */
2726 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2727 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2728 "Tahoma","Times New Roman", /* FIXME unverified */
2729 "Fixedsys,177", "System,177",
2730 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2731 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2732 { 0 }, { 0 }, { 0 }
2734 /* Arabic */
2735 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2736 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2737 "Tahoma","Times New Roman", /* FIXME unverified */
2738 "Fixedsys,178", "System,178",
2739 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2740 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2741 { 0 }, { 0 }, { 0 }
2743 /* Baltic */
2744 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2745 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2746 "Tahoma","Times New Roman", /* FIXME unverified */
2747 "Fixedsys,186", "System,186",
2748 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2749 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2750 { "Arial Baltic,0", "Arial,186" },
2751 { "Courier New Baltic,0", "Courier New,186" },
2752 { "Times New Roman Baltic,0", "Times New Roman,186" }
2754 /* Vietnamese */
2755 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2756 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2757 "Tahoma","Times New Roman", /* FIXME unverified */
2758 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2759 { 0 }, { 0 }, { 0 }
2761 /* Thai */
2762 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2763 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2764 "Tahoma","Times New Roman", /* FIXME unverified */
2765 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2766 { 0 }, { 0 }, { 0 }
2768 /* Japanese */
2769 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2770 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2771 "MS UI Gothic","MS Serif",
2772 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2773 { 0 }, { 0 }, { 0 }
2775 /* Chinese Simplified */
2776 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2777 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2778 "SimSun", "NSimSun",
2779 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2780 { 0 }, { 0 }, { 0 }
2782 /* Korean */
2783 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2784 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2785 "Gulim", "Batang",
2786 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2787 { 0 }, { 0 }, { 0 }
2789 /* Chinese Traditional */
2790 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2791 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2792 "PMingLiU", "MingLiU",
2793 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2794 { 0 }, { 0 }, { 0 }
2798 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2800 return ( ansi_cp == 932 /* CP932 for Japanese */
2801 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2802 || ansi_cp == 949 /* CP949 for Korean */
2803 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2806 static inline HKEY create_fonts_NT_registry_key(void)
2808 HKEY hkey = 0;
2810 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2811 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2812 return hkey;
2815 static inline HKEY create_fonts_9x_registry_key(void)
2817 HKEY hkey = 0;
2819 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2820 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2821 return hkey;
2824 static inline HKEY create_config_fonts_registry_key(void)
2826 HKEY hkey = 0;
2828 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2829 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2830 return hkey;
2833 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2835 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2836 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2837 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2838 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2841 static void set_value_key(HKEY hkey, const char *name, const char *value)
2843 if (value)
2844 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2845 else if (name)
2846 RegDeleteValueA(hkey, name);
2849 static void update_font_info(void)
2851 char buf[40], cpbuf[40];
2852 DWORD len, type;
2853 HKEY hkey = 0;
2854 UINT i, ansi_cp = 0, oem_cp = 0;
2855 BOOL done = FALSE;
2857 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2858 return;
2860 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2861 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2862 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2863 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2864 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2866 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2867 if (is_dbcs_ansi_cp(ansi_cp))
2868 use_default_fallback = TRUE;
2870 len = sizeof(buf);
2871 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2873 if (!strcmp( buf, cpbuf )) /* already set correctly */
2875 RegCloseKey(hkey);
2876 return;
2878 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2880 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2882 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2883 RegCloseKey(hkey);
2885 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2887 HKEY hkey;
2889 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2890 nls_update_font_list[i].oem_cp == oem_cp)
2892 hkey = create_config_fonts_registry_key();
2893 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2894 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2895 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2896 RegCloseKey(hkey);
2898 hkey = create_fonts_NT_registry_key();
2899 add_font_list(hkey, &nls_update_font_list[i]);
2900 RegCloseKey(hkey);
2902 hkey = create_fonts_9x_registry_key();
2903 add_font_list(hkey, &nls_update_font_list[i]);
2904 RegCloseKey(hkey);
2906 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2908 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2909 strlen(nls_update_font_list[i].shelldlg)+1);
2910 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2911 strlen(nls_update_font_list[i].tmsrmn)+1);
2913 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2914 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2915 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2916 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2917 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2918 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2919 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2920 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2922 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2923 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2924 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2926 RegCloseKey(hkey);
2928 done = TRUE;
2930 else
2932 /* Delete the FontSubstitutes from other locales */
2933 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2935 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2936 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2937 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2938 RegCloseKey(hkey);
2942 if (!done)
2943 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2946 static BOOL init_freetype(void)
2948 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2949 if(!ft_handle) {
2950 WINE_MESSAGE(
2951 "Wine cannot find the FreeType font library. To enable Wine to\n"
2952 "use TrueType fonts please install a version of FreeType greater than\n"
2953 "or equal to 2.0.5.\n"
2954 "http://www.freetype.org\n");
2955 return FALSE;
2958 #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;}
2960 LOAD_FUNCPTR(FT_Done_Face)
2961 LOAD_FUNCPTR(FT_Get_Char_Index)
2962 LOAD_FUNCPTR(FT_Get_First_Char)
2963 LOAD_FUNCPTR(FT_Get_Module)
2964 LOAD_FUNCPTR(FT_Get_Next_Char)
2965 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2966 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2967 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2968 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2969 LOAD_FUNCPTR(FT_Init_FreeType)
2970 LOAD_FUNCPTR(FT_Library_Version)
2971 LOAD_FUNCPTR(FT_Load_Glyph)
2972 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2973 LOAD_FUNCPTR(FT_Matrix_Multiply)
2974 #ifndef FT_MULFIX_INLINED
2975 LOAD_FUNCPTR(FT_MulFix)
2976 #endif
2977 LOAD_FUNCPTR(FT_New_Face)
2978 LOAD_FUNCPTR(FT_New_Memory_Face)
2979 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2980 LOAD_FUNCPTR(FT_Outline_Transform)
2981 LOAD_FUNCPTR(FT_Outline_Translate)
2982 LOAD_FUNCPTR(FT_Render_Glyph)
2983 LOAD_FUNCPTR(FT_Select_Charmap)
2984 LOAD_FUNCPTR(FT_Set_Charmap)
2985 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2986 LOAD_FUNCPTR(FT_Vector_Transform)
2987 LOAD_FUNCPTR(FT_Vector_Unit)
2988 #undef LOAD_FUNCPTR
2989 /* Don't warn if these ones are missing */
2990 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2991 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2992 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2993 #endif
2995 if(pFT_Init_FreeType(&library) != 0) {
2996 ERR("Can't init FreeType library\n");
2997 wine_dlclose(ft_handle, NULL, 0);
2998 ft_handle = NULL;
2999 return FALSE;
3001 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3003 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3004 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3005 ((FT_Version.minor << 8) & 0x00ff00) |
3006 ((FT_Version.patch ) & 0x0000ff);
3008 font_driver = &freetype_funcs;
3009 return TRUE;
3011 sym_not_found:
3012 WINE_MESSAGE(
3013 "Wine cannot find certain functions that it needs inside the FreeType\n"
3014 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3015 "FreeType to at least version 2.1.4.\n"
3016 "http://www.freetype.org\n");
3017 wine_dlclose(ft_handle, NULL, 0);
3018 ft_handle = NULL;
3019 return FALSE;
3022 static void init_font_list(void)
3024 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3025 static const WCHAR pathW[] = {'P','a','t','h',0};
3026 HKEY hkey;
3027 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3028 WCHAR windowsdir[MAX_PATH];
3029 char *unixname;
3030 const char *home;
3031 const char *data_dir;
3033 delete_external_font_keys();
3035 /* load the system bitmap fonts */
3036 load_system_fonts();
3038 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3039 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3040 strcatW(windowsdir, fontsW);
3041 if((unixname = wine_get_unix_file_name(windowsdir)))
3043 ReadFontDir(unixname, FALSE);
3044 HeapFree(GetProcessHeap(), 0, unixname);
3047 /* load the system truetype fonts */
3048 data_dir = wine_get_data_dir();
3049 if (!data_dir) data_dir = wine_get_build_dir();
3050 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3052 strcpy(unixname, data_dir);
3053 strcat(unixname, "/fonts/");
3054 ReadFontDir(unixname, TRUE);
3055 HeapFree(GetProcessHeap(), 0, unixname);
3058 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3059 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3060 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3061 will skip these. */
3062 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3063 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3064 &hkey) == ERROR_SUCCESS)
3066 LPWSTR data, valueW;
3067 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3068 &valuelen, &datalen, NULL, NULL);
3070 valuelen++; /* returned value doesn't include room for '\0' */
3071 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3072 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3073 if (valueW && data)
3075 dlen = datalen * sizeof(WCHAR);
3076 vlen = valuelen;
3077 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3078 &dlen) == ERROR_SUCCESS)
3080 if(data[0] && (data[1] == ':'))
3082 if((unixname = wine_get_unix_file_name(data)))
3084 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3085 HeapFree(GetProcessHeap(), 0, unixname);
3088 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3090 WCHAR pathW[MAX_PATH];
3091 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3092 BOOL added = FALSE;
3094 sprintfW(pathW, fmtW, windowsdir, data);
3095 if((unixname = wine_get_unix_file_name(pathW)))
3097 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3098 HeapFree(GetProcessHeap(), 0, unixname);
3100 if (!added)
3101 load_font_from_data_dir(data);
3103 /* reset dlen and vlen */
3104 dlen = datalen;
3105 vlen = valuelen;
3108 HeapFree(GetProcessHeap(), 0, data);
3109 HeapFree(GetProcessHeap(), 0, valueW);
3110 RegCloseKey(hkey);
3113 load_fontconfig_fonts();
3115 /* then look in any directories that we've specified in the config file */
3116 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3117 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3119 DWORD len;
3120 LPWSTR valueW;
3121 LPSTR valueA, ptr;
3123 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3125 len += sizeof(WCHAR);
3126 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3127 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3129 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3130 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3131 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3132 TRACE( "got font path %s\n", debugstr_a(valueA) );
3133 ptr = valueA;
3134 while (ptr)
3136 LPSTR next = strchr( ptr, ':' );
3137 if (next) *next++ = 0;
3138 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3139 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3141 strcpy( unixname, home );
3142 strcat( unixname, ptr + 1 );
3143 ReadFontDir( unixname, TRUE );
3144 HeapFree( GetProcessHeap(), 0, unixname );
3146 else
3147 ReadFontDir( ptr, TRUE );
3148 ptr = next;
3150 HeapFree( GetProcessHeap(), 0, valueA );
3152 HeapFree( GetProcessHeap(), 0, valueW );
3154 RegCloseKey(hkey);
3157 #ifdef __APPLE__
3158 /* Mac default font locations. */
3159 ReadFontDir( "/Library/Fonts", TRUE );
3160 ReadFontDir( "/Network/Library/Fonts", TRUE );
3161 ReadFontDir( "/System/Library/Fonts", TRUE );
3162 if ((home = getenv( "HOME" )))
3164 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3165 strcpy( unixname, home );
3166 strcat( unixname, "/Library/Fonts" );
3167 ReadFontDir( unixname, TRUE);
3168 HeapFree( GetProcessHeap(), 0, unixname );
3170 #endif
3173 static BOOL move_to_front(const WCHAR *name)
3175 Family *family, *cursor2;
3176 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3178 if(!strcmpiW(family->FamilyName, name))
3180 list_remove(&family->entry);
3181 list_add_head(&font_list, &family->entry);
3182 return TRUE;
3185 return FALSE;
3188 static BOOL set_default(const WCHAR **name_list)
3190 while (*name_list)
3192 if (move_to_front(*name_list)) return TRUE;
3193 name_list++;
3196 return FALSE;
3199 static void reorder_font_list(void)
3201 set_default( default_serif_list );
3202 set_default( default_fixed_list );
3203 set_default( default_sans_list );
3206 /*************************************************************
3207 * WineEngInit
3209 * Initialize FreeType library and create a list of available faces
3211 BOOL WineEngInit(void)
3213 HKEY hkey_font_cache;
3214 DWORD disposition;
3215 HANDLE font_mutex;
3217 /* update locale dependent font info in registry */
3218 update_font_info();
3220 if(!init_freetype()) return FALSE;
3222 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3224 ERR("Failed to create font mutex\n");
3225 return FALSE;
3227 WaitForSingleObject(font_mutex, INFINITE);
3229 create_font_cache_key(&hkey_font_cache, &disposition);
3231 if(disposition == REG_CREATED_NEW_KEY)
3232 init_font_list();
3233 else
3234 load_font_list_from_cache(hkey_font_cache);
3236 RegCloseKey(hkey_font_cache);
3238 reorder_font_list();
3240 DumpFontList();
3241 LoadSubstList();
3242 DumpSubstList();
3243 LoadReplaceList();
3245 if(disposition == REG_CREATED_NEW_KEY)
3246 update_reg_entries();
3248 init_system_links();
3250 ReleaseMutex(font_mutex);
3251 return TRUE;
3255 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3257 TT_OS2 *pOS2;
3258 TT_HoriHeader *pHori;
3260 LONG ppem;
3262 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3263 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3265 if(height == 0) height = 16;
3267 /* Calc. height of EM square:
3269 * For +ve lfHeight we have
3270 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3271 * Re-arranging gives:
3272 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3274 * For -ve lfHeight we have
3275 * |lfHeight| = ppem
3276 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3277 * with il = winAscent + winDescent - units_per_em]
3281 if(height > 0) {
3282 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3283 ppem = MulDiv(ft_face->units_per_EM, height,
3284 pHori->Ascender - pHori->Descender);
3285 else
3286 ppem = MulDiv(ft_face->units_per_EM, height,
3287 pOS2->usWinAscent + pOS2->usWinDescent);
3289 else
3290 ppem = -height;
3292 return ppem;
3295 static struct font_mapping *map_font_file( const char *name )
3297 struct font_mapping *mapping;
3298 struct stat st;
3299 int fd;
3301 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3302 if (fstat( fd, &st ) == -1) goto error;
3304 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3306 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3308 mapping->refcount++;
3309 close( fd );
3310 return mapping;
3313 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3314 goto error;
3316 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3317 close( fd );
3319 if (mapping->data == MAP_FAILED)
3321 HeapFree( GetProcessHeap(), 0, mapping );
3322 return NULL;
3324 mapping->refcount = 1;
3325 mapping->dev = st.st_dev;
3326 mapping->ino = st.st_ino;
3327 mapping->size = st.st_size;
3328 list_add_tail( &mappings_list, &mapping->entry );
3329 return mapping;
3331 error:
3332 close( fd );
3333 return NULL;
3336 static void unmap_font_file( struct font_mapping *mapping )
3338 if (!--mapping->refcount)
3340 list_remove( &mapping->entry );
3341 munmap( mapping->data, mapping->size );
3342 HeapFree( GetProcessHeap(), 0, mapping );
3346 static LONG load_VDMX(GdiFont*, LONG);
3348 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3350 FT_Error err;
3351 FT_Face ft_face;
3352 void *data_ptr;
3353 DWORD data_size;
3355 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3357 if (face->file)
3359 if (!(font->mapping = map_font_file( face->file )))
3361 WARN("failed to map %s\n", debugstr_a(face->file));
3362 return 0;
3364 data_ptr = font->mapping->data;
3365 data_size = font->mapping->size;
3367 else
3369 data_ptr = face->font_data_ptr;
3370 data_size = face->font_data_size;
3373 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3374 if(err) {
3375 ERR("FT_New_Face rets %d\n", err);
3376 return 0;
3379 /* set it here, as load_VDMX needs it */
3380 font->ft_face = ft_face;
3382 if(FT_IS_SCALABLE(ft_face)) {
3383 /* load the VDMX table if we have one */
3384 font->ppem = load_VDMX(font, height);
3385 if(font->ppem == 0)
3386 font->ppem = calc_ppem_for_height(ft_face, height);
3387 TRACE("height %d => ppem %d\n", height, font->ppem);
3389 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3390 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3391 } else {
3392 font->ppem = height;
3393 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3394 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3396 return ft_face;
3400 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3402 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3403 a single face with the requested charset. The idea is to check if
3404 the selected font supports the current ANSI codepage, if it does
3405 return the corresponding charset, else return the first charset */
3407 CHARSETINFO csi;
3408 int acp = GetACP(), i;
3409 DWORD fs0;
3411 *cp = acp;
3412 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3414 const SYSTEM_LINKS *font_link;
3416 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3417 return csi.ciCharset;
3419 font_link = find_font_link(family_name);
3420 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3421 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 font_link = find_font_link(font_name);
3776 if (font_link != NULL)
3778 TRACE("found entry in system list\n");
3779 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3781 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3782 new_child->face = font_link_entry->face;
3783 new_child->font = NULL;
3784 list_add_tail(&font->child_fonts, &new_child->entry);
3785 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3787 ret = TRUE;
3790 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3791 * Sans Serif. This is how asian windows get default fallbacks for fonts
3793 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3794 font->charset != OEM_CHARSET &&
3795 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3797 font_link = find_font_link(szDefaultFallbackLink);
3798 if (font_link != NULL)
3800 TRACE("found entry in default fallback list\n");
3801 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3803 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3804 new_child->face = font_link_entry->face;
3805 new_child->font = NULL;
3806 list_add_tail(&font->child_fonts, &new_child->entry);
3807 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3809 ret = TRUE;
3813 return ret;
3816 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3818 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3820 if (pFT_Set_Charmap)
3822 FT_Int i;
3823 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3825 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3827 for (i = 0; i < ft_face->num_charmaps; i++)
3829 if (ft_face->charmaps[i]->encoding == encoding)
3831 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3832 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3834 switch (ft_face->charmaps[i]->platform_id)
3836 default:
3837 cmap_def = ft_face->charmaps[i];
3838 break;
3839 case 0: /* Apple Unicode */
3840 cmap0 = ft_face->charmaps[i];
3841 break;
3842 case 1: /* Macintosh */
3843 cmap1 = ft_face->charmaps[i];
3844 break;
3845 case 2: /* ISO */
3846 cmap2 = ft_face->charmaps[i];
3847 break;
3848 case 3: /* Microsoft */
3849 cmap3 = ft_face->charmaps[i];
3850 break;
3854 if (cmap3) /* prefer Microsoft cmap table */
3855 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3856 else if (cmap1)
3857 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3858 else if (cmap2)
3859 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3860 else if (cmap0)
3861 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3862 else if (cmap_def)
3863 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3865 return ft_err == FT_Err_Ok;
3868 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3872 /*************************************************************
3873 * freetype_CreateDC
3875 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3876 LPCWSTR output, const DEVMODEW *devmode )
3878 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3880 if (!physdev) return FALSE;
3881 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3882 return TRUE;
3886 /*************************************************************
3887 * freetype_DeleteDC
3889 static BOOL freetype_DeleteDC( PHYSDEV dev )
3891 struct freetype_physdev *physdev = get_freetype_dev( dev );
3892 HeapFree( GetProcessHeap(), 0, physdev );
3893 return TRUE;
3897 /*************************************************************
3898 * freetype_SelectFont
3900 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3902 struct freetype_physdev *physdev = get_freetype_dev( dev );
3903 GdiFont *ret;
3904 Face *face, *best, *best_bitmap;
3905 Family *family, *last_resort_family;
3906 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
3907 INT height, width = 0;
3908 unsigned int score = 0, new_score;
3909 signed int diff = 0, newdiff;
3910 BOOL bd, it, can_use_bitmap, want_vertical;
3911 LOGFONTW lf;
3912 CHARSETINFO csi;
3913 HFONTLIST *hflist;
3914 FMAT2 dcmat;
3915 FontSubst *psub = NULL;
3916 DC *dc = get_dc_ptr( dev->hdc );
3917 const SYSTEM_LINKS *font_link;
3919 if (!hfont) /* notification that the font has been changed by another driver */
3921 dc->gdiFont = NULL;
3922 physdev->font = NULL;
3923 release_dc_ptr( dc );
3924 return 0;
3927 GetObjectW( hfont, sizeof(lf), &lf );
3928 lf.lfWidth = abs(lf.lfWidth);
3930 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3932 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3933 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3934 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3935 lf.lfEscapement);
3937 if(dc->GraphicsMode == GM_ADVANCED)
3939 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3940 /* Try to avoid not necessary glyph transformations */
3941 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3943 lf.lfHeight *= fabs(dcmat.eM11);
3944 lf.lfWidth *= fabs(dcmat.eM11);
3945 dcmat.eM11 = dcmat.eM22 = 1.0;
3948 else
3950 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3951 font scaling abilities. */
3952 dcmat.eM11 = dcmat.eM22 = 1.0;
3953 dcmat.eM21 = dcmat.eM12 = 0;
3954 if (dc->vport2WorldValid)
3956 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
3957 lf.lfOrientation = -lf.lfOrientation;
3958 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
3959 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
3963 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3964 dcmat.eM21, dcmat.eM22);
3966 GDI_CheckNotLock();
3967 EnterCriticalSection( &freetype_cs );
3969 /* check the cache first */
3970 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3971 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3972 goto done;
3975 if(list_empty(&font_list)) /* No fonts installed */
3977 TRACE("No fonts installed\n");
3978 goto done;
3981 TRACE("not in cache\n");
3982 ret = alloc_font();
3984 ret->font_desc.matrix = dcmat;
3985 ret->font_desc.lf = lf;
3986 ret->font_desc.can_use_bitmap = can_use_bitmap;
3987 calc_hash(&ret->font_desc);
3988 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3989 hflist->hfont = hfont;
3990 list_add_head(&ret->hfontlist, &hflist->entry);
3992 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3993 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3994 original value lfCharSet. Note this is a special case for
3995 Symbol and doesn't happen at least for "Wingdings*" */
3997 if(!strcmpiW(lf.lfFaceName, SymbolW))
3998 lf.lfCharSet = SYMBOL_CHARSET;
4000 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4001 switch(lf.lfCharSet) {
4002 case DEFAULT_CHARSET:
4003 csi.fs.fsCsb[0] = 0;
4004 break;
4005 default:
4006 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4007 csi.fs.fsCsb[0] = 0;
4008 break;
4012 family = NULL;
4013 if(lf.lfFaceName[0] != '\0') {
4014 CHILD_FONT *font_link_entry;
4015 LPWSTR FaceName = lf.lfFaceName;
4017 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4019 if(psub) {
4020 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4021 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4022 if (psub->to.charset != -1)
4023 lf.lfCharSet = psub->to.charset;
4026 /* We want a match on name and charset or just name if
4027 charset was DEFAULT_CHARSET. If the latter then
4028 we fixup the returned charset later in get_nearest_charset
4029 where we'll either use the charset of the current ansi codepage
4030 or if that's unavailable the first charset that the font supports.
4032 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4033 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4034 if (!strcmpiW(family->FamilyName, FaceName) ||
4035 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4037 font_link = find_font_link(family->FamilyName);
4038 face_list = get_face_list_from_family(family);
4039 LIST_FOR_EACH(face_elem_ptr, face_list) {
4040 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4041 if (!(face->scalable || can_use_bitmap))
4042 continue;
4043 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4044 goto found;
4045 if (font_link != NULL &&
4046 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4047 goto found;
4048 if (!csi.fs.fsCsb[0])
4049 goto found;
4054 /* Search by full face name. */
4055 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4056 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4057 face_list = get_face_list_from_family(family);
4058 LIST_FOR_EACH(face_elem_ptr, face_list) {
4059 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4060 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4061 (face->scalable || can_use_bitmap))
4063 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4064 goto found_face;
4065 font_link = find_font_link(family->FamilyName);
4066 if (font_link != NULL &&
4067 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4068 goto found_face;
4074 * Try check the SystemLink list first for a replacement font.
4075 * We may find good replacements there.
4077 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4079 if(!strcmpiW(font_link->font_name, FaceName) ||
4080 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4082 TRACE("found entry in system list\n");
4083 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4085 const SYSTEM_LINKS *links;
4087 face = font_link_entry->face;
4088 if (!(face->scalable || can_use_bitmap))
4089 continue;
4090 family = face->family;
4091 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4092 goto found;
4093 links = find_font_link(family->FamilyName);
4094 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4095 goto found;
4101 psub = NULL; /* substitution is no more relevant */
4103 /* If requested charset was DEFAULT_CHARSET then try using charset
4104 corresponding to the current ansi codepage */
4105 if (!csi.fs.fsCsb[0])
4107 INT acp = GetACP();
4108 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4109 FIXME("TCI failed on codepage %d\n", acp);
4110 csi.fs.fsCsb[0] = 0;
4111 } else
4112 lf.lfCharSet = csi.ciCharset;
4115 want_vertical = (lf.lfFaceName[0] == '@');
4117 /* Face families are in the top 4 bits of lfPitchAndFamily,
4118 so mask with 0xF0 before testing */
4120 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4121 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4122 strcpyW(lf.lfFaceName, defFixed);
4123 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4124 strcpyW(lf.lfFaceName, defSerif);
4125 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4126 strcpyW(lf.lfFaceName, defSans);
4127 else
4128 strcpyW(lf.lfFaceName, defSans);
4129 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4130 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4131 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4132 font_link = find_font_link(family->FamilyName);
4133 face_list = get_face_list_from_family(family);
4134 LIST_FOR_EACH(face_elem_ptr, face_list) {
4135 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4136 if (!(face->scalable || can_use_bitmap))
4137 continue;
4138 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4139 goto found;
4140 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4141 goto found;
4146 last_resort_family = NULL;
4147 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4148 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4149 font_link = find_font_link(family->FamilyName);
4150 face_list = get_face_list_from_family(family);
4151 LIST_FOR_EACH(face_elem_ptr, face_list) {
4152 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4153 if(face->vertical == want_vertical &&
4154 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4155 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4156 if(face->scalable)
4157 goto found;
4158 if(can_use_bitmap && !last_resort_family)
4159 last_resort_family = family;
4164 if(last_resort_family) {
4165 family = last_resort_family;
4166 csi.fs.fsCsb[0] = 0;
4167 goto found;
4170 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4171 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4172 face_list = get_face_list_from_family(family);
4173 LIST_FOR_EACH(face_elem_ptr, face_list) {
4174 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4175 if(face->scalable && face->vertical == want_vertical) {
4176 csi.fs.fsCsb[0] = 0;
4177 WARN("just using first face for now\n");
4178 goto found;
4180 if(can_use_bitmap && !last_resort_family)
4181 last_resort_family = family;
4184 if(!last_resort_family) {
4185 FIXME("can't find a single appropriate font - bailing\n");
4186 free_font(ret);
4187 ret = NULL;
4188 goto done;
4191 WARN("could only find a bitmap font - this will probably look awful!\n");
4192 family = last_resort_family;
4193 csi.fs.fsCsb[0] = 0;
4195 found:
4196 it = lf.lfItalic ? 1 : 0;
4197 bd = lf.lfWeight > 550 ? 1 : 0;
4199 height = lf.lfHeight;
4201 face = best = best_bitmap = NULL;
4202 font_link = find_font_link(family->FamilyName);
4203 face_list = get_face_list_from_family(family);
4204 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4206 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4207 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4208 !csi.fs.fsCsb[0])
4210 BOOL italic, bold;
4212 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4213 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4214 new_score = (italic ^ it) + (bold ^ bd);
4215 if(!best || new_score <= score)
4217 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4218 italic, bold, it, bd);
4219 score = new_score;
4220 best = face;
4221 if(best->scalable && score == 0) break;
4222 if(!best->scalable)
4224 if(height > 0)
4225 newdiff = height - (signed int)(best->size.height);
4226 else
4227 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4228 if(!best_bitmap || new_score < score ||
4229 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4231 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4232 diff = newdiff;
4233 best_bitmap = best;
4234 if(score == 0 && diff == 0) break;
4240 if(best)
4241 face = best->scalable ? best : best_bitmap;
4242 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4243 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4245 found_face:
4246 height = lf.lfHeight;
4248 ret->fs = face->fs;
4250 if(csi.fs.fsCsb[0]) {
4251 ret->charset = lf.lfCharSet;
4252 ret->codepage = csi.ciACP;
4254 else
4255 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4257 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4258 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4260 ret->aveWidth = height ? lf.lfWidth : 0;
4262 if(!face->scalable) {
4263 /* Windows uses integer scaling factors for bitmap fonts */
4264 INT scale, scaled_height;
4265 GdiFont *cachedfont;
4267 /* FIXME: rotation of bitmap fonts is ignored */
4268 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4269 if (ret->aveWidth)
4270 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4271 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4272 dcmat.eM11 = dcmat.eM22 = 1.0;
4273 /* As we changed the matrix, we need to search the cache for the font again,
4274 * otherwise we might explode the cache. */
4275 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4276 TRACE("Found cached font after non-scalable matrix rescale!\n");
4277 free_font( ret );
4278 ret = cachedfont;
4279 goto done;
4281 calc_hash(&ret->font_desc);
4283 if (height != 0) height = diff;
4284 height += face->size.height;
4286 scale = (height + face->size.height - 1) / face->size.height;
4287 scaled_height = scale * face->size.height;
4288 /* Only jump to the next height if the difference <= 25% original height */
4289 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4290 /* The jump between unscaled and doubled is delayed by 1 */
4291 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4292 ret->scale_y = scale;
4294 width = face->size.x_ppem >> 6;
4295 height = face->size.y_ppem >> 6;
4297 else
4298 ret->scale_y = 1.0;
4299 TRACE("font scale y: %f\n", ret->scale_y);
4301 ret->ft_face = OpenFontFace(ret, face, width, height);
4303 if (!ret->ft_face)
4305 free_font( ret );
4306 ret = NULL;
4307 goto done;
4310 ret->ntmFlags = face->ntmFlags;
4312 if (ret->charset == SYMBOL_CHARSET &&
4313 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4314 /* No ops */
4316 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4317 /* No ops */
4319 else {
4320 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4323 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4324 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4325 ret->underline = lf.lfUnderline ? 0xff : 0;
4326 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4327 create_child_font_list(ret);
4329 if (face->vertical) /* We need to try to load the GSUB table */
4331 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4332 if (length != GDI_ERROR)
4334 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4335 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4336 TRACE("Loaded GSUB table of %i bytes\n",length);
4340 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4342 add_to_cache(ret);
4343 done:
4344 if (ret)
4346 dc->gdiFont = ret;
4347 physdev->font = ret;
4349 LeaveCriticalSection( &freetype_cs );
4350 release_dc_ptr( dc );
4351 return ret ? hfont : 0;
4354 static void dump_gdi_font_list(void)
4356 GdiFont *gdiFont;
4357 struct list *elem_ptr;
4359 TRACE("---------- gdiFont Cache ----------\n");
4360 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4361 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4362 TRACE("gdiFont=%p %s %d\n",
4363 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4366 TRACE("---------- Unused gdiFont Cache ----------\n");
4367 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4368 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4369 TRACE("gdiFont=%p %s %d\n",
4370 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4373 TRACE("---------- Child gdiFont Cache ----------\n");
4374 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4375 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4376 TRACE("gdiFont=%p %s %d\n",
4377 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4381 /*************************************************************
4382 * WineEngDestroyFontInstance
4384 * free the gdiFont associated with this handle
4387 BOOL WineEngDestroyFontInstance(HFONT handle)
4389 GdiFont *gdiFont;
4390 HFONTLIST *hflist;
4391 BOOL ret = FALSE;
4392 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4393 int i = 0;
4395 GDI_CheckNotLock();
4396 EnterCriticalSection( &freetype_cs );
4398 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4400 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4401 while(hfontlist_elem_ptr) {
4402 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4403 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4404 if(hflist->hfont == handle) {
4405 TRACE("removing child font %p from child list\n", gdiFont);
4406 list_remove(&gdiFont->entry);
4407 LeaveCriticalSection( &freetype_cs );
4408 return TRUE;
4413 TRACE("destroying hfont=%p\n", handle);
4414 if(TRACE_ON(font))
4415 dump_gdi_font_list();
4417 font_elem_ptr = list_head(&gdi_font_list);
4418 while(font_elem_ptr) {
4419 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4420 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4422 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4423 while(hfontlist_elem_ptr) {
4424 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4425 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4426 if(hflist->hfont == handle) {
4427 list_remove(&hflist->entry);
4428 HeapFree(GetProcessHeap(), 0, hflist);
4429 ret = TRUE;
4432 if(list_empty(&gdiFont->hfontlist)) {
4433 TRACE("Moving to Unused list\n");
4434 list_remove(&gdiFont->entry);
4435 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4440 font_elem_ptr = list_head(&unused_gdi_font_list);
4441 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4442 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4443 while(font_elem_ptr) {
4444 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4445 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4446 TRACE("freeing %p\n", gdiFont);
4447 list_remove(&gdiFont->entry);
4448 free_font(gdiFont);
4450 LeaveCriticalSection( &freetype_cs );
4451 return ret;
4454 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4456 HRSRC rsrc;
4457 HGLOBAL hMem;
4458 WCHAR *p;
4459 int i;
4461 id += IDS_FIRST_SCRIPT;
4462 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4463 if (!rsrc) return 0;
4464 hMem = LoadResource( gdi32_module, rsrc );
4465 if (!hMem) return 0;
4467 p = LockResource( hMem );
4468 id &= 0x000f;
4469 while (id--) p += *p + 1;
4471 i = min(LF_FACESIZE - 1, *p);
4472 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4473 buffer[i] = 0;
4474 return i;
4478 /***************************************************
4479 * create_enum_charset_list
4481 * This function creates charset enumeration list because in DEFAULT_CHARSET
4482 * case, the ANSI codepage's charset takes precedence over other charsets.
4483 * This function works as a filter other than DEFAULT_CHARSET case.
4485 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4487 CHARSETINFO csi;
4488 DWORD n = 0;
4490 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4491 csi.fs.fsCsb[0] != 0) {
4492 list->element[n].mask = csi.fs.fsCsb[0];
4493 list->element[n].charset = csi.ciCharset;
4494 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4495 n++;
4497 else { /* charset is DEFAULT_CHARSET or invalid. */
4498 INT acp, i;
4500 /* Set the current codepage's charset as the first element. */
4501 acp = GetACP();
4502 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4503 csi.fs.fsCsb[0] != 0) {
4504 list->element[n].mask = csi.fs.fsCsb[0];
4505 list->element[n].charset = csi.ciCharset;
4506 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4507 n++;
4510 /* Fill out left elements. */
4511 for (i = 0; i < 32; i++) {
4512 FONTSIGNATURE fs;
4513 fs.fsCsb[0] = 1L << i;
4514 fs.fsCsb[1] = 0;
4515 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4516 continue; /* skip, already added. */
4517 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4518 continue; /* skip, this is an invalid fsCsb bit. */
4520 list->element[n].mask = fs.fsCsb[0];
4521 list->element[n].charset = csi.ciCharset;
4522 load_script_name( i, list->element[n].name );
4523 n++;
4526 list->total = n;
4528 return n;
4531 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4532 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4534 GdiFont *font;
4535 LONG width, height;
4537 if (face->cached_enum_data)
4539 TRACE("Cached\n");
4540 *pelf = face->cached_enum_data->elf;
4541 *pntm = face->cached_enum_data->ntm;
4542 *ptype = face->cached_enum_data->type;
4543 return;
4546 font = alloc_font();
4548 if(face->scalable) {
4549 height = -2048; /* 2048 is the most common em size */
4550 width = 0;
4551 } else {
4552 height = face->size.y_ppem >> 6;
4553 width = face->size.x_ppem >> 6;
4555 font->scale_y = 1.0;
4557 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4559 free_font(font);
4560 return;
4563 font->name = strdupW(face->family->FamilyName);
4564 font->ntmFlags = face->ntmFlags;
4566 if (get_outline_text_metrics(font))
4568 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4570 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4572 lstrcpynW(pelf->elfLogFont.lfFaceName,
4573 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4574 LF_FACESIZE);
4575 lstrcpynW(pelf->elfFullName,
4576 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4577 LF_FULLFACESIZE);
4578 lstrcpynW(pelf->elfStyle,
4579 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4580 LF_FACESIZE);
4582 else
4584 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4586 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4588 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4589 if (face->FullName)
4590 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4591 else
4592 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4593 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4596 pntm->ntmTm.ntmFlags = face->ntmFlags;
4597 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4598 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4599 pntm->ntmFontSig = face->fs;
4601 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4603 pelf->elfLogFont.lfEscapement = 0;
4604 pelf->elfLogFont.lfOrientation = 0;
4605 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4606 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4607 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4608 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4609 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4610 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4611 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4612 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4613 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4614 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4615 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4617 *ptype = 0;
4618 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4619 *ptype |= TRUETYPE_FONTTYPE;
4620 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4621 *ptype |= DEVICE_FONTTYPE;
4622 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4623 *ptype |= RASTER_FONTTYPE;
4625 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4626 if (face->cached_enum_data)
4628 face->cached_enum_data->elf = *pelf;
4629 face->cached_enum_data->ntm = *pntm;
4630 face->cached_enum_data->type = *ptype;
4633 free_font(font);
4636 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
4638 static const WCHAR spaceW[] = { ' ', 0 };
4640 strcpyW(full_name, family_name);
4641 strcatW(full_name, spaceW);
4642 strcatW(full_name, style_name);
4645 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4647 const struct list *face_list, *face_elem_ptr;
4649 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4651 face_list = get_face_list_from_family(family);
4652 LIST_FOR_EACH(face_elem_ptr, face_list)
4654 WCHAR full_family_name[LF_FULLFACESIZE];
4655 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4657 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4659 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4660 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4661 continue;
4664 create_full_name(full_family_name, family->FamilyName, face->StyleName);
4665 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4668 return FALSE;
4671 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
4673 WCHAR full_family_name[LF_FULLFACESIZE];
4675 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
4677 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4679 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4680 debugstr_w(family_name), debugstr_w(face->StyleName));
4681 return FALSE;
4684 create_full_name(full_family_name, family_name, face->StyleName);
4685 return !strcmpiW(lf->lfFaceName, full_family_name);
4688 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
4689 FONTENUMPROCW proc, LPARAM lparam)
4691 ENUMLOGFONTEXW elf;
4692 NEWTEXTMETRICEXW ntm;
4693 DWORD type = 0;
4694 int i;
4696 GetEnumStructs(face, &elf, &ntm, &type);
4697 for(i = 0; i < list->total; i++) {
4698 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4699 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4700 load_script_name( IDS_OEM_DOS, elf.elfScript );
4701 i = list->total; /* break out of loop after enumeration */
4702 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4703 continue;
4704 else {
4705 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4706 strcpyW(elf.elfScript, list->element[i].name);
4707 if (!elf.elfScript[0])
4708 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4710 /* Font Replacement */
4711 if (family != face->family)
4713 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
4714 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
4716 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4717 debugstr_w(elf.elfLogFont.lfFaceName),
4718 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4719 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4720 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4721 ntm.ntmTm.ntmFlags);
4722 /* release section before callback (FIXME) */
4723 LeaveCriticalSection( &freetype_cs );
4724 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4725 EnterCriticalSection( &freetype_cs );
4727 return TRUE;
4730 /*************************************************************
4731 * freetype_EnumFonts
4733 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4735 Family *family;
4736 Face *face;
4737 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4738 LOGFONTW lf;
4739 struct enum_charset_list enum_charsets;
4741 if (!plf)
4743 lf.lfCharSet = DEFAULT_CHARSET;
4744 lf.lfPitchAndFamily = 0;
4745 lf.lfFaceName[0] = 0;
4746 plf = &lf;
4749 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4751 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4753 GDI_CheckNotLock();
4754 EnterCriticalSection( &freetype_cs );
4755 if(plf->lfFaceName[0]) {
4756 FontSubst *psub;
4757 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4759 if(psub) {
4760 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4761 debugstr_w(psub->to.name));
4762 lf = *plf;
4763 strcpyW(lf.lfFaceName, psub->to.name);
4764 plf = &lf;
4767 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4768 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4769 if(family_matches(family, plf)) {
4770 face_list = get_face_list_from_family(family);
4771 LIST_FOR_EACH(face_elem_ptr, face_list) {
4772 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4773 if (!face_matches(family->FamilyName, face, plf)) continue;
4774 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4778 } else {
4779 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4780 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4781 face_list = get_face_list_from_family(family);
4782 face_elem_ptr = list_head(face_list);
4783 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4784 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4787 LeaveCriticalSection( &freetype_cs );
4788 return TRUE;
4791 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4793 pt->x.value = vec->x >> 6;
4794 pt->x.fract = (vec->x & 0x3f) << 10;
4795 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4796 pt->y.value = vec->y >> 6;
4797 pt->y.fract = (vec->y & 0x3f) << 10;
4798 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4799 return;
4802 /***************************************************
4803 * According to the MSDN documentation on WideCharToMultiByte,
4804 * certain codepages cannot set the default_used parameter.
4805 * This returns TRUE if the codepage can set that parameter, false else
4806 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4808 static BOOL codepage_sets_default_used(UINT codepage)
4810 switch (codepage)
4812 case CP_UTF7:
4813 case CP_UTF8:
4814 case CP_SYMBOL:
4815 return FALSE;
4816 default:
4817 return TRUE;
4822 * GSUB Table handling functions
4825 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4827 const GSUB_CoverageFormat1* cf1;
4829 cf1 = table;
4831 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4833 int count = GET_BE_WORD(cf1->GlyphCount);
4834 int i;
4835 TRACE("Coverage Format 1, %i glyphs\n",count);
4836 for (i = 0; i < count; i++)
4837 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4838 return i;
4839 return -1;
4841 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4843 const GSUB_CoverageFormat2* cf2;
4844 int i;
4845 int count;
4846 cf2 = (const GSUB_CoverageFormat2*)cf1;
4848 count = GET_BE_WORD(cf2->RangeCount);
4849 TRACE("Coverage Format 2, %i ranges\n",count);
4850 for (i = 0; i < count; i++)
4852 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4853 return -1;
4854 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4855 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4857 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4858 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4861 return -1;
4863 else
4864 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4866 return -1;
4869 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4871 const GSUB_ScriptList *script;
4872 const GSUB_Script *deflt = NULL;
4873 int i;
4874 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4876 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4877 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4879 const GSUB_Script *scr;
4880 int offset;
4882 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4883 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4885 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4886 return scr;
4887 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4888 deflt = scr;
4890 return deflt;
4893 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4895 int i;
4896 int offset;
4897 const GSUB_LangSys *Lang;
4899 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4901 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4903 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4904 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4906 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4907 return Lang;
4909 offset = GET_BE_WORD(script->DefaultLangSys);
4910 if (offset)
4912 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4913 return Lang;
4915 return NULL;
4918 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4920 int i;
4921 const GSUB_FeatureList *feature;
4922 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4924 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4925 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4927 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4928 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4930 const GSUB_Feature *feat;
4931 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4932 return feat;
4935 return NULL;
4938 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4940 int i;
4941 int offset;
4942 const GSUB_LookupList *lookup;
4943 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4945 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4946 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4948 const GSUB_LookupTable *look;
4949 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4950 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4951 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4952 if (GET_BE_WORD(look->LookupType) != 1)
4953 FIXME("We only handle SubType 1\n");
4954 else
4956 int j;
4958 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4960 const GSUB_SingleSubstFormat1 *ssf1;
4961 offset = GET_BE_WORD(look->SubTable[j]);
4962 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4963 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4965 int offset = GET_BE_WORD(ssf1->Coverage);
4966 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4967 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4969 TRACE(" Glyph 0x%x ->",glyph);
4970 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4971 TRACE(" 0x%x\n",glyph);
4974 else
4976 const GSUB_SingleSubstFormat2 *ssf2;
4977 INT index;
4978 INT offset;
4980 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4981 offset = GET_BE_WORD(ssf1->Coverage);
4982 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4983 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4984 TRACE(" Coverage index %i\n",index);
4985 if (index != -1)
4987 TRACE(" Glyph is 0x%x ->",glyph);
4988 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4989 TRACE("0x%x\n",glyph);
4995 return glyph;
4998 static const char* get_opentype_script(const GdiFont *font)
5001 * I am not sure if this is the correct way to generate our script tag
5004 switch (font->charset)
5006 case ANSI_CHARSET: return "latn";
5007 case BALTIC_CHARSET: return "latn"; /* ?? */
5008 case CHINESEBIG5_CHARSET: return "hani";
5009 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5010 case GB2312_CHARSET: return "hani";
5011 case GREEK_CHARSET: return "grek";
5012 case HANGUL_CHARSET: return "hang";
5013 case RUSSIAN_CHARSET: return "cyrl";
5014 case SHIFTJIS_CHARSET: return "kana";
5015 case TURKISH_CHARSET: return "latn"; /* ?? */
5016 case VIETNAMESE_CHARSET: return "latn";
5017 case JOHAB_CHARSET: return "latn"; /* ?? */
5018 case ARABIC_CHARSET: return "arab";
5019 case HEBREW_CHARSET: return "hebr";
5020 case THAI_CHARSET: return "thai";
5021 default: return "latn";
5025 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5027 const GSUB_Header *header;
5028 const GSUB_Script *script;
5029 const GSUB_LangSys *language;
5030 const GSUB_Feature *feature;
5032 if (!font->GSUB_Table)
5033 return glyph;
5035 header = font->GSUB_Table;
5037 script = GSUB_get_script_table(header, get_opentype_script(font));
5038 if (!script)
5040 TRACE("Script not found\n");
5041 return glyph;
5043 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5044 if (!language)
5046 TRACE("Language not found\n");
5047 return glyph;
5049 feature = GSUB_get_feature(header, language, "vrt2");
5050 if (!feature)
5051 feature = GSUB_get_feature(header, language, "vert");
5052 if (!feature)
5054 TRACE("vrt2/vert feature not found\n");
5055 return glyph;
5057 return GSUB_apply_feature(header, feature, glyph);
5060 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5062 FT_UInt glyphId;
5064 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5065 WCHAR wc = (WCHAR)glyph;
5066 BOOL default_used;
5067 BOOL *default_used_pointer;
5068 FT_UInt ret;
5069 char buf;
5070 default_used_pointer = NULL;
5071 default_used = FALSE;
5072 if (codepage_sets_default_used(font->codepage))
5073 default_used_pointer = &default_used;
5074 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5075 ret = 0;
5076 else
5077 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5078 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5079 return ret;
5082 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5084 if (glyph < 0x100) glyph += 0xf000;
5085 /* there is a number of old pre-Unicode "broken" TTFs, which
5086 do have symbols at U+00XX instead of U+f0XX */
5087 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5088 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5090 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5092 return glyphId;
5095 /*************************************************************
5096 * freetype_GetGlyphIndices
5098 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5100 struct freetype_physdev *physdev = get_freetype_dev( dev );
5101 int i;
5102 WORD default_char;
5103 BOOL got_default = FALSE;
5105 if (!physdev->font)
5107 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5108 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5111 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5113 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5114 got_default = TRUE;
5117 GDI_CheckNotLock();
5118 EnterCriticalSection( &freetype_cs );
5120 for(i = 0; i < count; i++)
5122 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5123 if (pgi[i] == 0)
5125 if (!got_default)
5127 if (FT_IS_SFNT(physdev->font->ft_face))
5129 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5130 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5132 else
5134 TEXTMETRICW textm;
5135 get_text_metrics(physdev->font, &textm);
5136 default_char = textm.tmDefaultChar;
5138 got_default = TRUE;
5140 pgi[i] = default_char;
5143 LeaveCriticalSection( &freetype_cs );
5144 return count;
5147 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5149 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5150 return !memcmp(matrix, &identity, sizeof(FMAT2));
5153 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5155 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5156 return !memcmp(matrix, &identity, sizeof(MAT2));
5159 static inline BYTE get_max_level( UINT format )
5161 switch( format )
5163 case GGO_GRAY2_BITMAP: return 4;
5164 case GGO_GRAY4_BITMAP: return 16;
5165 case GGO_GRAY8_BITMAP: return 64;
5167 return 255;
5170 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5172 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5173 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5174 const MAT2* lpmat)
5176 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5177 FT_Face ft_face = incoming_font->ft_face;
5178 GdiFont *font = incoming_font;
5179 FT_UInt glyph_index;
5180 DWORD width, height, pitch, needed = 0;
5181 FT_Bitmap ft_bitmap;
5182 FT_Error err;
5183 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5184 FT_Angle angle = 0;
5185 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5186 double widthRatio = 1.0;
5187 FT_Matrix transMat = identityMat;
5188 FT_Matrix transMatUnrotated;
5189 BOOL needsTransform = FALSE;
5190 BOOL tategaki = (font->GSUB_Table != NULL);
5191 UINT original_index;
5193 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5194 buflen, buf, lpmat);
5196 TRACE("font transform %f %f %f %f\n",
5197 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5198 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5200 if(format & GGO_GLYPH_INDEX) {
5201 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5202 original_index = glyph;
5203 format &= ~GGO_GLYPH_INDEX;
5204 } else {
5205 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5206 ft_face = font->ft_face;
5207 original_index = glyph_index;
5210 if(format & GGO_UNHINTED) {
5211 load_flags |= FT_LOAD_NO_HINTING;
5212 format &= ~GGO_UNHINTED;
5215 /* tategaki never appears to happen to lower glyph index */
5216 if (glyph_index < TATEGAKI_LOWER_BOUND )
5217 tategaki = FALSE;
5219 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5220 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5221 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5222 font->gmsize * sizeof(GM*));
5223 } else {
5224 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5225 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5227 *lpgm = FONT_GM(font,original_index)->gm;
5228 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5229 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5230 lpgm->gmCellIncX, lpgm->gmCellIncY);
5231 return 1; /* FIXME */
5235 if (!font->gm[original_index / GM_BLOCK_SIZE])
5236 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5238 /* Scaling factor */
5239 if (font->aveWidth)
5241 TEXTMETRICW tm;
5243 get_text_metrics(font, &tm);
5245 widthRatio = (double)font->aveWidth;
5246 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5248 else
5249 widthRatio = font->scale_y;
5251 /* Scaling transform */
5252 if (widthRatio != 1.0 || font->scale_y != 1.0)
5254 FT_Matrix scaleMat;
5255 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5256 scaleMat.xy = 0;
5257 scaleMat.yx = 0;
5258 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5260 pFT_Matrix_Multiply(&scaleMat, &transMat);
5261 needsTransform = TRUE;
5264 /* Slant transform */
5265 if (font->fake_italic) {
5266 FT_Matrix slantMat;
5268 slantMat.xx = (1 << 16);
5269 slantMat.xy = ((1 << 16) >> 2);
5270 slantMat.yx = 0;
5271 slantMat.yy = (1 << 16);
5272 pFT_Matrix_Multiply(&slantMat, &transMat);
5273 needsTransform = TRUE;
5276 /* Rotation transform */
5277 transMatUnrotated = transMat;
5278 if(font->orientation && !tategaki) {
5279 FT_Matrix rotationMat;
5280 FT_Vector vecAngle;
5281 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5282 pFT_Vector_Unit(&vecAngle, angle);
5283 rotationMat.xx = vecAngle.x;
5284 rotationMat.xy = -vecAngle.y;
5285 rotationMat.yx = -rotationMat.xy;
5286 rotationMat.yy = rotationMat.xx;
5288 pFT_Matrix_Multiply(&rotationMat, &transMat);
5289 needsTransform = TRUE;
5292 /* World transform */
5293 if (!is_identity_FMAT2(&font->font_desc.matrix))
5295 FT_Matrix worldMat;
5296 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5297 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5298 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5299 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5300 pFT_Matrix_Multiply(&worldMat, &transMat);
5301 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5302 needsTransform = TRUE;
5305 /* Extra transformation specified by caller */
5306 if (!is_identity_MAT2(lpmat))
5308 FT_Matrix extraMat;
5309 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5310 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5311 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5312 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5313 pFT_Matrix_Multiply(&extraMat, &transMat);
5314 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5315 needsTransform = TRUE;
5318 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5319 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5320 format == GGO_GRAY8_BITMAP))
5322 load_flags |= FT_LOAD_NO_BITMAP;
5325 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5327 if(err) {
5328 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5329 return GDI_ERROR;
5332 if(!needsTransform) {
5333 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5334 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5335 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5337 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5338 bottom = (ft_face->glyph->metrics.horiBearingY -
5339 ft_face->glyph->metrics.height) & -64;
5340 lpgm->gmCellIncX = adv;
5341 lpgm->gmCellIncY = 0;
5342 } else {
5343 INT xc, yc;
5344 FT_Vector vec;
5346 left = right = 0;
5348 for(xc = 0; xc < 2; xc++) {
5349 for(yc = 0; yc < 2; yc++) {
5350 vec.x = (ft_face->glyph->metrics.horiBearingX +
5351 xc * ft_face->glyph->metrics.width);
5352 vec.y = ft_face->glyph->metrics.horiBearingY -
5353 yc * ft_face->glyph->metrics.height;
5354 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5355 pFT_Vector_Transform(&vec, &transMat);
5356 if(xc == 0 && yc == 0) {
5357 left = right = vec.x;
5358 top = bottom = vec.y;
5359 } else {
5360 if(vec.x < left) left = vec.x;
5361 else if(vec.x > right) right = vec.x;
5362 if(vec.y < bottom) bottom = vec.y;
5363 else if(vec.y > top) top = vec.y;
5367 left = left & -64;
5368 right = (right + 63) & -64;
5369 bottom = bottom & -64;
5370 top = (top + 63) & -64;
5372 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5373 vec.x = ft_face->glyph->metrics.horiAdvance;
5374 vec.y = 0;
5375 pFT_Vector_Transform(&vec, &transMat);
5376 lpgm->gmCellIncX = (vec.x+63) >> 6;
5377 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5379 vec.x = ft_face->glyph->metrics.horiAdvance;
5380 vec.y = 0;
5381 pFT_Vector_Transform(&vec, &transMatUnrotated);
5382 adv = (vec.x+63) >> 6;
5385 lsb = left >> 6;
5386 bbx = (right - left) >> 6;
5387 lpgm->gmBlackBoxX = (right - left) >> 6;
5388 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5389 lpgm->gmptGlyphOrigin.x = left >> 6;
5390 lpgm->gmptGlyphOrigin.y = top >> 6;
5392 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5393 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5394 lpgm->gmCellIncX, lpgm->gmCellIncY);
5396 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5397 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5399 FONT_GM(font,original_index)->gm = *lpgm;
5400 FONT_GM(font,original_index)->adv = adv;
5401 FONT_GM(font,original_index)->lsb = lsb;
5402 FONT_GM(font,original_index)->bbx = bbx;
5403 FONT_GM(font,original_index)->init = TRUE;
5406 if(format == GGO_METRICS)
5408 return 1; /* FIXME */
5411 if(ft_face->glyph->format != ft_glyph_format_outline &&
5412 (format == GGO_NATIVE || format == GGO_BEZIER))
5414 TRACE("loaded a bitmap\n");
5415 return GDI_ERROR;
5418 switch(format) {
5419 case GGO_BITMAP:
5420 width = lpgm->gmBlackBoxX;
5421 height = lpgm->gmBlackBoxY;
5422 pitch = ((width + 31) >> 5) << 2;
5423 needed = pitch * height;
5425 if(!buf || !buflen) break;
5427 switch(ft_face->glyph->format) {
5428 case ft_glyph_format_bitmap:
5430 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5431 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5432 INT h = ft_face->glyph->bitmap.rows;
5433 while(h--) {
5434 memcpy(dst, src, w);
5435 src += ft_face->glyph->bitmap.pitch;
5436 dst += pitch;
5438 break;
5441 case ft_glyph_format_outline:
5442 ft_bitmap.width = width;
5443 ft_bitmap.rows = height;
5444 ft_bitmap.pitch = pitch;
5445 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5446 ft_bitmap.buffer = buf;
5448 if(needsTransform)
5449 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5451 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5453 /* Note: FreeType will only set 'black' bits for us. */
5454 memset(buf, 0, needed);
5455 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5456 break;
5458 default:
5459 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5460 return GDI_ERROR;
5462 break;
5464 case GGO_GRAY2_BITMAP:
5465 case GGO_GRAY4_BITMAP:
5466 case GGO_GRAY8_BITMAP:
5467 case WINE_GGO_GRAY16_BITMAP:
5469 unsigned int max_level, row, col;
5470 BYTE *start, *ptr;
5472 width = lpgm->gmBlackBoxX;
5473 height = lpgm->gmBlackBoxY;
5474 pitch = (width + 3) / 4 * 4;
5475 needed = pitch * height;
5477 if(!buf || !buflen) break;
5479 max_level = get_max_level( format );
5481 switch(ft_face->glyph->format) {
5482 case ft_glyph_format_bitmap:
5484 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5485 INT h = ft_face->glyph->bitmap.rows;
5486 INT x;
5487 memset( buf, 0, needed );
5488 while(h--) {
5489 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5490 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5491 src += ft_face->glyph->bitmap.pitch;
5492 dst += pitch;
5494 return needed;
5496 case ft_glyph_format_outline:
5498 ft_bitmap.width = width;
5499 ft_bitmap.rows = height;
5500 ft_bitmap.pitch = pitch;
5501 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5502 ft_bitmap.buffer = buf;
5504 if(needsTransform)
5505 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5507 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5509 memset(ft_bitmap.buffer, 0, buflen);
5511 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5513 if (max_level != 255)
5515 for (row = 0, start = buf; row < height; row++)
5517 for (col = 0, ptr = start; col < width; col++, ptr++)
5518 *ptr = (((int)*ptr) * max_level + 128) / 256;
5519 start += pitch;
5522 return needed;
5525 default:
5526 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5527 return GDI_ERROR;
5529 break;
5532 case WINE_GGO_HRGB_BITMAP:
5533 case WINE_GGO_HBGR_BITMAP:
5534 case WINE_GGO_VRGB_BITMAP:
5535 case WINE_GGO_VBGR_BITMAP:
5536 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5538 switch (ft_face->glyph->format)
5540 case FT_GLYPH_FORMAT_BITMAP:
5542 BYTE *src, *dst;
5543 INT src_pitch, x;
5545 width = lpgm->gmBlackBoxX;
5546 height = lpgm->gmBlackBoxY;
5547 pitch = width * 4;
5548 needed = pitch * height;
5550 if (!buf || !buflen) break;
5552 memset(buf, 0, buflen);
5553 dst = buf;
5554 src = ft_face->glyph->bitmap.buffer;
5555 src_pitch = ft_face->glyph->bitmap.pitch;
5557 height = min( height, ft_face->glyph->bitmap.rows );
5558 while ( height-- )
5560 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5562 if ( src[x / 8] & masks[x % 8] )
5563 ((unsigned int *)dst)[x] = ~0u;
5565 src += src_pitch;
5566 dst += pitch;
5569 break;
5572 case FT_GLYPH_FORMAT_OUTLINE:
5574 unsigned int *dst;
5575 BYTE *src;
5576 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5577 INT x_shift, y_shift;
5578 BOOL rgb;
5579 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5580 FT_Render_Mode render_mode =
5581 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5582 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5584 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5586 if ( render_mode == FT_RENDER_MODE_LCD)
5588 lpgm->gmBlackBoxX += 2;
5589 lpgm->gmptGlyphOrigin.x -= 1;
5591 else
5593 lpgm->gmBlackBoxY += 2;
5594 lpgm->gmptGlyphOrigin.y += 1;
5598 width = lpgm->gmBlackBoxX;
5599 height = lpgm->gmBlackBoxY;
5600 pitch = width * 4;
5601 needed = pitch * height;
5603 if (!buf || !buflen) break;
5605 memset(buf, 0, buflen);
5606 dst = buf;
5607 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5609 if ( needsTransform )
5610 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5612 if ( pFT_Library_SetLcdFilter )
5613 pFT_Library_SetLcdFilter( library, lcdfilter );
5614 pFT_Render_Glyph (ft_face->glyph, render_mode);
5616 src = ft_face->glyph->bitmap.buffer;
5617 src_pitch = ft_face->glyph->bitmap.pitch;
5618 src_width = ft_face->glyph->bitmap.width;
5619 src_height = ft_face->glyph->bitmap.rows;
5621 if ( render_mode == FT_RENDER_MODE_LCD)
5623 rgb_interval = 1;
5624 hmul = 3;
5625 vmul = 1;
5627 else
5629 rgb_interval = src_pitch;
5630 hmul = 1;
5631 vmul = 3;
5634 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5635 if ( x_shift < 0 ) x_shift = 0;
5636 if ( x_shift + (src_width / hmul) > width )
5637 x_shift = width - (src_width / hmul);
5639 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5640 if ( y_shift < 0 ) y_shift = 0;
5641 if ( y_shift + (src_height / vmul) > height )
5642 y_shift = height - (src_height / vmul);
5644 dst += x_shift + y_shift * ( pitch / 4 );
5645 while ( src_height )
5647 for ( x = 0; x < src_width / hmul; x++ )
5649 if ( rgb )
5651 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5652 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5653 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5654 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5656 else
5658 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5659 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5660 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5661 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5664 src += src_pitch * vmul;
5665 dst += pitch / 4;
5666 src_height -= vmul;
5669 break;
5672 default:
5673 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5674 return GDI_ERROR;
5677 break;
5679 #else
5680 return GDI_ERROR;
5681 #endif
5683 case GGO_NATIVE:
5685 int contour, point = 0, first_pt;
5686 FT_Outline *outline = &ft_face->glyph->outline;
5687 TTPOLYGONHEADER *pph;
5688 TTPOLYCURVE *ppc;
5689 DWORD pph_start, cpfx, type;
5691 if(buflen == 0) buf = NULL;
5693 if (needsTransform && buf) {
5694 pFT_Outline_Transform(outline, &transMat);
5697 for(contour = 0; contour < outline->n_contours; contour++) {
5698 pph_start = needed;
5699 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5700 first_pt = point;
5701 if(buf) {
5702 pph->dwType = TT_POLYGON_TYPE;
5703 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5705 needed += sizeof(*pph);
5706 point++;
5707 while(point <= outline->contours[contour]) {
5708 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5709 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5710 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5711 cpfx = 0;
5712 do {
5713 if(buf)
5714 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5715 cpfx++;
5716 point++;
5717 } while(point <= outline->contours[contour] &&
5718 (outline->tags[point] & FT_Curve_Tag_On) ==
5719 (outline->tags[point-1] & FT_Curve_Tag_On));
5720 /* At the end of a contour Windows adds the start point, but
5721 only for Beziers */
5722 if(point > outline->contours[contour] &&
5723 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5724 if(buf)
5725 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5726 cpfx++;
5727 } else if(point <= outline->contours[contour] &&
5728 outline->tags[point] & FT_Curve_Tag_On) {
5729 /* add closing pt for bezier */
5730 if(buf)
5731 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5732 cpfx++;
5733 point++;
5735 if(buf) {
5736 ppc->wType = type;
5737 ppc->cpfx = cpfx;
5739 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5741 if(buf)
5742 pph->cb = needed - pph_start;
5744 break;
5746 case GGO_BEZIER:
5748 /* Convert the quadratic Beziers to cubic Beziers.
5749 The parametric eqn for a cubic Bezier is, from PLRM:
5750 r(t) = at^3 + bt^2 + ct + r0
5751 with the control points:
5752 r1 = r0 + c/3
5753 r2 = r1 + (c + b)/3
5754 r3 = r0 + c + b + a
5756 A quadratic Bezier has the form:
5757 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5759 So equating powers of t leads to:
5760 r1 = 2/3 p1 + 1/3 p0
5761 r2 = 2/3 p1 + 1/3 p2
5762 and of course r0 = p0, r3 = p2
5765 int contour, point = 0, first_pt;
5766 FT_Outline *outline = &ft_face->glyph->outline;
5767 TTPOLYGONHEADER *pph;
5768 TTPOLYCURVE *ppc;
5769 DWORD pph_start, cpfx, type;
5770 FT_Vector cubic_control[4];
5771 if(buflen == 0) buf = NULL;
5773 if (needsTransform && buf) {
5774 pFT_Outline_Transform(outline, &transMat);
5777 for(contour = 0; contour < outline->n_contours; contour++) {
5778 pph_start = needed;
5779 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5780 first_pt = point;
5781 if(buf) {
5782 pph->dwType = TT_POLYGON_TYPE;
5783 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5785 needed += sizeof(*pph);
5786 point++;
5787 while(point <= outline->contours[contour]) {
5788 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5789 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5790 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5791 cpfx = 0;
5792 do {
5793 if(type == TT_PRIM_LINE) {
5794 if(buf)
5795 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5796 cpfx++;
5797 point++;
5798 } else {
5799 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5800 so cpfx = 3n */
5802 /* FIXME: Possible optimization in endpoint calculation
5803 if there are two consecutive curves */
5804 cubic_control[0] = outline->points[point-1];
5805 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5806 cubic_control[0].x += outline->points[point].x + 1;
5807 cubic_control[0].y += outline->points[point].y + 1;
5808 cubic_control[0].x >>= 1;
5809 cubic_control[0].y >>= 1;
5811 if(point+1 > outline->contours[contour])
5812 cubic_control[3] = outline->points[first_pt];
5813 else {
5814 cubic_control[3] = outline->points[point+1];
5815 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5816 cubic_control[3].x += outline->points[point].x + 1;
5817 cubic_control[3].y += outline->points[point].y + 1;
5818 cubic_control[3].x >>= 1;
5819 cubic_control[3].y >>= 1;
5822 /* r1 = 1/3 p0 + 2/3 p1
5823 r2 = 1/3 p2 + 2/3 p1 */
5824 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5825 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5826 cubic_control[2] = cubic_control[1];
5827 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5828 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5829 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5830 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5831 if(buf) {
5832 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5833 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5834 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5836 cpfx += 3;
5837 point++;
5839 } while(point <= outline->contours[contour] &&
5840 (outline->tags[point] & FT_Curve_Tag_On) ==
5841 (outline->tags[point-1] & FT_Curve_Tag_On));
5842 /* At the end of a contour Windows adds the start point,
5843 but only for Beziers and we've already done that.
5845 if(point <= outline->contours[contour] &&
5846 outline->tags[point] & FT_Curve_Tag_On) {
5847 /* This is the closing pt of a bezier, but we've already
5848 added it, so just inc point and carry on */
5849 point++;
5851 if(buf) {
5852 ppc->wType = type;
5853 ppc->cpfx = cpfx;
5855 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5857 if(buf)
5858 pph->cb = needed - pph_start;
5860 break;
5863 default:
5864 FIXME("Unsupported format %d\n", format);
5865 return GDI_ERROR;
5867 return needed;
5870 static BOOL get_bitmap_text_metrics(GdiFont *font)
5872 FT_Face ft_face = font->ft_face;
5873 FT_WinFNT_HeaderRec winfnt_header;
5874 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5875 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5876 font->potm->otmSize = size;
5878 #define TM font->potm->otmTextMetrics
5879 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5881 TM.tmHeight = winfnt_header.pixel_height;
5882 TM.tmAscent = winfnt_header.ascent;
5883 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5884 TM.tmInternalLeading = winfnt_header.internal_leading;
5885 TM.tmExternalLeading = winfnt_header.external_leading;
5886 TM.tmAveCharWidth = winfnt_header.avg_width;
5887 TM.tmMaxCharWidth = winfnt_header.max_width;
5888 TM.tmWeight = winfnt_header.weight;
5889 TM.tmOverhang = 0;
5890 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5891 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5892 TM.tmFirstChar = winfnt_header.first_char;
5893 TM.tmLastChar = winfnt_header.last_char;
5894 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5895 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5896 TM.tmItalic = winfnt_header.italic;
5897 TM.tmUnderlined = font->underline;
5898 TM.tmStruckOut = font->strikeout;
5899 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5900 TM.tmCharSet = winfnt_header.charset;
5902 else
5904 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5905 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5906 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5907 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5908 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5909 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5910 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5911 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5912 TM.tmOverhang = 0;
5913 TM.tmDigitizedAspectX = 96; /* FIXME */
5914 TM.tmDigitizedAspectY = 96; /* FIXME */
5915 TM.tmFirstChar = 1;
5916 TM.tmLastChar = 255;
5917 TM.tmDefaultChar = 32;
5918 TM.tmBreakChar = 32;
5919 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5920 TM.tmUnderlined = font->underline;
5921 TM.tmStruckOut = font->strikeout;
5922 /* NB inverted meaning of TMPF_FIXED_PITCH */
5923 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5924 TM.tmCharSet = font->charset;
5926 #undef TM
5928 return TRUE;
5932 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5934 double scale_x, scale_y;
5936 if (font->aveWidth)
5938 scale_x = (double)font->aveWidth;
5939 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5941 else
5942 scale_x = font->scale_y;
5944 scale_x *= fabs(font->font_desc.matrix.eM11);
5945 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5947 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5948 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5950 SCALE_Y(ptm->tmHeight);
5951 SCALE_Y(ptm->tmAscent);
5952 SCALE_Y(ptm->tmDescent);
5953 SCALE_Y(ptm->tmInternalLeading);
5954 SCALE_Y(ptm->tmExternalLeading);
5955 SCALE_Y(ptm->tmOverhang);
5957 SCALE_X(ptm->tmAveCharWidth);
5958 SCALE_X(ptm->tmMaxCharWidth);
5960 #undef SCALE_X
5961 #undef SCALE_Y
5964 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5966 double scale_x, scale_y;
5968 if (font->aveWidth)
5970 scale_x = (double)font->aveWidth;
5971 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5973 else
5974 scale_x = font->scale_y;
5976 scale_x *= fabs(font->font_desc.matrix.eM11);
5977 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5979 scale_font_metrics(font, &potm->otmTextMetrics);
5981 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5982 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5984 SCALE_Y(potm->otmAscent);
5985 SCALE_Y(potm->otmDescent);
5986 SCALE_Y(potm->otmLineGap);
5987 SCALE_Y(potm->otmsCapEmHeight);
5988 SCALE_Y(potm->otmsXHeight);
5989 SCALE_Y(potm->otmrcFontBox.top);
5990 SCALE_Y(potm->otmrcFontBox.bottom);
5991 SCALE_X(potm->otmrcFontBox.left);
5992 SCALE_X(potm->otmrcFontBox.right);
5993 SCALE_Y(potm->otmMacAscent);
5994 SCALE_Y(potm->otmMacDescent);
5995 SCALE_Y(potm->otmMacLineGap);
5996 SCALE_X(potm->otmptSubscriptSize.x);
5997 SCALE_Y(potm->otmptSubscriptSize.y);
5998 SCALE_X(potm->otmptSubscriptOffset.x);
5999 SCALE_Y(potm->otmptSubscriptOffset.y);
6000 SCALE_X(potm->otmptSuperscriptSize.x);
6001 SCALE_Y(potm->otmptSuperscriptSize.y);
6002 SCALE_X(potm->otmptSuperscriptOffset.x);
6003 SCALE_Y(potm->otmptSuperscriptOffset.y);
6004 SCALE_Y(potm->otmsStrikeoutSize);
6005 SCALE_Y(potm->otmsStrikeoutPosition);
6006 SCALE_Y(potm->otmsUnderscoreSize);
6007 SCALE_Y(potm->otmsUnderscorePosition);
6009 #undef SCALE_X
6010 #undef SCALE_Y
6013 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6015 if(!font->potm)
6017 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6019 /* Make sure that the font has sane width/height ratio */
6020 if (font->aveWidth)
6022 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6024 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6025 font->aveWidth = 0;
6029 *ptm = font->potm->otmTextMetrics;
6030 scale_font_metrics(font, ptm);
6031 return TRUE;
6034 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6036 int i;
6038 for(i = 0; i < ft_face->num_charmaps; i++)
6040 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6041 return TRUE;
6043 return FALSE;
6046 static BOOL get_outline_text_metrics(GdiFont *font)
6048 BOOL ret = FALSE;
6049 FT_Face ft_face = font->ft_face;
6050 UINT needed, lenfam, lensty;
6051 TT_OS2 *pOS2;
6052 TT_HoriHeader *pHori;
6053 TT_Postscript *pPost;
6054 FT_Fixed x_scale, y_scale;
6055 WCHAR *family_nameW, *style_nameW;
6056 static const WCHAR spaceW[] = {' ', '\0'};
6057 char *cp;
6058 INT ascent, descent;
6060 TRACE("font=%p\n", font);
6062 if(!FT_IS_SCALABLE(ft_face))
6063 return FALSE;
6065 needed = sizeof(*font->potm);
6067 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6068 family_nameW = strdupW(font->name);
6070 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6071 * sizeof(WCHAR);
6072 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6073 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6074 style_nameW, lensty/sizeof(WCHAR));
6076 /* These names should be read from the TT name table */
6078 /* length of otmpFamilyName */
6079 needed += lenfam;
6081 /* length of otmpFaceName */
6082 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6083 needed += lenfam; /* just the family name */
6084 } else {
6085 needed += lenfam + lensty; /* family + " " + style */
6088 /* length of otmpStyleName */
6089 needed += lensty;
6091 /* length of otmpFullName */
6092 needed += lenfam + lensty;
6095 x_scale = ft_face->size->metrics.x_scale;
6096 y_scale = ft_face->size->metrics.y_scale;
6098 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6099 if(!pOS2) {
6100 FIXME("Can't find OS/2 table - not TT font?\n");
6101 goto end;
6104 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6105 if(!pHori) {
6106 FIXME("Can't find HHEA table - not TT font?\n");
6107 goto end;
6110 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6112 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",
6113 pOS2->usWinAscent, pOS2->usWinDescent,
6114 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6115 ft_face->ascender, ft_face->descender, ft_face->height,
6116 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6117 ft_face->bbox.yMax, ft_face->bbox.yMin);
6119 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6120 font->potm->otmSize = needed;
6122 #define TM font->potm->otmTextMetrics
6124 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6125 ascent = pHori->Ascender;
6126 descent = -pHori->Descender;
6127 } else {
6128 ascent = pOS2->usWinAscent;
6129 descent = pOS2->usWinDescent;
6132 if(font->yMax) {
6133 TM.tmAscent = font->yMax;
6134 TM.tmDescent = -font->yMin;
6135 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6136 } else {
6137 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6138 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6139 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6140 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6143 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6145 /* MSDN says:
6146 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6148 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6149 ((ascent + descent) -
6150 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6152 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6153 if (TM.tmAveCharWidth == 0) {
6154 TM.tmAveCharWidth = 1;
6156 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6157 TM.tmWeight = FW_REGULAR;
6158 if (font->fake_bold)
6159 TM.tmWeight = FW_BOLD;
6160 else
6162 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6164 if (pOS2->usWeightClass > FW_MEDIUM)
6165 TM.tmWeight = pOS2->usWeightClass;
6167 else if (pOS2->usWeightClass <= FW_MEDIUM)
6168 TM.tmWeight = pOS2->usWeightClass;
6170 TM.tmOverhang = 0;
6171 TM.tmDigitizedAspectX = 300;
6172 TM.tmDigitizedAspectY = 300;
6173 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6174 * symbol range to 0 - f0ff
6177 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6179 TM.tmFirstChar = 0;
6180 switch(GetACP())
6182 case 1257: /* Baltic */
6183 TM.tmLastChar = 0xf8fd;
6184 break;
6185 default:
6186 TM.tmLastChar = 0xf0ff;
6188 TM.tmBreakChar = 0x20;
6189 TM.tmDefaultChar = 0x1f;
6191 else
6193 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6194 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6196 if(pOS2->usFirstCharIndex <= 1)
6197 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6198 else if (pOS2->usFirstCharIndex > 0xff)
6199 TM.tmBreakChar = 0x20;
6200 else
6201 TM.tmBreakChar = pOS2->usFirstCharIndex;
6202 TM.tmDefaultChar = TM.tmBreakChar - 1;
6204 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6205 TM.tmUnderlined = font->underline;
6206 TM.tmStruckOut = font->strikeout;
6208 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6209 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6210 (pOS2->version == 0xFFFFU ||
6211 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6212 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6213 else
6214 TM.tmPitchAndFamily = 0;
6216 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6218 case PAN_FAMILY_SCRIPT:
6219 TM.tmPitchAndFamily |= FF_SCRIPT;
6220 break;
6222 case PAN_FAMILY_DECORATIVE:
6223 TM.tmPitchAndFamily |= FF_DECORATIVE;
6224 break;
6226 case PAN_ANY:
6227 case PAN_NO_FIT:
6228 case PAN_FAMILY_TEXT_DISPLAY:
6229 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6230 /* which is clearly not what the panose spec says. */
6231 default:
6232 if(TM.tmPitchAndFamily == 0 || /* fixed */
6233 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6234 TM.tmPitchAndFamily = FF_MODERN;
6235 else
6237 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6239 case PAN_ANY:
6240 case PAN_NO_FIT:
6241 default:
6242 TM.tmPitchAndFamily |= FF_DONTCARE;
6243 break;
6245 case PAN_SERIF_COVE:
6246 case PAN_SERIF_OBTUSE_COVE:
6247 case PAN_SERIF_SQUARE_COVE:
6248 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6249 case PAN_SERIF_SQUARE:
6250 case PAN_SERIF_THIN:
6251 case PAN_SERIF_BONE:
6252 case PAN_SERIF_EXAGGERATED:
6253 case PAN_SERIF_TRIANGLE:
6254 TM.tmPitchAndFamily |= FF_ROMAN;
6255 break;
6257 case PAN_SERIF_NORMAL_SANS:
6258 case PAN_SERIF_OBTUSE_SANS:
6259 case PAN_SERIF_PERP_SANS:
6260 case PAN_SERIF_FLARED:
6261 case PAN_SERIF_ROUNDED:
6262 TM.tmPitchAndFamily |= FF_SWISS;
6263 break;
6266 break;
6269 if(FT_IS_SCALABLE(ft_face))
6270 TM.tmPitchAndFamily |= TMPF_VECTOR;
6272 if(FT_IS_SFNT(ft_face))
6274 if (font->ntmFlags & NTM_PS_OPENTYPE)
6275 TM.tmPitchAndFamily |= TMPF_DEVICE;
6276 else
6277 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6280 TM.tmCharSet = font->charset;
6282 font->potm->otmFiller = 0;
6283 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6284 font->potm->otmfsSelection = pOS2->fsSelection;
6285 font->potm->otmfsType = pOS2->fsType;
6286 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6287 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6288 font->potm->otmItalicAngle = 0; /* POST table */
6289 font->potm->otmEMSquare = ft_face->units_per_EM;
6290 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6291 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6292 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6293 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6294 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6295 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6296 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6297 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6298 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6299 font->potm->otmMacAscent = TM.tmAscent;
6300 font->potm->otmMacDescent = -TM.tmDescent;
6301 font->potm->otmMacLineGap = font->potm->otmLineGap;
6302 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6303 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6304 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6305 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6306 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6307 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6308 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6309 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6310 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6311 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6312 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6313 if(!pPost) {
6314 font->potm->otmsUnderscoreSize = 0;
6315 font->potm->otmsUnderscorePosition = 0;
6316 } else {
6317 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6318 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6320 #undef TM
6322 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6323 cp = (char*)font->potm + sizeof(*font->potm);
6324 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6325 strcpyW((WCHAR*)cp, family_nameW);
6326 cp += lenfam;
6327 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6328 strcpyW((WCHAR*)cp, style_nameW);
6329 cp += lensty;
6330 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6331 strcpyW((WCHAR*)cp, family_nameW);
6332 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6333 strcatW((WCHAR*)cp, spaceW);
6334 strcatW((WCHAR*)cp, style_nameW);
6335 cp += lenfam + lensty;
6336 } else
6337 cp += lenfam;
6338 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6339 strcpyW((WCHAR*)cp, family_nameW);
6340 strcatW((WCHAR*)cp, spaceW);
6341 strcatW((WCHAR*)cp, style_nameW);
6342 ret = TRUE;
6344 end:
6345 HeapFree(GetProcessHeap(), 0, style_nameW);
6346 HeapFree(GetProcessHeap(), 0, family_nameW);
6347 return ret;
6350 /*************************************************************
6351 * freetype_GetGlyphOutline
6353 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6354 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6356 struct freetype_physdev *physdev = get_freetype_dev( dev );
6357 DWORD ret;
6359 if (!physdev->font)
6361 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6362 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6365 GDI_CheckNotLock();
6366 EnterCriticalSection( &freetype_cs );
6367 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6368 LeaveCriticalSection( &freetype_cs );
6369 return ret;
6372 /*************************************************************
6373 * freetype_GetTextMetrics
6375 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6377 struct freetype_physdev *physdev = get_freetype_dev( dev );
6378 BOOL ret;
6380 if (!physdev->font)
6382 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6383 return dev->funcs->pGetTextMetrics( dev, metrics );
6386 GDI_CheckNotLock();
6387 EnterCriticalSection( &freetype_cs );
6388 ret = get_text_metrics( physdev->font, metrics );
6389 LeaveCriticalSection( &freetype_cs );
6390 return ret;
6393 /*************************************************************
6394 * freetype_GetOutlineTextMetrics
6396 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6398 struct freetype_physdev *physdev = get_freetype_dev( dev );
6399 UINT ret = 0;
6401 if (!physdev->font)
6403 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6404 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6407 TRACE("font=%p\n", physdev->font);
6409 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6411 GDI_CheckNotLock();
6412 EnterCriticalSection( &freetype_cs );
6414 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6416 if(cbSize >= physdev->font->potm->otmSize)
6418 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6419 scale_outline_font_metrics(physdev->font, potm);
6421 ret = physdev->font->potm->otmSize;
6423 LeaveCriticalSection( &freetype_cs );
6424 return ret;
6427 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6429 HFONTLIST *hfontlist;
6430 child->font = alloc_font();
6431 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6432 if(!child->font->ft_face)
6434 free_font(child->font);
6435 child->font = NULL;
6436 return FALSE;
6439 child->font->font_desc = font->font_desc;
6440 child->font->ntmFlags = child->face->ntmFlags;
6441 child->font->orientation = font->orientation;
6442 child->font->scale_y = font->scale_y;
6443 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6444 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6445 child->font->name = strdupW(child->face->family->FamilyName);
6446 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6447 child->font->base_font = font;
6448 list_add_head(&child_font_list, &child->font->entry);
6449 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6450 return TRUE;
6453 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6455 FT_UInt g;
6456 CHILD_FONT *child_font;
6458 if(font->base_font)
6459 font = font->base_font;
6461 *linked_font = font;
6463 if((*glyph = get_glyph_index(font, c)))
6465 *glyph = get_GSUB_vert_glyph(font, *glyph);
6466 return TRUE;
6469 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6471 if(!child_font->font)
6472 if(!load_child_font(font, child_font))
6473 continue;
6475 if(!child_font->font->ft_face)
6476 continue;
6477 g = get_glyph_index(child_font->font, c);
6478 g = get_GSUB_vert_glyph(child_font->font, g);
6479 if(g)
6481 *glyph = g;
6482 *linked_font = child_font->font;
6483 return TRUE;
6486 return FALSE;
6489 /*************************************************************
6490 * freetype_GetCharWidth
6492 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6494 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6495 UINT c;
6496 GLYPHMETRICS gm;
6497 FT_UInt glyph_index;
6498 GdiFont *linked_font;
6499 struct freetype_physdev *physdev = get_freetype_dev( dev );
6501 if (!physdev->font)
6503 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6504 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6507 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6509 GDI_CheckNotLock();
6510 EnterCriticalSection( &freetype_cs );
6511 for(c = firstChar; c <= lastChar; c++) {
6512 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6513 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6514 &gm, 0, NULL, &identity);
6515 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6517 LeaveCriticalSection( &freetype_cs );
6518 return TRUE;
6521 /*************************************************************
6522 * freetype_GetCharABCWidths
6524 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6526 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6527 UINT c;
6528 GLYPHMETRICS gm;
6529 FT_UInt glyph_index;
6530 GdiFont *linked_font;
6531 struct freetype_physdev *physdev = get_freetype_dev( dev );
6533 if (!physdev->font)
6535 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6536 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6539 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6541 GDI_CheckNotLock();
6542 EnterCriticalSection( &freetype_cs );
6544 for(c = firstChar; c <= lastChar; c++) {
6545 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6546 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6547 &gm, 0, NULL, &identity);
6548 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6549 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6550 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6551 FONT_GM(linked_font,glyph_index)->bbx;
6553 LeaveCriticalSection( &freetype_cs );
6554 return TRUE;
6557 /*************************************************************
6558 * freetype_GetCharABCWidthsI
6560 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6562 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6563 UINT c;
6564 GLYPHMETRICS gm;
6565 FT_UInt glyph_index;
6566 GdiFont *linked_font;
6567 struct freetype_physdev *physdev = get_freetype_dev( dev );
6569 if (!physdev->font)
6571 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6572 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6575 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6576 return FALSE;
6578 GDI_CheckNotLock();
6579 EnterCriticalSection( &freetype_cs );
6581 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6582 if (!pgi)
6583 for(c = firstChar; c < firstChar+count; c++) {
6584 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6585 &gm, 0, NULL, &identity);
6586 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6587 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6588 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6589 - FONT_GM(linked_font,c)->bbx;
6591 else
6592 for(c = 0; c < count; c++) {
6593 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6594 &gm, 0, NULL, &identity);
6595 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6596 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6597 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6598 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6601 LeaveCriticalSection( &freetype_cs );
6602 return TRUE;
6605 /*************************************************************
6606 * freetype_GetTextExtentExPoint
6608 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6609 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6611 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6612 INT idx;
6613 INT nfit = 0, ext;
6614 GLYPHMETRICS gm;
6615 TEXTMETRICW tm;
6616 FT_UInt glyph_index;
6617 GdiFont *linked_font;
6618 struct freetype_physdev *physdev = get_freetype_dev( dev );
6620 if (!physdev->font)
6622 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6623 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6626 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6628 GDI_CheckNotLock();
6629 EnterCriticalSection( &freetype_cs );
6631 size->cx = 0;
6632 get_text_metrics( physdev->font, &tm );
6633 size->cy = tm.tmHeight;
6635 for(idx = 0; idx < count; idx++) {
6636 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6637 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6638 &gm, 0, NULL, &identity);
6639 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6640 ext = size->cx;
6641 if (! pnfit || ext <= max_ext) {
6642 ++nfit;
6643 if (dxs)
6644 dxs[idx] = ext;
6648 if (pnfit)
6649 *pnfit = nfit;
6651 LeaveCriticalSection( &freetype_cs );
6652 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6653 return TRUE;
6656 /*************************************************************
6657 * freetype_GetTextExtentExPointI
6659 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6660 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6662 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6663 INT idx;
6664 INT nfit = 0, ext;
6665 GLYPHMETRICS gm;
6666 TEXTMETRICW tm;
6667 struct freetype_physdev *physdev = get_freetype_dev( dev );
6669 if (!physdev->font)
6671 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6672 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6675 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6677 GDI_CheckNotLock();
6678 EnterCriticalSection( &freetype_cs );
6680 size->cx = 0;
6681 get_text_metrics(physdev->font, &tm);
6682 size->cy = tm.tmHeight;
6684 for(idx = 0; idx < count; idx++) {
6685 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6686 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6687 ext = size->cx;
6688 if (! pnfit || ext <= max_ext) {
6689 ++nfit;
6690 if (dxs)
6691 dxs[idx] = ext;
6695 if (pnfit)
6696 *pnfit = nfit;
6698 LeaveCriticalSection( &freetype_cs );
6699 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6700 return TRUE;
6703 /*************************************************************
6704 * freetype_GetFontData
6706 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6708 struct freetype_physdev *physdev = get_freetype_dev( dev );
6710 if (!physdev->font)
6712 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6713 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6716 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6717 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6718 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6720 return get_font_data( physdev->font, table, offset, buf, cbData );
6723 /*************************************************************
6724 * freetype_GetTextFace
6726 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6728 INT n;
6729 struct freetype_physdev *physdev = get_freetype_dev( dev );
6731 if (!physdev->font)
6733 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6734 return dev->funcs->pGetTextFace( dev, count, str );
6737 n = strlenW(physdev->font->name) + 1;
6738 if (str)
6740 lstrcpynW(str, physdev->font->name, count);
6741 n = min(count, n);
6743 return n;
6746 /*************************************************************
6747 * freetype_GetTextCharsetInfo
6749 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6751 struct freetype_physdev *physdev = get_freetype_dev( dev );
6753 if (!physdev->font)
6755 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6756 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6758 if (fs) *fs = physdev->font->fs;
6759 return physdev->font->charset;
6762 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6764 GdiFont *font = dc->gdiFont, *linked_font;
6765 struct list *first_hfont;
6766 BOOL ret;
6768 GDI_CheckNotLock();
6769 EnterCriticalSection( &freetype_cs );
6770 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6771 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6772 if(font == linked_font)
6773 *new_hfont = dc->hFont;
6774 else
6776 first_hfont = list_head(&linked_font->hfontlist);
6777 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6779 LeaveCriticalSection( &freetype_cs );
6780 return ret;
6783 /* Retrieve a list of supported Unicode ranges for a given font.
6784 * Can be called with NULL gs to calculate the buffer size. Returns
6785 * the number of ranges found.
6787 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6789 DWORD num_ranges = 0;
6791 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6793 FT_UInt glyph_code;
6794 FT_ULong char_code, char_code_prev;
6796 glyph_code = 0;
6797 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6799 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6800 face->num_glyphs, glyph_code, char_code);
6802 if (!glyph_code) return 0;
6804 if (gs)
6806 gs->ranges[0].wcLow = (USHORT)char_code;
6807 gs->ranges[0].cGlyphs = 0;
6808 gs->cGlyphsSupported = 0;
6811 num_ranges = 1;
6812 while (glyph_code)
6814 if (char_code < char_code_prev)
6816 ERR("expected increasing char code from FT_Get_Next_Char\n");
6817 return 0;
6819 if (char_code - char_code_prev > 1)
6821 num_ranges++;
6822 if (gs)
6824 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6825 gs->ranges[num_ranges - 1].cGlyphs = 1;
6826 gs->cGlyphsSupported++;
6829 else if (gs)
6831 gs->ranges[num_ranges - 1].cGlyphs++;
6832 gs->cGlyphsSupported++;
6834 char_code_prev = char_code;
6835 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6838 else
6839 FIXME("encoding %u not supported\n", face->charmap->encoding);
6841 return num_ranges;
6844 /*************************************************************
6845 * freetype_GetFontUnicodeRanges
6847 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6849 struct freetype_physdev *physdev = get_freetype_dev( dev );
6850 DWORD size, num_ranges;
6852 if (!physdev->font)
6854 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6855 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6858 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6859 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6860 if (glyphset)
6862 glyphset->cbThis = size;
6863 glyphset->cRanges = num_ranges;
6864 glyphset->flAccel = 0;
6866 return size;
6869 /*************************************************************
6870 * freetype_FontIsLinked
6872 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6874 struct freetype_physdev *physdev = get_freetype_dev( dev );
6875 BOOL ret;
6877 if (!physdev->font)
6879 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6880 return dev->funcs->pFontIsLinked( dev );
6883 GDI_CheckNotLock();
6884 EnterCriticalSection( &freetype_cs );
6885 ret = !list_empty(&physdev->font->child_fonts);
6886 LeaveCriticalSection( &freetype_cs );
6887 return ret;
6890 static BOOL is_hinting_enabled(void)
6892 /* Use the >= 2.2.0 function if available */
6893 if(pFT_Get_TrueType_Engine_Type)
6895 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6896 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6898 #ifdef FT_DRIVER_HAS_HINTER
6899 else
6901 FT_Module mod;
6903 /* otherwise if we've been compiled with < 2.2.0 headers
6904 use the internal macro */
6905 mod = pFT_Get_Module(library, "truetype");
6906 if(mod && FT_DRIVER_HAS_HINTER(mod))
6907 return TRUE;
6909 #endif
6911 return FALSE;
6914 static BOOL is_subpixel_rendering_enabled( void )
6916 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6917 return pFT_Library_SetLcdFilter &&
6918 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6919 #else
6920 return FALSE;
6921 #endif
6924 /*************************************************************************
6925 * GetRasterizerCaps (GDI32.@)
6927 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6929 static int hinting = -1;
6930 static int subpixel = -1;
6932 if(hinting == -1)
6934 hinting = is_hinting_enabled();
6935 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6938 if ( subpixel == -1 )
6940 subpixel = is_subpixel_rendering_enabled();
6941 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6944 lprs->nSize = sizeof(RASTERIZER_STATUS);
6945 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6946 if ( subpixel )
6947 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6948 lprs->nLanguageID = 0;
6949 return TRUE;
6952 /*************************************************************
6953 * freetype_GdiRealizationInfo
6955 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6957 struct freetype_physdev *physdev = get_freetype_dev( dev );
6958 realization_info_t *info = ptr;
6960 if (!physdev->font)
6962 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6963 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6966 FIXME("(%p, %p): stub!\n", physdev->font, info);
6968 info->flags = 1;
6969 if(FT_IS_SCALABLE(physdev->font->ft_face))
6970 info->flags |= 2;
6972 info->cache_num = physdev->font->cache_num;
6973 info->unknown2 = -1;
6974 return TRUE;
6977 /*************************************************************************
6978 * Kerning support for TrueType fonts
6980 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6982 struct TT_kern_table
6984 USHORT version;
6985 USHORT nTables;
6988 struct TT_kern_subtable
6990 USHORT version;
6991 USHORT length;
6992 union
6994 USHORT word;
6995 struct
6997 USHORT horizontal : 1;
6998 USHORT minimum : 1;
6999 USHORT cross_stream: 1;
7000 USHORT override : 1;
7001 USHORT reserved1 : 4;
7002 USHORT format : 8;
7003 } bits;
7004 } coverage;
7007 struct TT_format0_kern_subtable
7009 USHORT nPairs;
7010 USHORT searchRange;
7011 USHORT entrySelector;
7012 USHORT rangeShift;
7015 struct TT_kern_pair
7017 USHORT left;
7018 USHORT right;
7019 short value;
7022 static DWORD parse_format0_kern_subtable(GdiFont *font,
7023 const struct TT_format0_kern_subtable *tt_f0_ks,
7024 const USHORT *glyph_to_char,
7025 KERNINGPAIR *kern_pair, DWORD cPairs)
7027 USHORT i, nPairs;
7028 const struct TT_kern_pair *tt_kern_pair;
7030 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7032 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7034 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7035 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7036 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7038 if (!kern_pair || !cPairs)
7039 return nPairs;
7041 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7043 nPairs = min(nPairs, cPairs);
7045 for (i = 0; i < nPairs; i++)
7047 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7048 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7049 /* this algorithm appears to better match what Windows does */
7050 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7051 if (kern_pair->iKernAmount < 0)
7053 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7054 kern_pair->iKernAmount -= font->ppem;
7056 else if (kern_pair->iKernAmount > 0)
7058 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7059 kern_pair->iKernAmount += font->ppem;
7061 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7063 TRACE("left %u right %u value %d\n",
7064 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7066 kern_pair++;
7068 TRACE("copied %u entries\n", nPairs);
7069 return nPairs;
7072 /*************************************************************
7073 * freetype_GetKerningPairs
7075 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7077 DWORD length;
7078 void *buf;
7079 const struct TT_kern_table *tt_kern_table;
7080 const struct TT_kern_subtable *tt_kern_subtable;
7081 USHORT i, nTables;
7082 USHORT *glyph_to_char;
7083 GdiFont *font;
7084 struct freetype_physdev *physdev = get_freetype_dev( dev );
7086 if (!(font = physdev->font))
7088 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7089 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7092 GDI_CheckNotLock();
7093 EnterCriticalSection( &freetype_cs );
7094 if (font->total_kern_pairs != (DWORD)-1)
7096 if (cPairs && kern_pair)
7098 cPairs = min(cPairs, font->total_kern_pairs);
7099 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7101 else cPairs = font->total_kern_pairs;
7103 LeaveCriticalSection( &freetype_cs );
7104 return cPairs;
7107 font->total_kern_pairs = 0;
7109 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7111 if (length == GDI_ERROR)
7113 TRACE("no kerning data in the font\n");
7114 LeaveCriticalSection( &freetype_cs );
7115 return 0;
7118 buf = HeapAlloc(GetProcessHeap(), 0, length);
7119 if (!buf)
7121 WARN("Out of memory\n");
7122 LeaveCriticalSection( &freetype_cs );
7123 return 0;
7126 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7128 /* build a glyph index to char code map */
7129 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7130 if (!glyph_to_char)
7132 WARN("Out of memory allocating a glyph index to char code map\n");
7133 HeapFree(GetProcessHeap(), 0, buf);
7134 LeaveCriticalSection( &freetype_cs );
7135 return 0;
7138 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7140 FT_UInt glyph_code;
7141 FT_ULong char_code;
7143 glyph_code = 0;
7144 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7146 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7147 font->ft_face->num_glyphs, glyph_code, char_code);
7149 while (glyph_code)
7151 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7153 /* FIXME: This doesn't match what Windows does: it does some fancy
7154 * things with duplicate glyph index to char code mappings, while
7155 * we just avoid overriding existing entries.
7157 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7158 glyph_to_char[glyph_code] = (USHORT)char_code;
7160 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7163 else
7165 ULONG n;
7167 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7168 for (n = 0; n <= 65535; n++)
7169 glyph_to_char[n] = (USHORT)n;
7172 tt_kern_table = buf;
7173 nTables = GET_BE_WORD(tt_kern_table->nTables);
7174 TRACE("version %u, nTables %u\n",
7175 GET_BE_WORD(tt_kern_table->version), nTables);
7177 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7179 for (i = 0; i < nTables; i++)
7181 struct TT_kern_subtable tt_kern_subtable_copy;
7183 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7184 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7185 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7187 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7188 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7189 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7191 /* According to the TrueType specification this is the only format
7192 * that will be properly interpreted by Windows and OS/2
7194 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7196 DWORD new_chunk, old_total = font->total_kern_pairs;
7198 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7199 glyph_to_char, NULL, 0);
7200 font->total_kern_pairs += new_chunk;
7202 if (!font->kern_pairs)
7203 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7204 font->total_kern_pairs * sizeof(*font->kern_pairs));
7205 else
7206 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7207 font->total_kern_pairs * sizeof(*font->kern_pairs));
7209 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7210 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7212 else
7213 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7215 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7218 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7219 HeapFree(GetProcessHeap(), 0, buf);
7221 if (cPairs && kern_pair)
7223 cPairs = min(cPairs, font->total_kern_pairs);
7224 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7226 else cPairs = font->total_kern_pairs;
7228 LeaveCriticalSection( &freetype_cs );
7229 return cPairs;
7232 static const struct gdi_dc_funcs freetype_funcs =
7234 NULL, /* pAbortDoc */
7235 NULL, /* pAbortPath */
7236 NULL, /* pAlphaBlend */
7237 NULL, /* pAngleArc */
7238 NULL, /* pArc */
7239 NULL, /* pArcTo */
7240 NULL, /* pBeginPath */
7241 NULL, /* pBlendImage */
7242 NULL, /* pChoosePixelFormat */
7243 NULL, /* pChord */
7244 NULL, /* pCloseFigure */
7245 NULL, /* pCopyBitmap */
7246 NULL, /* pCreateBitmap */
7247 NULL, /* pCreateCompatibleDC */
7248 freetype_CreateDC, /* pCreateDC */
7249 NULL, /* pDeleteBitmap */
7250 freetype_DeleteDC, /* pDeleteDC */
7251 NULL, /* pDeleteObject */
7252 NULL, /* pDescribePixelFormat */
7253 NULL, /* pDeviceCapabilities */
7254 NULL, /* pEllipse */
7255 NULL, /* pEndDoc */
7256 NULL, /* pEndPage */
7257 NULL, /* pEndPath */
7258 freetype_EnumFonts, /* pEnumFonts */
7259 NULL, /* pEnumICMProfiles */
7260 NULL, /* pExcludeClipRect */
7261 NULL, /* pExtDeviceMode */
7262 NULL, /* pExtEscape */
7263 NULL, /* pExtFloodFill */
7264 NULL, /* pExtSelectClipRgn */
7265 NULL, /* pExtTextOut */
7266 NULL, /* pFillPath */
7267 NULL, /* pFillRgn */
7268 NULL, /* pFlattenPath */
7269 freetype_FontIsLinked, /* pFontIsLinked */
7270 NULL, /* pFrameRgn */
7271 NULL, /* pGdiComment */
7272 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7273 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7274 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7275 freetype_GetCharWidth, /* pGetCharWidth */
7276 NULL, /* pGetDeviceCaps */
7277 NULL, /* pGetDeviceGammaRamp */
7278 freetype_GetFontData, /* pGetFontData */
7279 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7280 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7281 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7282 NULL, /* pGetICMProfile */
7283 NULL, /* pGetImage */
7284 freetype_GetKerningPairs, /* pGetKerningPairs */
7285 NULL, /* pGetNearestColor */
7286 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7287 NULL, /* pGetPixel */
7288 NULL, /* pGetPixelFormat */
7289 NULL, /* pGetSystemPaletteEntries */
7290 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7291 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7292 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7293 freetype_GetTextFace, /* pGetTextFace */
7294 freetype_GetTextMetrics, /* pGetTextMetrics */
7295 NULL, /* pGradientFill */
7296 NULL, /* pIntersectClipRect */
7297 NULL, /* pInvertRgn */
7298 NULL, /* pLineTo */
7299 NULL, /* pModifyWorldTransform */
7300 NULL, /* pMoveTo */
7301 NULL, /* pOffsetClipRgn */
7302 NULL, /* pOffsetViewportOrg */
7303 NULL, /* pOffsetWindowOrg */
7304 NULL, /* pPaintRgn */
7305 NULL, /* pPatBlt */
7306 NULL, /* pPie */
7307 NULL, /* pPolyBezier */
7308 NULL, /* pPolyBezierTo */
7309 NULL, /* pPolyDraw */
7310 NULL, /* pPolyPolygon */
7311 NULL, /* pPolyPolyline */
7312 NULL, /* pPolygon */
7313 NULL, /* pPolyline */
7314 NULL, /* pPolylineTo */
7315 NULL, /* pPutImage */
7316 NULL, /* pRealizeDefaultPalette */
7317 NULL, /* pRealizePalette */
7318 NULL, /* pRectangle */
7319 NULL, /* pResetDC */
7320 NULL, /* pRestoreDC */
7321 NULL, /* pRoundRect */
7322 NULL, /* pSaveDC */
7323 NULL, /* pScaleViewportExt */
7324 NULL, /* pScaleWindowExt */
7325 NULL, /* pSelectBitmap */
7326 NULL, /* pSelectBrush */
7327 NULL, /* pSelectClipPath */
7328 freetype_SelectFont, /* pSelectFont */
7329 NULL, /* pSelectPalette */
7330 NULL, /* pSelectPen */
7331 NULL, /* pSetArcDirection */
7332 NULL, /* pSetBkColor */
7333 NULL, /* pSetBkMode */
7334 NULL, /* pSetDCBrushColor */
7335 NULL, /* pSetDCPenColor */
7336 NULL, /* pSetDIBColorTable */
7337 NULL, /* pSetDIBitsToDevice */
7338 NULL, /* pSetDeviceClipping */
7339 NULL, /* pSetDeviceGammaRamp */
7340 NULL, /* pSetLayout */
7341 NULL, /* pSetMapMode */
7342 NULL, /* pSetMapperFlags */
7343 NULL, /* pSetPixel */
7344 NULL, /* pSetPixelFormat */
7345 NULL, /* pSetPolyFillMode */
7346 NULL, /* pSetROP2 */
7347 NULL, /* pSetRelAbs */
7348 NULL, /* pSetStretchBltMode */
7349 NULL, /* pSetTextAlign */
7350 NULL, /* pSetTextCharacterExtra */
7351 NULL, /* pSetTextColor */
7352 NULL, /* pSetTextJustification */
7353 NULL, /* pSetViewportExt */
7354 NULL, /* pSetViewportOrg */
7355 NULL, /* pSetWindowExt */
7356 NULL, /* pSetWindowOrg */
7357 NULL, /* pSetWorldTransform */
7358 NULL, /* pStartDoc */
7359 NULL, /* pStartPage */
7360 NULL, /* pStretchBlt */
7361 NULL, /* pStretchDIBits */
7362 NULL, /* pStrokeAndFillPath */
7363 NULL, /* pStrokePath */
7364 NULL, /* pSwapBuffers */
7365 NULL, /* pUnrealizePalette */
7366 NULL, /* pWidenPath */
7367 /* OpenGL not supported */
7370 #else /* HAVE_FREETYPE */
7372 /*************************************************************************/
7374 BOOL WineEngInit(void)
7376 return FALSE;
7378 BOOL WineEngDestroyFontInstance(HFONT hfont)
7380 return FALSE;
7383 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7385 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7386 return 1;
7389 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7391 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7392 return TRUE;
7395 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7397 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7398 return NULL;
7401 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7403 return FALSE;
7406 /*************************************************************************
7407 * GetRasterizerCaps (GDI32.@)
7409 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7411 lprs->nSize = sizeof(RASTERIZER_STATUS);
7412 lprs->wFlags = 0;
7413 lprs->nLanguageID = 0;
7414 return TRUE;
7417 #endif /* HAVE_FREETYPE */