gdi32: find_face_from_filename() needs to take font replacements into account.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blobec39814f96fdf7e3d836d19d5d0fc12a244596f5
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 #define ADDFONT_EXTERNAL_FONT 0x01
1500 #define ADDFONT_FORCE_BITMAP 0x02
1501 #define ADDFONT_ADD_TO_CACHE 0x04
1503 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)
1505 int bitmap_num = 0;
1506 Family *family;
1507 WCHAR *StyleW;
1509 do {
1510 TT_OS2 *pOS2;
1511 TT_Header *pHeader;
1512 WCHAR *english_family, *localised_family;
1513 Face *face;
1514 struct list *face_elem_ptr;
1515 FT_WinFNT_HeaderRec winfnt_header;
1516 int internal_leading;
1517 FONTSIGNATURE fs;
1518 My_FT_Bitmap_Size *size = NULL;
1519 FT_ULong tmp_size;
1521 if(!FT_IS_SCALABLE(ft_face))
1522 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1524 english_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1525 if (!english_family)
1526 english_family = towstr(CP_ACP, ft_face->family_name);
1528 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1529 if (localised_family && !strcmpiW(localised_family, english_family))
1531 HeapFree(GetProcessHeap(), 0, localised_family);
1532 localised_family = NULL;
1535 if (vertical)
1537 english_family = prepend_at(english_family);
1538 localised_family = prepend_at(localised_family);
1541 family = find_family_from_name(localised_family ? localised_family : english_family);
1542 if(!family) {
1543 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1544 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1545 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1546 list_init(&family->faces);
1547 family->replacement = &family->faces;
1548 list_add_tail(&font_list, &family->entry);
1550 if(localised_family) {
1551 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1552 subst->from.name = strdupW(english_family);
1553 subst->from.charset = -1;
1554 subst->to.name = strdupW(localised_family);
1555 subst->to.charset = -1;
1556 add_font_subst(&font_subst_list, subst, 0);
1559 HeapFree(GetProcessHeap(), 0, localised_family);
1560 HeapFree(GetProcessHeap(), 0, english_family);
1562 StyleW = towstr(CP_ACP, ft_face->style_name);
1564 internal_leading = 0;
1565 memset(&fs, 0, sizeof(fs));
1567 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1568 if(pOS2) {
1569 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1570 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1571 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1572 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1573 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1574 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1575 if(pOS2->version == 0) {
1576 FT_UInt dummy;
1578 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1579 fs.fsCsb[0] |= FS_LATIN1;
1580 else
1581 fs.fsCsb[0] |= FS_SYMBOL;
1584 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1585 CHARSETINFO csi;
1586 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1587 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1588 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1589 fs = csi.fs;
1590 internal_leading = winfnt_header.internal_leading;
1593 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1594 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1595 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1596 if(!strcmpiW(face->StyleName, StyleW) &&
1597 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1598 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1599 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1600 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1602 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1603 TRACE("Original font is newer so skipping this one\n");
1604 HeapFree(GetProcessHeap(), 0, StyleW);
1605 return;
1606 } else {
1607 TRACE("Replacing original with this one\n");
1608 list_remove(&face->entry);
1609 HeapFree(GetProcessHeap(), 0, face->file);
1610 HeapFree(GetProcessHeap(), 0, face->StyleName);
1611 HeapFree(GetProcessHeap(), 0, face->FullName);
1612 HeapFree(GetProcessHeap(), 0, face);
1613 break;
1617 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1618 face->cached_enum_data = NULL;
1619 face->StyleName = StyleW;
1620 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1621 if (file)
1623 face->file = strdupA(file);
1624 face->font_data_ptr = NULL;
1625 face->font_data_size = 0;
1627 else
1629 face->file = NULL;
1630 face->font_data_ptr = font_data_ptr;
1631 face->font_data_size = font_data_size;
1633 face->face_index = face_index;
1634 face->ntmFlags = 0;
1635 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1636 face->ntmFlags |= NTM_ITALIC;
1637 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1638 face->ntmFlags |= NTM_BOLD;
1639 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1640 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1641 face->family = family;
1642 face->vertical = vertical;
1643 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1644 face->fs = fs;
1646 if(FT_IS_SCALABLE(ft_face)) {
1647 memset(&face->size, 0, sizeof(face->size));
1648 face->scalable = TRUE;
1649 } else {
1650 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1651 size->height, size->width, size->size >> 6,
1652 size->x_ppem >> 6, size->y_ppem >> 6);
1653 face->size.height = size->height;
1654 face->size.width = size->width;
1655 face->size.size = size->size;
1656 face->size.x_ppem = size->x_ppem;
1657 face->size.y_ppem = size->y_ppem;
1658 face->size.internal_leading = internal_leading;
1659 face->scalable = FALSE;
1662 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1663 tmp_size = 0;
1664 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1666 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1667 face->ntmFlags |= NTM_PS_OPENTYPE;
1670 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1671 face->fs.fsCsb[0], face->fs.fsCsb[1],
1672 face->fs.fsUsb[0], face->fs.fsUsb[1],
1673 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1675 if(face->fs.fsCsb[0] == 0)
1677 int i;
1679 /* let's see if we can find any interesting cmaps */
1680 for(i = 0; i < ft_face->num_charmaps; i++) {
1681 switch(ft_face->charmaps[i]->encoding) {
1682 case FT_ENCODING_UNICODE:
1683 case FT_ENCODING_APPLE_ROMAN:
1684 face->fs.fsCsb[0] |= FS_LATIN1;
1685 break;
1686 case FT_ENCODING_MS_SYMBOL:
1687 face->fs.fsCsb[0] |= FS_SYMBOL;
1688 break;
1689 default:
1690 break;
1695 if(flags & ADDFONT_ADD_TO_CACHE)
1696 add_face_to_cache(face);
1698 AddFaceToFamily(face, family);
1700 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1702 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1703 debugstr_w(StyleW));
1706 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1708 FT_Face ft_face;
1709 TT_OS2 *pOS2;
1710 TT_Header *pHeader = NULL;
1711 FT_Error err;
1712 FT_Long face_index = 0, num_faces;
1713 INT ret = 0;
1715 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1716 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1718 #ifdef HAVE_CARBON_CARBON_H
1719 if(file)
1721 char **mac_list = expand_mac_font(file);
1722 if(mac_list)
1724 BOOL had_one = FALSE;
1725 char **cursor;
1726 for(cursor = mac_list; *cursor; cursor++)
1728 had_one = TRUE;
1729 AddFontToList(*cursor, NULL, 0, flags);
1730 HeapFree(GetProcessHeap(), 0, *cursor);
1732 HeapFree(GetProcessHeap(), 0, mac_list);
1733 if(had_one)
1734 return 1;
1737 #endif /* HAVE_CARBON_CARBON_H */
1739 do {
1740 if (file)
1742 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1743 err = pFT_New_Face(library, file, face_index, &ft_face);
1744 } else
1746 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1747 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1750 if(err != 0) {
1751 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1752 return 0;
1755 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*/
1756 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1757 pFT_Done_Face(ft_face);
1758 return 0;
1761 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1762 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1763 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1764 pFT_Done_Face(ft_face);
1765 return 0;
1768 if(FT_IS_SFNT(ft_face))
1770 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1771 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1772 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1774 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1775 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1776 pFT_Done_Face(ft_face);
1777 return 0;
1780 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1781 we don't want to load these. */
1782 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1784 FT_ULong len = 0;
1786 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1788 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1789 pFT_Done_Face(ft_face);
1790 return 0;
1795 if(!ft_face->family_name || !ft_face->style_name) {
1796 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1797 pFT_Done_Face(ft_face);
1798 return 0;
1801 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1803 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1804 pFT_Done_Face(ft_face);
1805 return 0;
1808 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1809 ++ret;
1811 if (FT_HAS_VERTICAL(ft_face))
1813 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1814 ++ret;
1817 num_faces = ft_face->num_faces;
1818 pFT_Done_Face(ft_face);
1819 } while(num_faces > ++face_index);
1820 return ret;
1823 static void DumpFontList(void)
1825 Family *family;
1826 Face *face;
1827 struct list *family_elem_ptr, *face_elem_ptr;
1829 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1830 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1831 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1832 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1833 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1834 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1835 if(!face->scalable)
1836 TRACE(" %d", face->size.height);
1837 TRACE("\n");
1840 return;
1843 /***********************************************************
1844 * The replacement list is a way to map an entire font
1845 * family onto another family. For example adding
1847 * [HKCU\Software\Wine\Fonts\Replacements]
1848 * "Wingdings"="Winedings"
1850 * would enumerate the Winedings font both as Winedings and
1851 * Wingdings. However if a real Wingdings font is present the
1852 * replacement does not take place.
1855 static void LoadReplaceList(void)
1857 HKEY hkey;
1858 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1859 LPWSTR value;
1860 LPVOID data;
1861 CHAR familyA[400];
1863 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1864 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1866 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1867 &valuelen, &datalen, NULL, NULL);
1869 valuelen++; /* returned value doesn't include room for '\0' */
1870 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1871 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1873 dlen = datalen;
1874 vlen = valuelen;
1875 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1876 &dlen) == ERROR_SUCCESS) {
1877 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1878 /* "NewName"="Oldname" */
1879 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1881 if(!find_family_from_any_name(value))
1883 Family * const family = find_family_from_any_name(data);
1884 if (family != NULL)
1886 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1887 if (new_family != NULL)
1889 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1890 new_family->FamilyName = strdupW(value);
1891 new_family->EnglishName = NULL;
1892 list_init(&new_family->faces);
1893 new_family->replacement = &family->faces;
1894 list_add_tail(&font_list, &new_family->entry);
1897 else
1899 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1902 else
1904 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1906 /* reset dlen and vlen */
1907 dlen = datalen;
1908 vlen = valuelen;
1910 HeapFree(GetProcessHeap(), 0, data);
1911 HeapFree(GetProcessHeap(), 0, value);
1912 RegCloseKey(hkey);
1916 static const WCHAR *font_links_list[] =
1918 Lucida_Sans_Unicode,
1919 Microsoft_Sans_Serif,
1920 Tahoma
1923 static const struct font_links_defaults_list
1925 /* Keyed off substitution for "MS Shell Dlg" */
1926 const WCHAR *shelldlg;
1927 /* Maximum of four substitutes, plus terminating NULL pointer */
1928 const WCHAR *substitutes[5];
1929 } font_links_defaults_list[] =
1931 /* Non East-Asian */
1932 { Tahoma, /* FIXME unverified ordering */
1933 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
1935 /* Below lists are courtesy of
1936 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1938 /* Japanese */
1939 { MS_UI_Gothic,
1940 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
1942 /* Chinese Simplified */
1943 { SimSun,
1944 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
1946 /* Korean */
1947 { Gulim,
1948 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
1950 /* Chinese Traditional */
1951 { PMingLiU,
1952 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
1957 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
1959 SYSTEM_LINKS *font_link;
1961 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1963 if(!strcmpiW(font_link->font_name, name))
1964 return font_link;
1967 return NULL;
1970 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
1972 const WCHAR *value;
1973 int i;
1974 FontSubst *psub;
1975 Family *family;
1976 Face *face;
1977 const char *file;
1978 WCHAR *fileW;
1980 if (values)
1982 SYSTEM_LINKS *font_link;
1984 psub = get_font_subst(&font_subst_list, name, -1);
1985 /* Don't store fonts that are only substitutes for other fonts */
1986 if(psub)
1988 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
1989 return;
1992 font_link = find_font_link(name);
1993 if (font_link == NULL)
1995 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1996 font_link->font_name = strdupW(name);
1997 list_init(&font_link->links);
1998 list_add_tail(&system_links, &font_link->entry);
2001 memset(&font_link->fs, 0, sizeof font_link->fs);
2002 for (i = 0; values[i] != NULL; i++)
2004 const struct list *face_list;
2005 CHILD_FONT *child_font;
2007 value = values[i];
2008 if (!strcmpiW(name,value))
2009 continue;
2010 psub = get_font_subst(&font_subst_list, value, -1);
2011 if(psub)
2012 value = psub->to.name;
2013 family = find_family_from_name(value);
2014 if (!family)
2015 continue;
2016 file = NULL;
2017 /* Use first extant filename for this Family */
2018 face_list = get_face_list_from_family(family);
2019 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2021 if (!face->file)
2022 continue;
2023 file = strrchr(face->file, '/');
2024 if (!file)
2025 file = face->file;
2026 else
2027 file++;
2028 break;
2030 if (!file)
2031 continue;
2032 fileW = towstr(CP_UNIXCP, file);
2034 face = find_face_from_filename(fileW, value);
2035 if(!face)
2037 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2038 continue;
2041 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2042 child_font->face = face;
2043 child_font->font = NULL;
2044 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2045 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2046 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2047 list_add_tail(&font_link->links, &child_font->entry);
2049 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2050 HeapFree(GetProcessHeap(), 0, fileW);
2056 /*************************************************************
2057 * init_system_links
2059 static BOOL init_system_links(void)
2061 HKEY hkey;
2062 BOOL ret = FALSE;
2063 DWORD type, max_val, max_data, val_len, data_len, index;
2064 WCHAR *value, *data;
2065 WCHAR *entry, *next;
2066 SYSTEM_LINKS *font_link, *system_font_link;
2067 CHILD_FONT *child_font;
2068 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2069 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2070 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2071 Face *face;
2072 FontSubst *psub;
2073 UINT i, j;
2075 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2077 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2078 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2079 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2080 val_len = max_val + 1;
2081 data_len = max_data;
2082 index = 0;
2083 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2085 psub = get_font_subst(&font_subst_list, value, -1);
2086 /* Don't store fonts that are only substitutes for other fonts */
2087 if(psub)
2089 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2090 goto next;
2092 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2093 font_link->font_name = strdupW(value);
2094 memset(&font_link->fs, 0, sizeof font_link->fs);
2095 list_init(&font_link->links);
2096 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2098 WCHAR *face_name;
2099 CHILD_FONT *child_font;
2101 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2103 next = entry + strlenW(entry) + 1;
2105 face_name = strchrW(entry, ',');
2106 if(face_name)
2108 *face_name++ = 0;
2109 while(isspaceW(*face_name))
2110 face_name++;
2112 psub = get_font_subst(&font_subst_list, face_name, -1);
2113 if(psub)
2114 face_name = psub->to.name;
2116 face = find_face_from_filename(entry, face_name);
2117 if(!face)
2119 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2120 continue;
2123 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2124 child_font->face = face;
2125 child_font->font = NULL;
2126 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2127 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2128 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2129 list_add_tail(&font_link->links, &child_font->entry);
2131 list_add_tail(&system_links, &font_link->entry);
2132 next:
2133 val_len = max_val + 1;
2134 data_len = max_data;
2137 HeapFree(GetProcessHeap(), 0, value);
2138 HeapFree(GetProcessHeap(), 0, data);
2139 RegCloseKey(hkey);
2143 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2144 if (!psub) {
2145 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2146 goto skip_internal;
2149 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2151 const FontSubst *psub2;
2152 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2154 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2156 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2157 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2159 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2160 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2162 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2164 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2168 skip_internal:
2170 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2171 that Tahoma has */
2173 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2174 system_font_link->font_name = strdupW(System);
2175 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2176 list_init(&system_font_link->links);
2178 face = find_face_from_filename(tahoma_ttf, Tahoma);
2179 if(face)
2181 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2182 child_font->face = face;
2183 child_font->font = NULL;
2184 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2185 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2186 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2187 list_add_tail(&system_font_link->links, &child_font->entry);
2189 font_link = find_font_link(Tahoma);
2190 if (font_link != NULL)
2192 CHILD_FONT *font_link_entry;
2193 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2195 CHILD_FONT *new_child;
2196 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2197 new_child->face = font_link_entry->face;
2198 new_child->font = NULL;
2199 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2200 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2201 list_add_tail(&system_font_link->links, &new_child->entry);
2204 list_add_tail(&system_links, &system_font_link->entry);
2205 return ret;
2208 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2210 DIR *dir;
2211 struct dirent *dent;
2212 char path[MAX_PATH];
2214 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2216 dir = opendir(dirname);
2217 if(!dir) {
2218 WARN("Can't open directory %s\n", debugstr_a(dirname));
2219 return FALSE;
2221 while((dent = readdir(dir)) != NULL) {
2222 struct stat statbuf;
2224 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2225 continue;
2227 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2229 sprintf(path, "%s/%s", dirname, dent->d_name);
2231 if(stat(path, &statbuf) == -1)
2233 WARN("Can't stat %s\n", debugstr_a(path));
2234 continue;
2236 if(S_ISDIR(statbuf.st_mode))
2237 ReadFontDir(path, external_fonts);
2238 else
2240 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2241 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2242 AddFontToList(path, NULL, 0, addfont_flags);
2245 closedir(dir);
2246 return TRUE;
2249 static void load_fontconfig_fonts(void)
2251 #ifdef SONAME_LIBFONTCONFIG
2252 void *fc_handle = NULL;
2253 FcConfig *config;
2254 FcPattern *pat;
2255 FcObjectSet *os;
2256 FcFontSet *fontset;
2257 int i, len;
2258 char *file;
2259 const char *ext;
2261 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2262 if(!fc_handle) {
2263 TRACE("Wine cannot find the fontconfig library (%s).\n",
2264 SONAME_LIBFONTCONFIG);
2265 return;
2267 #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;}
2268 LOAD_FUNCPTR(FcConfigGetCurrent);
2269 LOAD_FUNCPTR(FcFontList);
2270 LOAD_FUNCPTR(FcFontSetDestroy);
2271 LOAD_FUNCPTR(FcInit);
2272 LOAD_FUNCPTR(FcObjectSetAdd);
2273 LOAD_FUNCPTR(FcObjectSetCreate);
2274 LOAD_FUNCPTR(FcObjectSetDestroy);
2275 LOAD_FUNCPTR(FcPatternCreate);
2276 LOAD_FUNCPTR(FcPatternDestroy);
2277 LOAD_FUNCPTR(FcPatternGetBool);
2278 LOAD_FUNCPTR(FcPatternGetString);
2279 #undef LOAD_FUNCPTR
2281 if(!pFcInit()) return;
2283 config = pFcConfigGetCurrent();
2284 pat = pFcPatternCreate();
2285 os = pFcObjectSetCreate();
2286 pFcObjectSetAdd(os, FC_FILE);
2287 pFcObjectSetAdd(os, FC_SCALABLE);
2288 fontset = pFcFontList(config, pat, os);
2289 if(!fontset) return;
2290 for(i = 0; i < fontset->nfont; i++) {
2291 FcBool scalable;
2293 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2294 continue;
2295 TRACE("fontconfig: %s\n", file);
2297 /* We're just interested in OT/TT fonts for now, so this hack just
2298 picks up the scalable fonts without extensions .pf[ab] to save time
2299 loading every other font */
2301 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2303 TRACE("not scalable\n");
2304 continue;
2307 len = strlen( file );
2308 if(len < 4) continue;
2309 ext = &file[ len - 3 ];
2310 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2311 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2313 pFcFontSetDestroy(fontset);
2314 pFcObjectSetDestroy(os);
2315 pFcPatternDestroy(pat);
2316 sym_not_found:
2317 #endif
2318 return;
2321 static BOOL load_font_from_data_dir(LPCWSTR file)
2323 BOOL ret = FALSE;
2324 const char *data_dir = wine_get_data_dir();
2326 if (!data_dir) data_dir = wine_get_build_dir();
2328 if (data_dir)
2330 INT len;
2331 char *unix_name;
2333 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2335 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2337 strcpy(unix_name, data_dir);
2338 strcat(unix_name, "/fonts/");
2340 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2342 EnterCriticalSection( &freetype_cs );
2343 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2344 LeaveCriticalSection( &freetype_cs );
2345 HeapFree(GetProcessHeap(), 0, unix_name);
2347 return ret;
2350 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2352 static const WCHAR slashW[] = {'\\','\0'};
2353 BOOL ret = FALSE;
2354 WCHAR windowsdir[MAX_PATH];
2355 char *unixname;
2357 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2358 strcatW(windowsdir, fontsW);
2359 strcatW(windowsdir, slashW);
2360 strcatW(windowsdir, file);
2361 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2362 EnterCriticalSection( &freetype_cs );
2363 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2364 LeaveCriticalSection( &freetype_cs );
2365 HeapFree(GetProcessHeap(), 0, unixname);
2367 return ret;
2370 static void load_system_fonts(void)
2372 HKEY hkey;
2373 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2374 const WCHAR * const *value;
2375 DWORD dlen, type;
2376 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2377 char *unixname;
2379 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2380 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2381 strcatW(windowsdir, fontsW);
2382 for(value = SystemFontValues; *value; value++) {
2383 dlen = sizeof(data);
2384 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2385 type == REG_SZ) {
2386 BOOL added = FALSE;
2388 sprintfW(pathW, fmtW, windowsdir, data);
2389 if((unixname = wine_get_unix_file_name(pathW))) {
2390 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2391 HeapFree(GetProcessHeap(), 0, unixname);
2393 if (!added)
2394 load_font_from_data_dir(data);
2397 RegCloseKey(hkey);
2401 /*************************************************************
2403 * This adds registry entries for any externally loaded fonts
2404 * (fonts from fontconfig or FontDirs). It also deletes entries
2405 * of no longer existing fonts.
2408 static void update_reg_entries(void)
2410 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2411 LPWSTR valueW;
2412 DWORD len, len_fam;
2413 Family *family;
2414 Face *face;
2415 struct list *family_elem_ptr, *face_elem_ptr;
2416 WCHAR *file;
2417 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2418 static const WCHAR spaceW[] = {' ', '\0'};
2419 char *path;
2421 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2422 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2423 ERR("Can't create Windows font reg key\n");
2424 goto end;
2427 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2428 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2429 ERR("Can't create Windows font reg key\n");
2430 goto end;
2433 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2434 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2435 ERR("Can't create external font reg key\n");
2436 goto end;
2439 /* enumerate the fonts and add external ones to the two keys */
2441 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2442 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2443 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2444 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2445 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2446 if(!face->external) continue;
2447 len = len_fam;
2448 if (!(face->ntmFlags & NTM_REGULAR))
2449 len = len_fam + strlenW(face->StyleName) + 1;
2450 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2451 strcpyW(valueW, family->FamilyName);
2452 if(len != len_fam) {
2453 strcatW(valueW, spaceW);
2454 strcatW(valueW, face->StyleName);
2456 strcatW(valueW, TrueType);
2458 file = wine_get_dos_file_name(face->file);
2459 if(file)
2460 len = strlenW(file) + 1;
2461 else
2463 if((path = strrchr(face->file, '/')) == NULL)
2464 path = face->file;
2465 else
2466 path++;
2467 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2469 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2470 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2472 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2473 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2474 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2476 HeapFree(GetProcessHeap(), 0, file);
2477 HeapFree(GetProcessHeap(), 0, valueW);
2480 end:
2481 if(external_key) RegCloseKey(external_key);
2482 if(win9x_key) RegCloseKey(win9x_key);
2483 if(winnt_key) RegCloseKey(winnt_key);
2484 return;
2487 static void delete_external_font_keys(void)
2489 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2490 DWORD dlen, vlen, datalen, valuelen, i, type;
2491 LPWSTR valueW;
2492 LPVOID data;
2494 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2495 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2496 ERR("Can't create Windows font reg key\n");
2497 goto end;
2500 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2501 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2502 ERR("Can't create Windows font reg key\n");
2503 goto end;
2506 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2507 ERR("Can't create external font reg key\n");
2508 goto end;
2511 /* Delete all external fonts added last time */
2513 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2514 &valuelen, &datalen, NULL, NULL);
2515 valuelen++; /* returned value doesn't include room for '\0' */
2516 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2517 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2519 dlen = datalen * sizeof(WCHAR);
2520 vlen = valuelen;
2521 i = 0;
2522 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2523 &dlen) == ERROR_SUCCESS) {
2525 RegDeleteValueW(winnt_key, valueW);
2526 RegDeleteValueW(win9x_key, valueW);
2527 /* reset dlen and vlen */
2528 dlen = datalen;
2529 vlen = valuelen;
2531 HeapFree(GetProcessHeap(), 0, data);
2532 HeapFree(GetProcessHeap(), 0, valueW);
2534 /* Delete the old external fonts key */
2535 RegCloseKey(external_key);
2536 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2538 end:
2539 if(win9x_key) RegCloseKey(win9x_key);
2540 if(winnt_key) RegCloseKey(winnt_key);
2543 /*************************************************************
2544 * WineEngAddFontResourceEx
2547 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2549 INT ret = 0;
2551 GDI_CheckNotLock();
2553 if (ft_handle) /* do it only if we have freetype up and running */
2555 char *unixname;
2557 if(flags)
2558 FIXME("Ignoring flags %x\n", flags);
2560 if((unixname = wine_get_unix_file_name(file)))
2562 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2564 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2565 EnterCriticalSection( &freetype_cs );
2566 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2567 LeaveCriticalSection( &freetype_cs );
2568 HeapFree(GetProcessHeap(), 0, unixname);
2570 if (!ret && !strchrW(file, '\\')) {
2571 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2572 ret = load_font_from_winfonts_dir(file);
2573 if (!ret) {
2574 /* Try in datadir/fonts (or builddir/fonts),
2575 * needed for Magic the Gathering Online
2577 ret = load_font_from_data_dir(file);
2581 return ret;
2584 /*************************************************************
2585 * WineEngAddFontMemResourceEx
2588 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2590 GDI_CheckNotLock();
2592 if (ft_handle) /* do it only if we have freetype up and running */
2594 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2596 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2597 memcpy(pFontCopy, pbFont, cbFont);
2599 EnterCriticalSection( &freetype_cs );
2600 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2601 LeaveCriticalSection( &freetype_cs );
2603 if (*pcFonts == 0)
2605 TRACE("AddFontToList failed\n");
2606 HeapFree(GetProcessHeap(), 0, pFontCopy);
2607 return 0;
2609 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2610 * For now return something unique but quite random
2612 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2613 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2616 *pcFonts = 0;
2617 return 0;
2620 /*************************************************************
2621 * WineEngRemoveFontResourceEx
2624 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2626 GDI_CheckNotLock();
2627 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2628 return TRUE;
2631 static const struct nls_update_font_list
2633 UINT ansi_cp, oem_cp;
2634 const char *oem, *fixed, *system;
2635 const char *courier, *serif, *small, *sserif;
2636 /* these are for font substitutes */
2637 const char *shelldlg, *tmsrmn;
2638 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2639 *helv_0, *tmsrmn_0;
2640 const struct subst
2642 const char *from, *to;
2643 } arial_0, courier_new_0, times_new_roman_0;
2644 } nls_update_font_list[] =
2646 /* Latin 1 (United States) */
2647 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2648 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2649 "Tahoma","Times New Roman",
2650 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2651 { 0 }, { 0 }, { 0 }
2653 /* Latin 1 (Multilingual) */
2654 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2655 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2656 "Tahoma","Times New Roman", /* FIXME unverified */
2657 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2658 { 0 }, { 0 }, { 0 }
2660 /* Eastern Europe */
2661 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2662 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2663 "Tahoma","Times New Roman", /* FIXME unverified */
2664 "Fixedsys,238", "System,238",
2665 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2666 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2667 { "Arial CE,0", "Arial,238" },
2668 { "Courier New CE,0", "Courier New,238" },
2669 { "Times New Roman CE,0", "Times New Roman,238" }
2671 /* Cyrillic */
2672 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2673 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2674 "Tahoma","Times New Roman", /* FIXME unverified */
2675 "Fixedsys,204", "System,204",
2676 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2677 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2678 { "Arial Cyr,0", "Arial,204" },
2679 { "Courier New Cyr,0", "Courier New,204" },
2680 { "Times New Roman Cyr,0", "Times New Roman,204" }
2682 /* Greek */
2683 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2684 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2685 "Tahoma","Times New Roman", /* FIXME unverified */
2686 "Fixedsys,161", "System,161",
2687 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2688 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2689 { "Arial Greek,0", "Arial,161" },
2690 { "Courier New Greek,0", "Courier New,161" },
2691 { "Times New Roman Greek,0", "Times New Roman,161" }
2693 /* Turkish */
2694 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2695 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2696 "Tahoma","Times New Roman", /* FIXME unverified */
2697 "Fixedsys,162", "System,162",
2698 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2699 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2700 { "Arial Tur,0", "Arial,162" },
2701 { "Courier New Tur,0", "Courier New,162" },
2702 { "Times New Roman Tur,0", "Times New Roman,162" }
2704 /* Hebrew */
2705 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2706 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2707 "Tahoma","Times New Roman", /* FIXME unverified */
2708 "Fixedsys,177", "System,177",
2709 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2710 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2711 { 0 }, { 0 }, { 0 }
2713 /* Arabic */
2714 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2715 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2716 "Tahoma","Times New Roman", /* FIXME unverified */
2717 "Fixedsys,178", "System,178",
2718 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2719 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2720 { 0 }, { 0 }, { 0 }
2722 /* Baltic */
2723 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2724 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2725 "Tahoma","Times New Roman", /* FIXME unverified */
2726 "Fixedsys,186", "System,186",
2727 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2728 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2729 { "Arial Baltic,0", "Arial,186" },
2730 { "Courier New Baltic,0", "Courier New,186" },
2731 { "Times New Roman Baltic,0", "Times New Roman,186" }
2733 /* Vietnamese */
2734 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2735 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2736 "Tahoma","Times New Roman", /* FIXME unverified */
2737 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2738 { 0 }, { 0 }, { 0 }
2740 /* Thai */
2741 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2742 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2743 "Tahoma","Times New Roman", /* FIXME unverified */
2744 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2745 { 0 }, { 0 }, { 0 }
2747 /* Japanese */
2748 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2749 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2750 "MS UI Gothic","MS Serif",
2751 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2752 { 0 }, { 0 }, { 0 }
2754 /* Chinese Simplified */
2755 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2756 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2757 "SimSun", "NSimSun",
2758 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2759 { 0 }, { 0 }, { 0 }
2761 /* Korean */
2762 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2763 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2764 "Gulim", "Batang",
2765 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2766 { 0 }, { 0 }, { 0 }
2768 /* Chinese Traditional */
2769 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2770 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2771 "PMingLiU", "MingLiU",
2772 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2773 { 0 }, { 0 }, { 0 }
2777 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2779 return ( ansi_cp == 932 /* CP932 for Japanese */
2780 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2781 || ansi_cp == 949 /* CP949 for Korean */
2782 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2785 static inline HKEY create_fonts_NT_registry_key(void)
2787 HKEY hkey = 0;
2789 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2790 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2791 return hkey;
2794 static inline HKEY create_fonts_9x_registry_key(void)
2796 HKEY hkey = 0;
2798 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2799 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2800 return hkey;
2803 static inline HKEY create_config_fonts_registry_key(void)
2805 HKEY hkey = 0;
2807 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2808 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2809 return hkey;
2812 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2814 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2815 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2816 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2817 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2820 static void set_value_key(HKEY hkey, const char *name, const char *value)
2822 if (value)
2823 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2824 else if (name)
2825 RegDeleteValueA(hkey, name);
2828 static void update_font_info(void)
2830 char buf[40], cpbuf[40];
2831 DWORD len, type;
2832 HKEY hkey = 0;
2833 UINT i, ansi_cp = 0, oem_cp = 0;
2834 BOOL done = FALSE;
2836 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2837 return;
2839 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2840 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2841 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2842 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2843 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2845 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2846 if (is_dbcs_ansi_cp(ansi_cp))
2847 use_default_fallback = TRUE;
2849 len = sizeof(buf);
2850 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2852 if (!strcmp( buf, cpbuf )) /* already set correctly */
2854 RegCloseKey(hkey);
2855 return;
2857 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2859 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2861 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2862 RegCloseKey(hkey);
2864 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2866 HKEY hkey;
2868 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2869 nls_update_font_list[i].oem_cp == oem_cp)
2871 hkey = create_config_fonts_registry_key();
2872 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2873 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2874 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2875 RegCloseKey(hkey);
2877 hkey = create_fonts_NT_registry_key();
2878 add_font_list(hkey, &nls_update_font_list[i]);
2879 RegCloseKey(hkey);
2881 hkey = create_fonts_9x_registry_key();
2882 add_font_list(hkey, &nls_update_font_list[i]);
2883 RegCloseKey(hkey);
2885 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2887 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2888 strlen(nls_update_font_list[i].shelldlg)+1);
2889 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2890 strlen(nls_update_font_list[i].tmsrmn)+1);
2892 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2893 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2894 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2895 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2896 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2897 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2898 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2899 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2901 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2902 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2903 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2905 RegCloseKey(hkey);
2907 done = TRUE;
2909 else
2911 /* Delete the FontSubstitutes from other locales */
2912 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2914 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2915 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2916 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2917 RegCloseKey(hkey);
2921 if (!done)
2922 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2925 static BOOL init_freetype(void)
2927 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2928 if(!ft_handle) {
2929 WINE_MESSAGE(
2930 "Wine cannot find the FreeType font library. To enable Wine to\n"
2931 "use TrueType fonts please install a version of FreeType greater than\n"
2932 "or equal to 2.0.5.\n"
2933 "http://www.freetype.org\n");
2934 return FALSE;
2937 #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;}
2939 LOAD_FUNCPTR(FT_Done_Face)
2940 LOAD_FUNCPTR(FT_Get_Char_Index)
2941 LOAD_FUNCPTR(FT_Get_First_Char)
2942 LOAD_FUNCPTR(FT_Get_Module)
2943 LOAD_FUNCPTR(FT_Get_Next_Char)
2944 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2945 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2946 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2947 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2948 LOAD_FUNCPTR(FT_Init_FreeType)
2949 LOAD_FUNCPTR(FT_Library_Version)
2950 LOAD_FUNCPTR(FT_Load_Glyph)
2951 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2952 LOAD_FUNCPTR(FT_Matrix_Multiply)
2953 #ifndef FT_MULFIX_INLINED
2954 LOAD_FUNCPTR(FT_MulFix)
2955 #endif
2956 LOAD_FUNCPTR(FT_New_Face)
2957 LOAD_FUNCPTR(FT_New_Memory_Face)
2958 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2959 LOAD_FUNCPTR(FT_Outline_Transform)
2960 LOAD_FUNCPTR(FT_Outline_Translate)
2961 LOAD_FUNCPTR(FT_Render_Glyph)
2962 LOAD_FUNCPTR(FT_Select_Charmap)
2963 LOAD_FUNCPTR(FT_Set_Charmap)
2964 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2965 LOAD_FUNCPTR(FT_Vector_Transform)
2966 LOAD_FUNCPTR(FT_Vector_Unit)
2967 #undef LOAD_FUNCPTR
2968 /* Don't warn if these ones are missing */
2969 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2970 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2971 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2972 #endif
2974 if(pFT_Init_FreeType(&library) != 0) {
2975 ERR("Can't init FreeType library\n");
2976 wine_dlclose(ft_handle, NULL, 0);
2977 ft_handle = NULL;
2978 return FALSE;
2980 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2982 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2983 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2984 ((FT_Version.minor << 8) & 0x00ff00) |
2985 ((FT_Version.patch ) & 0x0000ff);
2987 font_driver = &freetype_funcs;
2988 return TRUE;
2990 sym_not_found:
2991 WINE_MESSAGE(
2992 "Wine cannot find certain functions that it needs inside the FreeType\n"
2993 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2994 "FreeType to at least version 2.1.4.\n"
2995 "http://www.freetype.org\n");
2996 wine_dlclose(ft_handle, NULL, 0);
2997 ft_handle = NULL;
2998 return FALSE;
3001 static void init_font_list(void)
3003 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3004 static const WCHAR pathW[] = {'P','a','t','h',0};
3005 HKEY hkey;
3006 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3007 WCHAR windowsdir[MAX_PATH];
3008 char *unixname;
3009 const char *home;
3010 const char *data_dir;
3012 delete_external_font_keys();
3014 /* load the system bitmap fonts */
3015 load_system_fonts();
3017 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3018 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3019 strcatW(windowsdir, fontsW);
3020 if((unixname = wine_get_unix_file_name(windowsdir)))
3022 ReadFontDir(unixname, FALSE);
3023 HeapFree(GetProcessHeap(), 0, unixname);
3026 /* load the system truetype fonts */
3027 data_dir = wine_get_data_dir();
3028 if (!data_dir) data_dir = wine_get_build_dir();
3029 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3031 strcpy(unixname, data_dir);
3032 strcat(unixname, "/fonts/");
3033 ReadFontDir(unixname, TRUE);
3034 HeapFree(GetProcessHeap(), 0, unixname);
3037 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3038 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3039 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3040 will skip these. */
3041 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3042 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3043 &hkey) == ERROR_SUCCESS)
3045 LPWSTR data, valueW;
3046 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3047 &valuelen, &datalen, NULL, NULL);
3049 valuelen++; /* returned value doesn't include room for '\0' */
3050 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3051 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3052 if (valueW && data)
3054 dlen = datalen * sizeof(WCHAR);
3055 vlen = valuelen;
3056 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3057 &dlen) == ERROR_SUCCESS)
3059 if(data[0] && (data[1] == ':'))
3061 if((unixname = wine_get_unix_file_name(data)))
3063 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3064 HeapFree(GetProcessHeap(), 0, unixname);
3067 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3069 WCHAR pathW[MAX_PATH];
3070 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3071 BOOL added = FALSE;
3073 sprintfW(pathW, fmtW, windowsdir, data);
3074 if((unixname = wine_get_unix_file_name(pathW)))
3076 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3077 HeapFree(GetProcessHeap(), 0, unixname);
3079 if (!added)
3080 load_font_from_data_dir(data);
3082 /* reset dlen and vlen */
3083 dlen = datalen;
3084 vlen = valuelen;
3087 HeapFree(GetProcessHeap(), 0, data);
3088 HeapFree(GetProcessHeap(), 0, valueW);
3089 RegCloseKey(hkey);
3092 load_fontconfig_fonts();
3094 /* then look in any directories that we've specified in the config file */
3095 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3096 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3098 DWORD len;
3099 LPWSTR valueW;
3100 LPSTR valueA, ptr;
3102 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3104 len += sizeof(WCHAR);
3105 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3106 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3108 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3109 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3110 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3111 TRACE( "got font path %s\n", debugstr_a(valueA) );
3112 ptr = valueA;
3113 while (ptr)
3115 LPSTR next = strchr( ptr, ':' );
3116 if (next) *next++ = 0;
3117 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3118 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3120 strcpy( unixname, home );
3121 strcat( unixname, ptr + 1 );
3122 ReadFontDir( unixname, TRUE );
3123 HeapFree( GetProcessHeap(), 0, unixname );
3125 else
3126 ReadFontDir( ptr, TRUE );
3127 ptr = next;
3129 HeapFree( GetProcessHeap(), 0, valueA );
3131 HeapFree( GetProcessHeap(), 0, valueW );
3133 RegCloseKey(hkey);
3136 #ifdef __APPLE__
3137 /* Mac default font locations. */
3138 ReadFontDir( "/Library/Fonts", TRUE );
3139 ReadFontDir( "/Network/Library/Fonts", TRUE );
3140 ReadFontDir( "/System/Library/Fonts", TRUE );
3141 if ((home = getenv( "HOME" )))
3143 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3144 strcpy( unixname, home );
3145 strcat( unixname, "/Library/Fonts" );
3146 ReadFontDir( unixname, TRUE);
3147 HeapFree( GetProcessHeap(), 0, unixname );
3149 #endif
3152 static BOOL move_to_front(const WCHAR *name)
3154 Family *family, *cursor2;
3155 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3157 if(!strcmpiW(family->FamilyName, name))
3159 list_remove(&family->entry);
3160 list_add_head(&font_list, &family->entry);
3161 return TRUE;
3164 return FALSE;
3167 static BOOL set_default(const WCHAR **name_list)
3169 while (*name_list)
3171 if (move_to_front(*name_list)) return TRUE;
3172 name_list++;
3175 return FALSE;
3178 static void reorder_font_list(void)
3180 set_default( default_serif_list );
3181 set_default( default_fixed_list );
3182 set_default( default_sans_list );
3185 /*************************************************************
3186 * WineEngInit
3188 * Initialize FreeType library and create a list of available faces
3190 BOOL WineEngInit(void)
3192 HKEY hkey_font_cache;
3193 DWORD disposition;
3194 HANDLE font_mutex;
3196 /* update locale dependent font info in registry */
3197 update_font_info();
3199 if(!init_freetype()) return FALSE;
3201 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3203 ERR("Failed to create font mutex\n");
3204 return FALSE;
3206 WaitForSingleObject(font_mutex, INFINITE);
3208 create_font_cache_key(&hkey_font_cache, &disposition);
3210 if(disposition == REG_CREATED_NEW_KEY)
3211 init_font_list();
3212 else
3213 load_font_list_from_cache(hkey_font_cache);
3215 RegCloseKey(hkey_font_cache);
3217 reorder_font_list();
3219 DumpFontList();
3220 LoadSubstList();
3221 DumpSubstList();
3222 LoadReplaceList();
3224 if(disposition == REG_CREATED_NEW_KEY)
3225 update_reg_entries();
3227 init_system_links();
3229 ReleaseMutex(font_mutex);
3230 return TRUE;
3234 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3236 TT_OS2 *pOS2;
3237 TT_HoriHeader *pHori;
3239 LONG ppem;
3241 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3242 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3244 if(height == 0) height = 16;
3246 /* Calc. height of EM square:
3248 * For +ve lfHeight we have
3249 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3250 * Re-arranging gives:
3251 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3253 * For -ve lfHeight we have
3254 * |lfHeight| = ppem
3255 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3256 * with il = winAscent + winDescent - units_per_em]
3260 if(height > 0) {
3261 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3262 ppem = MulDiv(ft_face->units_per_EM, height,
3263 pHori->Ascender - pHori->Descender);
3264 else
3265 ppem = MulDiv(ft_face->units_per_EM, height,
3266 pOS2->usWinAscent + pOS2->usWinDescent);
3268 else
3269 ppem = -height;
3271 return ppem;
3274 static struct font_mapping *map_font_file( const char *name )
3276 struct font_mapping *mapping;
3277 struct stat st;
3278 int fd;
3280 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3281 if (fstat( fd, &st ) == -1) goto error;
3283 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3285 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3287 mapping->refcount++;
3288 close( fd );
3289 return mapping;
3292 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3293 goto error;
3295 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3296 close( fd );
3298 if (mapping->data == MAP_FAILED)
3300 HeapFree( GetProcessHeap(), 0, mapping );
3301 return NULL;
3303 mapping->refcount = 1;
3304 mapping->dev = st.st_dev;
3305 mapping->ino = st.st_ino;
3306 mapping->size = st.st_size;
3307 list_add_tail( &mappings_list, &mapping->entry );
3308 return mapping;
3310 error:
3311 close( fd );
3312 return NULL;
3315 static void unmap_font_file( struct font_mapping *mapping )
3317 if (!--mapping->refcount)
3319 list_remove( &mapping->entry );
3320 munmap( mapping->data, mapping->size );
3321 HeapFree( GetProcessHeap(), 0, mapping );
3325 static LONG load_VDMX(GdiFont*, LONG);
3327 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3329 FT_Error err;
3330 FT_Face ft_face;
3331 void *data_ptr;
3332 DWORD data_size;
3334 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3336 if (face->file)
3338 if (!(font->mapping = map_font_file( face->file )))
3340 WARN("failed to map %s\n", debugstr_a(face->file));
3341 return 0;
3343 data_ptr = font->mapping->data;
3344 data_size = font->mapping->size;
3346 else
3348 data_ptr = face->font_data_ptr;
3349 data_size = face->font_data_size;
3352 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3353 if(err) {
3354 ERR("FT_New_Face rets %d\n", err);
3355 return 0;
3358 /* set it here, as load_VDMX needs it */
3359 font->ft_face = ft_face;
3361 if(FT_IS_SCALABLE(ft_face)) {
3362 /* load the VDMX table if we have one */
3363 font->ppem = load_VDMX(font, height);
3364 if(font->ppem == 0)
3365 font->ppem = calc_ppem_for_height(ft_face, height);
3366 TRACE("height %d => ppem %d\n", height, font->ppem);
3368 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3369 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3370 } else {
3371 font->ppem = height;
3372 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3373 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3375 return ft_face;
3379 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3381 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3382 a single face with the requested charset. The idea is to check if
3383 the selected font supports the current ANSI codepage, if it does
3384 return the corresponding charset, else return the first charset */
3386 CHARSETINFO csi;
3387 int acp = GetACP(), i;
3388 DWORD fs0;
3390 *cp = acp;
3391 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3393 const SYSTEM_LINKS *font_link;
3395 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3396 return csi.ciCharset;
3398 font_link = find_font_link(family_name);
3399 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3400 return csi.ciCharset;
3403 for(i = 0; i < 32; i++) {
3404 fs0 = 1L << i;
3405 if(face->fs.fsCsb[0] & fs0) {
3406 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3407 *cp = csi.ciACP;
3408 return csi.ciCharset;
3410 else
3411 FIXME("TCI failing on %x\n", fs0);
3415 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3416 face->fs.fsCsb[0], face->file);
3417 *cp = acp;
3418 return DEFAULT_CHARSET;
3421 static GdiFont *alloc_font(void)
3423 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3424 ret->gmsize = 1;
3425 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3426 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3427 ret->potm = NULL;
3428 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3429 ret->total_kern_pairs = (DWORD)-1;
3430 ret->kern_pairs = NULL;
3431 list_init(&ret->hfontlist);
3432 list_init(&ret->child_fonts);
3433 return ret;
3436 static void free_font(GdiFont *font)
3438 struct list *cursor, *cursor2;
3439 DWORD i;
3441 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3443 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3444 list_remove(cursor);
3445 if(child->font)
3446 free_font(child->font);
3447 HeapFree(GetProcessHeap(), 0, child);
3450 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3452 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3453 DeleteObject(hfontlist->hfont);
3454 list_remove(&hfontlist->entry);
3455 HeapFree(GetProcessHeap(), 0, hfontlist);
3458 if (font->ft_face) pFT_Done_Face(font->ft_face);
3459 if (font->mapping) unmap_font_file( font->mapping );
3460 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3461 HeapFree(GetProcessHeap(), 0, font->potm);
3462 HeapFree(GetProcessHeap(), 0, font->name);
3463 for (i = 0; i < font->gmsize; i++)
3464 HeapFree(GetProcessHeap(),0,font->gm[i]);
3465 HeapFree(GetProcessHeap(), 0, font->gm);
3466 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3467 HeapFree(GetProcessHeap(), 0, font);
3471 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3473 FT_Face ft_face = font->ft_face;
3474 FT_ULong len;
3475 FT_Error err;
3477 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3479 if(!buf)
3480 len = 0;
3481 else
3482 len = cbData;
3484 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3486 /* make sure value of len is the value freetype says it needs */
3487 if (buf && len)
3489 FT_ULong needed = 0;
3490 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3491 if( !err && needed < len) len = needed;
3493 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3494 if (err)
3496 TRACE("Can't find table %c%c%c%c\n",
3497 /* bytes were reversed */
3498 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3499 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3500 return GDI_ERROR;
3502 return len;
3505 /*************************************************************
3506 * load_VDMX
3508 * load the vdmx entry for the specified height
3511 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3512 ( ( (FT_ULong)_x4 << 24 ) | \
3513 ( (FT_ULong)_x3 << 16 ) | \
3514 ( (FT_ULong)_x2 << 8 ) | \
3515 (FT_ULong)_x1 )
3517 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3519 typedef struct {
3520 BYTE bCharSet;
3521 BYTE xRatio;
3522 BYTE yStartRatio;
3523 BYTE yEndRatio;
3524 } Ratios;
3526 typedef struct {
3527 WORD recs;
3528 BYTE startsz;
3529 BYTE endsz;
3530 } VDMX_group;
3532 static LONG load_VDMX(GdiFont *font, LONG height)
3534 WORD hdr[3], tmp;
3535 VDMX_group group;
3536 BYTE devXRatio, devYRatio;
3537 USHORT numRecs, numRatios;
3538 DWORD result, offset = -1;
3539 LONG ppem = 0;
3540 int i;
3542 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3544 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3545 return ppem;
3547 /* FIXME: need the real device aspect ratio */
3548 devXRatio = 1;
3549 devYRatio = 1;
3551 numRecs = GET_BE_WORD(hdr[1]);
3552 numRatios = GET_BE_WORD(hdr[2]);
3554 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3555 for(i = 0; i < numRatios; i++) {
3556 Ratios ratio;
3558 offset = (3 * 2) + (i * sizeof(Ratios));
3559 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3560 offset = -1;
3562 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3564 if((ratio.xRatio == 0 &&
3565 ratio.yStartRatio == 0 &&
3566 ratio.yEndRatio == 0) ||
3567 (devXRatio == ratio.xRatio &&
3568 devYRatio >= ratio.yStartRatio &&
3569 devYRatio <= ratio.yEndRatio))
3571 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3572 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3573 offset = GET_BE_WORD(tmp);
3574 break;
3578 if(offset == -1) {
3579 FIXME("No suitable ratio found\n");
3580 return ppem;
3583 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3584 USHORT recs;
3585 BYTE startsz, endsz;
3586 WORD *vTable;
3588 recs = GET_BE_WORD(group.recs);
3589 startsz = group.startsz;
3590 endsz = group.endsz;
3592 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3594 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3595 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3596 if(result == GDI_ERROR) {
3597 FIXME("Failed to retrieve vTable\n");
3598 goto end;
3601 if(height > 0) {
3602 for(i = 0; i < recs; i++) {
3603 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3604 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3605 ppem = GET_BE_WORD(vTable[i * 3]);
3607 if(yMax + -yMin == height) {
3608 font->yMax = yMax;
3609 font->yMin = yMin;
3610 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3611 break;
3613 if(yMax + -yMin > height) {
3614 if(--i < 0) {
3615 ppem = 0;
3616 goto end; /* failed */
3618 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3619 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3620 ppem = GET_BE_WORD(vTable[i * 3]);
3621 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3622 break;
3625 if(!font->yMax) {
3626 ppem = 0;
3627 TRACE("ppem not found for height %d\n", height);
3630 end:
3631 HeapFree(GetProcessHeap(), 0, vTable);
3634 return ppem;
3637 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3639 if(font->font_desc.hash != fd->hash) return TRUE;
3640 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3641 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3642 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3643 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3646 static void calc_hash(FONT_DESC *pfd)
3648 DWORD hash = 0, *ptr, two_chars;
3649 WORD *pwc;
3650 unsigned int i;
3652 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3653 hash ^= *ptr;
3654 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3655 hash ^= *ptr;
3656 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3657 two_chars = *ptr;
3658 pwc = (WCHAR *)&two_chars;
3659 if(!*pwc) break;
3660 *pwc = toupperW(*pwc);
3661 pwc++;
3662 *pwc = toupperW(*pwc);
3663 hash ^= two_chars;
3664 if(!*pwc) break;
3666 hash ^= !pfd->can_use_bitmap;
3667 pfd->hash = hash;
3668 return;
3671 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3673 GdiFont *ret;
3674 FONT_DESC fd;
3675 HFONTLIST *hflist;
3676 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3678 fd.lf = *plf;
3679 fd.matrix = *pmat;
3680 fd.can_use_bitmap = can_use_bitmap;
3681 calc_hash(&fd);
3683 /* try the child list */
3684 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3685 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3686 if(!fontcmp(ret, &fd)) {
3687 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3688 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3689 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3690 if(hflist->hfont == hfont)
3691 return ret;
3696 /* try the in-use list */
3697 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3698 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3699 if(!fontcmp(ret, &fd)) {
3700 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3701 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3702 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3703 if(hflist->hfont == hfont)
3704 return ret;
3706 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3707 hflist->hfont = hfont;
3708 list_add_head(&ret->hfontlist, &hflist->entry);
3709 return ret;
3713 /* then the unused list */
3714 font_elem_ptr = list_head(&unused_gdi_font_list);
3715 while(font_elem_ptr) {
3716 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3717 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3718 if(!fontcmp(ret, &fd)) {
3719 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3720 assert(list_empty(&ret->hfontlist));
3721 TRACE("Found %p in unused list\n", ret);
3722 list_remove(&ret->entry);
3723 list_add_head(&gdi_font_list, &ret->entry);
3724 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3725 hflist->hfont = hfont;
3726 list_add_head(&ret->hfontlist, &hflist->entry);
3727 return ret;
3730 return NULL;
3733 static void add_to_cache(GdiFont *font)
3735 static DWORD cache_num = 1;
3737 font->cache_num = cache_num++;
3738 list_add_head(&gdi_font_list, &font->entry);
3741 /*************************************************************
3742 * create_child_font_list
3744 static BOOL create_child_font_list(GdiFont *font)
3746 BOOL ret = FALSE;
3747 SYSTEM_LINKS *font_link;
3748 CHILD_FONT *font_link_entry, *new_child;
3749 FontSubst *psub;
3750 WCHAR* font_name;
3752 psub = get_font_subst(&font_subst_list, font->name, -1);
3753 font_name = psub ? psub->to.name : font->name;
3754 font_link = find_font_link(font_name);
3755 if (font_link != NULL)
3757 TRACE("found entry in system list\n");
3758 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3760 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3761 new_child->face = font_link_entry->face;
3762 new_child->font = NULL;
3763 list_add_tail(&font->child_fonts, &new_child->entry);
3764 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3766 ret = TRUE;
3769 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3770 * Sans Serif. This is how asian windows get default fallbacks for fonts
3772 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3773 font->charset != OEM_CHARSET &&
3774 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3776 font_link = find_font_link(szDefaultFallbackLink);
3777 if (font_link != NULL)
3779 TRACE("found entry in default fallback list\n");
3780 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3782 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3783 new_child->face = font_link_entry->face;
3784 new_child->font = NULL;
3785 list_add_tail(&font->child_fonts, &new_child->entry);
3786 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3788 ret = TRUE;
3792 return ret;
3795 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3797 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3799 if (pFT_Set_Charmap)
3801 FT_Int i;
3802 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3804 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3806 for (i = 0; i < ft_face->num_charmaps; i++)
3808 if (ft_face->charmaps[i]->encoding == encoding)
3810 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3811 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3813 switch (ft_face->charmaps[i]->platform_id)
3815 default:
3816 cmap_def = ft_face->charmaps[i];
3817 break;
3818 case 0: /* Apple Unicode */
3819 cmap0 = ft_face->charmaps[i];
3820 break;
3821 case 1: /* Macintosh */
3822 cmap1 = ft_face->charmaps[i];
3823 break;
3824 case 2: /* ISO */
3825 cmap2 = ft_face->charmaps[i];
3826 break;
3827 case 3: /* Microsoft */
3828 cmap3 = ft_face->charmaps[i];
3829 break;
3833 if (cmap3) /* prefer Microsoft cmap table */
3834 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3835 else if (cmap1)
3836 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3837 else if (cmap2)
3838 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3839 else if (cmap0)
3840 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3841 else if (cmap_def)
3842 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3844 return ft_err == FT_Err_Ok;
3847 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3851 /*************************************************************
3852 * freetype_CreateDC
3854 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3855 LPCWSTR output, const DEVMODEW *devmode )
3857 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3859 if (!physdev) return FALSE;
3860 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3861 return TRUE;
3865 /*************************************************************
3866 * freetype_DeleteDC
3868 static BOOL freetype_DeleteDC( PHYSDEV dev )
3870 struct freetype_physdev *physdev = get_freetype_dev( dev );
3871 HeapFree( GetProcessHeap(), 0, physdev );
3872 return TRUE;
3876 /*************************************************************
3877 * freetype_SelectFont
3879 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3881 struct freetype_physdev *physdev = get_freetype_dev( dev );
3882 GdiFont *ret;
3883 Face *face, *best, *best_bitmap;
3884 Family *family, *last_resort_family;
3885 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
3886 INT height, width = 0;
3887 unsigned int score = 0, new_score;
3888 signed int diff = 0, newdiff;
3889 BOOL bd, it, can_use_bitmap, want_vertical;
3890 LOGFONTW lf;
3891 CHARSETINFO csi;
3892 HFONTLIST *hflist;
3893 FMAT2 dcmat;
3894 FontSubst *psub = NULL;
3895 DC *dc = get_dc_ptr( dev->hdc );
3896 const SYSTEM_LINKS *font_link;
3898 if (!hfont) /* notification that the font has been changed by another driver */
3900 dc->gdiFont = NULL;
3901 physdev->font = NULL;
3902 release_dc_ptr( dc );
3903 return 0;
3906 GetObjectW( hfont, sizeof(lf), &lf );
3907 lf.lfWidth = abs(lf.lfWidth);
3909 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3911 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3912 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3913 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3914 lf.lfEscapement);
3916 if(dc->GraphicsMode == GM_ADVANCED)
3918 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3919 /* Try to avoid not necessary glyph transformations */
3920 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3922 lf.lfHeight *= fabs(dcmat.eM11);
3923 lf.lfWidth *= fabs(dcmat.eM11);
3924 dcmat.eM11 = dcmat.eM22 = 1.0;
3927 else
3929 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3930 font scaling abilities. */
3931 dcmat.eM11 = dcmat.eM22 = 1.0;
3932 dcmat.eM21 = dcmat.eM12 = 0;
3933 if (dc->vport2WorldValid)
3935 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
3936 lf.lfOrientation = -lf.lfOrientation;
3937 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
3938 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
3942 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3943 dcmat.eM21, dcmat.eM22);
3945 GDI_CheckNotLock();
3946 EnterCriticalSection( &freetype_cs );
3948 /* check the cache first */
3949 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3950 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3951 goto done;
3954 if(list_empty(&font_list)) /* No fonts installed */
3956 TRACE("No fonts installed\n");
3957 goto done;
3960 TRACE("not in cache\n");
3961 ret = alloc_font();
3963 ret->font_desc.matrix = dcmat;
3964 ret->font_desc.lf = lf;
3965 ret->font_desc.can_use_bitmap = can_use_bitmap;
3966 calc_hash(&ret->font_desc);
3967 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3968 hflist->hfont = hfont;
3969 list_add_head(&ret->hfontlist, &hflist->entry);
3971 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3972 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3973 original value lfCharSet. Note this is a special case for
3974 Symbol and doesn't happen at least for "Wingdings*" */
3976 if(!strcmpiW(lf.lfFaceName, SymbolW))
3977 lf.lfCharSet = SYMBOL_CHARSET;
3979 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3980 switch(lf.lfCharSet) {
3981 case DEFAULT_CHARSET:
3982 csi.fs.fsCsb[0] = 0;
3983 break;
3984 default:
3985 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3986 csi.fs.fsCsb[0] = 0;
3987 break;
3991 family = NULL;
3992 if(lf.lfFaceName[0] != '\0') {
3993 CHILD_FONT *font_link_entry;
3994 LPWSTR FaceName = lf.lfFaceName;
3996 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3998 if(psub) {
3999 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4000 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4001 if (psub->to.charset != -1)
4002 lf.lfCharSet = psub->to.charset;
4005 /* We want a match on name and charset or just name if
4006 charset was DEFAULT_CHARSET. If the latter then
4007 we fixup the returned charset later in get_nearest_charset
4008 where we'll either use the charset of the current ansi codepage
4009 or if that's unavailable the first charset that the font supports.
4011 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4012 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4013 if (!strcmpiW(family->FamilyName, FaceName) ||
4014 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4016 font_link = find_font_link(family->FamilyName);
4017 face_list = get_face_list_from_family(family);
4018 LIST_FOR_EACH(face_elem_ptr, face_list) {
4019 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4020 if (!(face->scalable || can_use_bitmap))
4021 continue;
4022 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4023 goto found;
4024 if (font_link != NULL &&
4025 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4026 goto found;
4027 if (!csi.fs.fsCsb[0])
4028 goto found;
4033 /* Search by full face name. */
4034 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4035 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4036 face_list = get_face_list_from_family(family);
4037 LIST_FOR_EACH(face_elem_ptr, face_list) {
4038 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4039 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4040 (face->scalable || can_use_bitmap))
4042 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4043 goto found_face;
4044 font_link = find_font_link(family->FamilyName);
4045 if (font_link != NULL &&
4046 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4047 goto found_face;
4053 * Try check the SystemLink list first for a replacement font.
4054 * We may find good replacements there.
4056 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4058 if(!strcmpiW(font_link->font_name, FaceName) ||
4059 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4061 TRACE("found entry in system list\n");
4062 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4064 const SYSTEM_LINKS *links;
4066 face = font_link_entry->face;
4067 if (!(face->scalable || can_use_bitmap))
4068 continue;
4069 family = face->family;
4070 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4071 goto found;
4072 links = find_font_link(family->FamilyName);
4073 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4074 goto found;
4080 psub = NULL; /* substitution is no more relevant */
4082 /* If requested charset was DEFAULT_CHARSET then try using charset
4083 corresponding to the current ansi codepage */
4084 if (!csi.fs.fsCsb[0])
4086 INT acp = GetACP();
4087 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4088 FIXME("TCI failed on codepage %d\n", acp);
4089 csi.fs.fsCsb[0] = 0;
4090 } else
4091 lf.lfCharSet = csi.ciCharset;
4094 want_vertical = (lf.lfFaceName[0] == '@');
4096 /* Face families are in the top 4 bits of lfPitchAndFamily,
4097 so mask with 0xF0 before testing */
4099 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4100 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4101 strcpyW(lf.lfFaceName, defFixed);
4102 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4103 strcpyW(lf.lfFaceName, defSerif);
4104 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4105 strcpyW(lf.lfFaceName, defSans);
4106 else
4107 strcpyW(lf.lfFaceName, defSans);
4108 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4109 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4110 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4111 font_link = find_font_link(family->FamilyName);
4112 face_list = get_face_list_from_family(family);
4113 LIST_FOR_EACH(face_elem_ptr, face_list) {
4114 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4115 if (!(face->scalable || can_use_bitmap))
4116 continue;
4117 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4118 goto found;
4119 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4120 goto found;
4125 last_resort_family = NULL;
4126 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4127 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4128 font_link = find_font_link(family->FamilyName);
4129 face_list = get_face_list_from_family(family);
4130 LIST_FOR_EACH(face_elem_ptr, face_list) {
4131 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4132 if(face->vertical == want_vertical &&
4133 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4134 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4135 if(face->scalable)
4136 goto found;
4137 if(can_use_bitmap && !last_resort_family)
4138 last_resort_family = family;
4143 if(last_resort_family) {
4144 family = last_resort_family;
4145 csi.fs.fsCsb[0] = 0;
4146 goto found;
4149 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4150 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4151 face_list = get_face_list_from_family(family);
4152 LIST_FOR_EACH(face_elem_ptr, face_list) {
4153 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4154 if(face->scalable && face->vertical == want_vertical) {
4155 csi.fs.fsCsb[0] = 0;
4156 WARN("just using first face for now\n");
4157 goto found;
4159 if(can_use_bitmap && !last_resort_family)
4160 last_resort_family = family;
4163 if(!last_resort_family) {
4164 FIXME("can't find a single appropriate font - bailing\n");
4165 free_font(ret);
4166 ret = NULL;
4167 goto done;
4170 WARN("could only find a bitmap font - this will probably look awful!\n");
4171 family = last_resort_family;
4172 csi.fs.fsCsb[0] = 0;
4174 found:
4175 it = lf.lfItalic ? 1 : 0;
4176 bd = lf.lfWeight > 550 ? 1 : 0;
4178 height = lf.lfHeight;
4180 face = best = best_bitmap = NULL;
4181 font_link = find_font_link(family->FamilyName);
4182 face_list = get_face_list_from_family(family);
4183 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4185 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4186 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4187 !csi.fs.fsCsb[0])
4189 BOOL italic, bold;
4191 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4192 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4193 new_score = (italic ^ it) + (bold ^ bd);
4194 if(!best || new_score <= score)
4196 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4197 italic, bold, it, bd);
4198 score = new_score;
4199 best = face;
4200 if(best->scalable && score == 0) break;
4201 if(!best->scalable)
4203 if(height > 0)
4204 newdiff = height - (signed int)(best->size.height);
4205 else
4206 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4207 if(!best_bitmap || new_score < score ||
4208 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4210 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4211 diff = newdiff;
4212 best_bitmap = best;
4213 if(score == 0 && diff == 0) break;
4219 if(best)
4220 face = best->scalable ? best : best_bitmap;
4221 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4222 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4224 found_face:
4225 height = lf.lfHeight;
4227 ret->fs = face->fs;
4229 if(csi.fs.fsCsb[0]) {
4230 ret->charset = lf.lfCharSet;
4231 ret->codepage = csi.ciACP;
4233 else
4234 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4236 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4237 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4239 ret->aveWidth = height ? lf.lfWidth : 0;
4241 if(!face->scalable) {
4242 /* Windows uses integer scaling factors for bitmap fonts */
4243 INT scale, scaled_height;
4244 GdiFont *cachedfont;
4246 /* FIXME: rotation of bitmap fonts is ignored */
4247 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4248 if (ret->aveWidth)
4249 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4250 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4251 dcmat.eM11 = dcmat.eM22 = 1.0;
4252 /* As we changed the matrix, we need to search the cache for the font again,
4253 * otherwise we might explode the cache. */
4254 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4255 TRACE("Found cached font after non-scalable matrix rescale!\n");
4256 free_font( ret );
4257 ret = cachedfont;
4258 goto done;
4260 calc_hash(&ret->font_desc);
4262 if (height != 0) height = diff;
4263 height += face->size.height;
4265 scale = (height + face->size.height - 1) / face->size.height;
4266 scaled_height = scale * face->size.height;
4267 /* Only jump to the next height if the difference <= 25% original height */
4268 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4269 /* The jump between unscaled and doubled is delayed by 1 */
4270 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4271 ret->scale_y = scale;
4273 width = face->size.x_ppem >> 6;
4274 height = face->size.y_ppem >> 6;
4276 else
4277 ret->scale_y = 1.0;
4278 TRACE("font scale y: %f\n", ret->scale_y);
4280 ret->ft_face = OpenFontFace(ret, face, width, height);
4282 if (!ret->ft_face)
4284 free_font( ret );
4285 ret = NULL;
4286 goto done;
4289 ret->ntmFlags = face->ntmFlags;
4291 if (ret->charset == SYMBOL_CHARSET &&
4292 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4293 /* No ops */
4295 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4296 /* No ops */
4298 else {
4299 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4302 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4303 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4304 ret->underline = lf.lfUnderline ? 0xff : 0;
4305 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4306 create_child_font_list(ret);
4308 if (face->vertical) /* We need to try to load the GSUB table */
4310 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4311 if (length != GDI_ERROR)
4313 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4314 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4315 TRACE("Loaded GSUB table of %i bytes\n",length);
4319 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4321 add_to_cache(ret);
4322 done:
4323 if (ret)
4325 dc->gdiFont = ret;
4326 physdev->font = ret;
4328 LeaveCriticalSection( &freetype_cs );
4329 release_dc_ptr( dc );
4330 return ret ? hfont : 0;
4333 static void dump_gdi_font_list(void)
4335 GdiFont *gdiFont;
4336 struct list *elem_ptr;
4338 TRACE("---------- gdiFont Cache ----------\n");
4339 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4340 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4341 TRACE("gdiFont=%p %s %d\n",
4342 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4345 TRACE("---------- Unused gdiFont Cache ----------\n");
4346 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4347 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4348 TRACE("gdiFont=%p %s %d\n",
4349 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4352 TRACE("---------- Child gdiFont Cache ----------\n");
4353 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4354 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4355 TRACE("gdiFont=%p %s %d\n",
4356 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4360 /*************************************************************
4361 * WineEngDestroyFontInstance
4363 * free the gdiFont associated with this handle
4366 BOOL WineEngDestroyFontInstance(HFONT handle)
4368 GdiFont *gdiFont;
4369 HFONTLIST *hflist;
4370 BOOL ret = FALSE;
4371 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4372 int i = 0;
4374 GDI_CheckNotLock();
4375 EnterCriticalSection( &freetype_cs );
4377 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4379 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4380 while(hfontlist_elem_ptr) {
4381 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4382 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4383 if(hflist->hfont == handle) {
4384 TRACE("removing child font %p from child list\n", gdiFont);
4385 list_remove(&gdiFont->entry);
4386 LeaveCriticalSection( &freetype_cs );
4387 return TRUE;
4392 TRACE("destroying hfont=%p\n", handle);
4393 if(TRACE_ON(font))
4394 dump_gdi_font_list();
4396 font_elem_ptr = list_head(&gdi_font_list);
4397 while(font_elem_ptr) {
4398 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4399 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4401 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4402 while(hfontlist_elem_ptr) {
4403 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4404 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4405 if(hflist->hfont == handle) {
4406 list_remove(&hflist->entry);
4407 HeapFree(GetProcessHeap(), 0, hflist);
4408 ret = TRUE;
4411 if(list_empty(&gdiFont->hfontlist)) {
4412 TRACE("Moving to Unused list\n");
4413 list_remove(&gdiFont->entry);
4414 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4419 font_elem_ptr = list_head(&unused_gdi_font_list);
4420 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4421 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4422 while(font_elem_ptr) {
4423 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4424 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4425 TRACE("freeing %p\n", gdiFont);
4426 list_remove(&gdiFont->entry);
4427 free_font(gdiFont);
4429 LeaveCriticalSection( &freetype_cs );
4430 return ret;
4433 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4435 HRSRC rsrc;
4436 HGLOBAL hMem;
4437 WCHAR *p;
4438 int i;
4440 id += IDS_FIRST_SCRIPT;
4441 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4442 if (!rsrc) return 0;
4443 hMem = LoadResource( gdi32_module, rsrc );
4444 if (!hMem) return 0;
4446 p = LockResource( hMem );
4447 id &= 0x000f;
4448 while (id--) p += *p + 1;
4450 i = min(LF_FACESIZE - 1, *p);
4451 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4452 buffer[i] = 0;
4453 return i;
4457 /***************************************************
4458 * create_enum_charset_list
4460 * This function creates charset enumeration list because in DEFAULT_CHARSET
4461 * case, the ANSI codepage's charset takes precedence over other charsets.
4462 * This function works as a filter other than DEFAULT_CHARSET case.
4464 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4466 CHARSETINFO csi;
4467 DWORD n = 0;
4469 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4470 csi.fs.fsCsb[0] != 0) {
4471 list->element[n].mask = csi.fs.fsCsb[0];
4472 list->element[n].charset = csi.ciCharset;
4473 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4474 n++;
4476 else { /* charset is DEFAULT_CHARSET or invalid. */
4477 INT acp, i;
4479 /* Set the current codepage's charset as the first element. */
4480 acp = GetACP();
4481 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4482 csi.fs.fsCsb[0] != 0) {
4483 list->element[n].mask = csi.fs.fsCsb[0];
4484 list->element[n].charset = csi.ciCharset;
4485 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4486 n++;
4489 /* Fill out left elements. */
4490 for (i = 0; i < 32; i++) {
4491 FONTSIGNATURE fs;
4492 fs.fsCsb[0] = 1L << i;
4493 fs.fsCsb[1] = 0;
4494 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4495 continue; /* skip, already added. */
4496 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4497 continue; /* skip, this is an invalid fsCsb bit. */
4499 list->element[n].mask = fs.fsCsb[0];
4500 list->element[n].charset = csi.ciCharset;
4501 load_script_name( i, list->element[n].name );
4502 n++;
4505 list->total = n;
4507 return n;
4510 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4511 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4513 GdiFont *font;
4514 LONG width, height;
4516 if (face->cached_enum_data)
4518 TRACE("Cached\n");
4519 *pelf = face->cached_enum_data->elf;
4520 *pntm = face->cached_enum_data->ntm;
4521 *ptype = face->cached_enum_data->type;
4522 return;
4525 font = alloc_font();
4527 if(face->scalable) {
4528 height = -2048; /* 2048 is the most common em size */
4529 width = 0;
4530 } else {
4531 height = face->size.y_ppem >> 6;
4532 width = face->size.x_ppem >> 6;
4534 font->scale_y = 1.0;
4536 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4538 free_font(font);
4539 return;
4542 font->name = strdupW(face->family->FamilyName);
4543 font->ntmFlags = face->ntmFlags;
4545 if (get_outline_text_metrics(font))
4547 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4549 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4551 lstrcpynW(pelf->elfLogFont.lfFaceName,
4552 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4553 LF_FACESIZE);
4554 lstrcpynW(pelf->elfFullName,
4555 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4556 LF_FULLFACESIZE);
4557 lstrcpynW(pelf->elfStyle,
4558 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4559 LF_FACESIZE);
4561 else
4563 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4565 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4567 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4568 if (face->FullName)
4569 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4570 else
4571 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4572 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4575 pntm->ntmTm.ntmFlags = face->ntmFlags;
4576 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4577 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4578 pntm->ntmFontSig = face->fs;
4580 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4582 pelf->elfLogFont.lfEscapement = 0;
4583 pelf->elfLogFont.lfOrientation = 0;
4584 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4585 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4586 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4587 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4588 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4589 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4590 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4591 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4592 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4593 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4594 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4596 *ptype = 0;
4597 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4598 *ptype |= TRUETYPE_FONTTYPE;
4599 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4600 *ptype |= DEVICE_FONTTYPE;
4601 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4602 *ptype |= RASTER_FONTTYPE;
4604 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4605 if (face->cached_enum_data)
4607 face->cached_enum_data->elf = *pelf;
4608 face->cached_enum_data->ntm = *pntm;
4609 face->cached_enum_data->type = *ptype;
4612 free_font(font);
4615 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
4617 static const WCHAR spaceW[] = { ' ', 0 };
4619 strcpyW(full_name, family_name);
4620 strcatW(full_name, spaceW);
4621 strcatW(full_name, style_name);
4624 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4626 const struct list *face_list, *face_elem_ptr;
4628 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4630 face_list = get_face_list_from_family(family);
4631 LIST_FOR_EACH(face_elem_ptr, face_list)
4633 WCHAR full_family_name[LF_FULLFACESIZE];
4634 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4636 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4638 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4639 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4640 continue;
4643 create_full_name(full_family_name, family->FamilyName, face->StyleName);
4644 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4647 return FALSE;
4650 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
4652 WCHAR full_family_name[LF_FULLFACESIZE];
4654 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
4656 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4658 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4659 debugstr_w(family_name), debugstr_w(face->StyleName));
4660 return FALSE;
4663 create_full_name(full_family_name, family_name, face->StyleName);
4664 return !strcmpiW(lf->lfFaceName, full_family_name);
4667 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
4668 FONTENUMPROCW proc, LPARAM lparam)
4670 ENUMLOGFONTEXW elf;
4671 NEWTEXTMETRICEXW ntm;
4672 DWORD type = 0;
4673 int i;
4675 GetEnumStructs(face, &elf, &ntm, &type);
4676 for(i = 0; i < list->total; i++) {
4677 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4678 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4679 load_script_name( IDS_OEM_DOS, elf.elfScript );
4680 i = list->total; /* break out of loop after enumeration */
4681 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4682 continue;
4683 else {
4684 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4685 strcpyW(elf.elfScript, list->element[i].name);
4686 if (!elf.elfScript[0])
4687 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4689 /* Font Replacement */
4690 if (family != face->family)
4692 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
4693 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
4695 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4696 debugstr_w(elf.elfLogFont.lfFaceName),
4697 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4698 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4699 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4700 ntm.ntmTm.ntmFlags);
4701 /* release section before callback (FIXME) */
4702 LeaveCriticalSection( &freetype_cs );
4703 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4704 EnterCriticalSection( &freetype_cs );
4706 return TRUE;
4709 /*************************************************************
4710 * freetype_EnumFonts
4712 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4714 Family *family;
4715 Face *face;
4716 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4717 LOGFONTW lf;
4718 struct enum_charset_list enum_charsets;
4720 if (!plf)
4722 lf.lfCharSet = DEFAULT_CHARSET;
4723 lf.lfPitchAndFamily = 0;
4724 lf.lfFaceName[0] = 0;
4725 plf = &lf;
4728 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4730 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4732 GDI_CheckNotLock();
4733 EnterCriticalSection( &freetype_cs );
4734 if(plf->lfFaceName[0]) {
4735 FontSubst *psub;
4736 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4738 if(psub) {
4739 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4740 debugstr_w(psub->to.name));
4741 lf = *plf;
4742 strcpyW(lf.lfFaceName, psub->to.name);
4743 plf = &lf;
4746 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4747 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4748 if(family_matches(family, plf)) {
4749 face_list = get_face_list_from_family(family);
4750 LIST_FOR_EACH(face_elem_ptr, face_list) {
4751 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4752 if (!face_matches(family->FamilyName, face, plf)) continue;
4753 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4757 } else {
4758 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4759 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4760 face_list = get_face_list_from_family(family);
4761 face_elem_ptr = list_head(face_list);
4762 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4763 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
4766 LeaveCriticalSection( &freetype_cs );
4767 return TRUE;
4770 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4772 pt->x.value = vec->x >> 6;
4773 pt->x.fract = (vec->x & 0x3f) << 10;
4774 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4775 pt->y.value = vec->y >> 6;
4776 pt->y.fract = (vec->y & 0x3f) << 10;
4777 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4778 return;
4781 /***************************************************
4782 * According to the MSDN documentation on WideCharToMultiByte,
4783 * certain codepages cannot set the default_used parameter.
4784 * This returns TRUE if the codepage can set that parameter, false else
4785 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4787 static BOOL codepage_sets_default_used(UINT codepage)
4789 switch (codepage)
4791 case CP_UTF7:
4792 case CP_UTF8:
4793 case CP_SYMBOL:
4794 return FALSE;
4795 default:
4796 return TRUE;
4801 * GSUB Table handling functions
4804 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4806 const GSUB_CoverageFormat1* cf1;
4808 cf1 = table;
4810 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4812 int count = GET_BE_WORD(cf1->GlyphCount);
4813 int i;
4814 TRACE("Coverage Format 1, %i glyphs\n",count);
4815 for (i = 0; i < count; i++)
4816 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4817 return i;
4818 return -1;
4820 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4822 const GSUB_CoverageFormat2* cf2;
4823 int i;
4824 int count;
4825 cf2 = (const GSUB_CoverageFormat2*)cf1;
4827 count = GET_BE_WORD(cf2->RangeCount);
4828 TRACE("Coverage Format 2, %i ranges\n",count);
4829 for (i = 0; i < count; i++)
4831 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4832 return -1;
4833 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4834 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4836 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4837 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4840 return -1;
4842 else
4843 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4845 return -1;
4848 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4850 const GSUB_ScriptList *script;
4851 const GSUB_Script *deflt = NULL;
4852 int i;
4853 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4855 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4856 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4858 const GSUB_Script *scr;
4859 int offset;
4861 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4862 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4864 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4865 return scr;
4866 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4867 deflt = scr;
4869 return deflt;
4872 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4874 int i;
4875 int offset;
4876 const GSUB_LangSys *Lang;
4878 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4880 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4882 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4883 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4885 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4886 return Lang;
4888 offset = GET_BE_WORD(script->DefaultLangSys);
4889 if (offset)
4891 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4892 return Lang;
4894 return NULL;
4897 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4899 int i;
4900 const GSUB_FeatureList *feature;
4901 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4903 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4904 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4906 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4907 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4909 const GSUB_Feature *feat;
4910 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4911 return feat;
4914 return NULL;
4917 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4919 int i;
4920 int offset;
4921 const GSUB_LookupList *lookup;
4922 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4924 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4925 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4927 const GSUB_LookupTable *look;
4928 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4929 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4930 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4931 if (GET_BE_WORD(look->LookupType) != 1)
4932 FIXME("We only handle SubType 1\n");
4933 else
4935 int j;
4937 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4939 const GSUB_SingleSubstFormat1 *ssf1;
4940 offset = GET_BE_WORD(look->SubTable[j]);
4941 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4942 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4944 int offset = GET_BE_WORD(ssf1->Coverage);
4945 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4946 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4948 TRACE(" Glyph 0x%x ->",glyph);
4949 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4950 TRACE(" 0x%x\n",glyph);
4953 else
4955 const GSUB_SingleSubstFormat2 *ssf2;
4956 INT index;
4957 INT offset;
4959 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4960 offset = GET_BE_WORD(ssf1->Coverage);
4961 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4962 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4963 TRACE(" Coverage index %i\n",index);
4964 if (index != -1)
4966 TRACE(" Glyph is 0x%x ->",glyph);
4967 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4968 TRACE("0x%x\n",glyph);
4974 return glyph;
4977 static const char* get_opentype_script(const GdiFont *font)
4980 * I am not sure if this is the correct way to generate our script tag
4983 switch (font->charset)
4985 case ANSI_CHARSET: return "latn";
4986 case BALTIC_CHARSET: return "latn"; /* ?? */
4987 case CHINESEBIG5_CHARSET: return "hani";
4988 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4989 case GB2312_CHARSET: return "hani";
4990 case GREEK_CHARSET: return "grek";
4991 case HANGUL_CHARSET: return "hang";
4992 case RUSSIAN_CHARSET: return "cyrl";
4993 case SHIFTJIS_CHARSET: return "kana";
4994 case TURKISH_CHARSET: return "latn"; /* ?? */
4995 case VIETNAMESE_CHARSET: return "latn";
4996 case JOHAB_CHARSET: return "latn"; /* ?? */
4997 case ARABIC_CHARSET: return "arab";
4998 case HEBREW_CHARSET: return "hebr";
4999 case THAI_CHARSET: return "thai";
5000 default: return "latn";
5004 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5006 const GSUB_Header *header;
5007 const GSUB_Script *script;
5008 const GSUB_LangSys *language;
5009 const GSUB_Feature *feature;
5011 if (!font->GSUB_Table)
5012 return glyph;
5014 header = font->GSUB_Table;
5016 script = GSUB_get_script_table(header, get_opentype_script(font));
5017 if (!script)
5019 TRACE("Script not found\n");
5020 return glyph;
5022 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5023 if (!language)
5025 TRACE("Language not found\n");
5026 return glyph;
5028 feature = GSUB_get_feature(header, language, "vrt2");
5029 if (!feature)
5030 feature = GSUB_get_feature(header, language, "vert");
5031 if (!feature)
5033 TRACE("vrt2/vert feature not found\n");
5034 return glyph;
5036 return GSUB_apply_feature(header, feature, glyph);
5039 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5041 FT_UInt glyphId;
5043 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5044 WCHAR wc = (WCHAR)glyph;
5045 BOOL default_used;
5046 BOOL *default_used_pointer;
5047 FT_UInt ret;
5048 char buf;
5049 default_used_pointer = NULL;
5050 default_used = FALSE;
5051 if (codepage_sets_default_used(font->codepage))
5052 default_used_pointer = &default_used;
5053 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5054 ret = 0;
5055 else
5056 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5057 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5058 return ret;
5061 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5063 if (glyph < 0x100) glyph += 0xf000;
5064 /* there is a number of old pre-Unicode "broken" TTFs, which
5065 do have symbols at U+00XX instead of U+f0XX */
5066 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5067 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5069 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5071 return glyphId;
5074 /*************************************************************
5075 * freetype_GetGlyphIndices
5077 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5079 struct freetype_physdev *physdev = get_freetype_dev( dev );
5080 int i;
5081 WORD default_char;
5082 BOOL got_default = FALSE;
5084 if (!physdev->font)
5086 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5087 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5090 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5092 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5093 got_default = TRUE;
5096 GDI_CheckNotLock();
5097 EnterCriticalSection( &freetype_cs );
5099 for(i = 0; i < count; i++)
5101 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5102 if (pgi[i] == 0)
5104 if (!got_default)
5106 if (FT_IS_SFNT(physdev->font->ft_face))
5108 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5109 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5111 else
5113 TEXTMETRICW textm;
5114 get_text_metrics(physdev->font, &textm);
5115 default_char = textm.tmDefaultChar;
5117 got_default = TRUE;
5119 pgi[i] = default_char;
5122 LeaveCriticalSection( &freetype_cs );
5123 return count;
5126 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5128 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5129 return !memcmp(matrix, &identity, sizeof(FMAT2));
5132 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5134 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5135 return !memcmp(matrix, &identity, sizeof(MAT2));
5138 static inline BYTE get_max_level( UINT format )
5140 switch( format )
5142 case GGO_GRAY2_BITMAP: return 4;
5143 case GGO_GRAY4_BITMAP: return 16;
5144 case GGO_GRAY8_BITMAP: return 64;
5146 return 255;
5149 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5151 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5152 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5153 const MAT2* lpmat)
5155 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5156 FT_Face ft_face = incoming_font->ft_face;
5157 GdiFont *font = incoming_font;
5158 FT_UInt glyph_index;
5159 DWORD width, height, pitch, needed = 0;
5160 FT_Bitmap ft_bitmap;
5161 FT_Error err;
5162 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5163 FT_Angle angle = 0;
5164 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5165 double widthRatio = 1.0;
5166 FT_Matrix transMat = identityMat;
5167 FT_Matrix transMatUnrotated;
5168 BOOL needsTransform = FALSE;
5169 BOOL tategaki = (font->GSUB_Table != NULL);
5170 UINT original_index;
5172 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5173 buflen, buf, lpmat);
5175 TRACE("font transform %f %f %f %f\n",
5176 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5177 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5179 if(format & GGO_GLYPH_INDEX) {
5180 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5181 original_index = glyph;
5182 format &= ~GGO_GLYPH_INDEX;
5183 } else {
5184 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5185 ft_face = font->ft_face;
5186 original_index = glyph_index;
5189 if(format & GGO_UNHINTED) {
5190 load_flags |= FT_LOAD_NO_HINTING;
5191 format &= ~GGO_UNHINTED;
5194 /* tategaki never appears to happen to lower glyph index */
5195 if (glyph_index < TATEGAKI_LOWER_BOUND )
5196 tategaki = FALSE;
5198 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5199 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5200 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5201 font->gmsize * sizeof(GM*));
5202 } else {
5203 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5204 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5206 *lpgm = FONT_GM(font,original_index)->gm;
5207 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5208 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5209 lpgm->gmCellIncX, lpgm->gmCellIncY);
5210 return 1; /* FIXME */
5214 if (!font->gm[original_index / GM_BLOCK_SIZE])
5215 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5217 /* Scaling factor */
5218 if (font->aveWidth)
5220 TEXTMETRICW tm;
5222 get_text_metrics(font, &tm);
5224 widthRatio = (double)font->aveWidth;
5225 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5227 else
5228 widthRatio = font->scale_y;
5230 /* Scaling transform */
5231 if (widthRatio != 1.0 || font->scale_y != 1.0)
5233 FT_Matrix scaleMat;
5234 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5235 scaleMat.xy = 0;
5236 scaleMat.yx = 0;
5237 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5239 pFT_Matrix_Multiply(&scaleMat, &transMat);
5240 needsTransform = TRUE;
5243 /* Slant transform */
5244 if (font->fake_italic) {
5245 FT_Matrix slantMat;
5247 slantMat.xx = (1 << 16);
5248 slantMat.xy = ((1 << 16) >> 2);
5249 slantMat.yx = 0;
5250 slantMat.yy = (1 << 16);
5251 pFT_Matrix_Multiply(&slantMat, &transMat);
5252 needsTransform = TRUE;
5255 /* Rotation transform */
5256 transMatUnrotated = transMat;
5257 if(font->orientation && !tategaki) {
5258 FT_Matrix rotationMat;
5259 FT_Vector vecAngle;
5260 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5261 pFT_Vector_Unit(&vecAngle, angle);
5262 rotationMat.xx = vecAngle.x;
5263 rotationMat.xy = -vecAngle.y;
5264 rotationMat.yx = -rotationMat.xy;
5265 rotationMat.yy = rotationMat.xx;
5267 pFT_Matrix_Multiply(&rotationMat, &transMat);
5268 needsTransform = TRUE;
5271 /* World transform */
5272 if (!is_identity_FMAT2(&font->font_desc.matrix))
5274 FT_Matrix worldMat;
5275 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5276 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5277 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5278 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5279 pFT_Matrix_Multiply(&worldMat, &transMat);
5280 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5281 needsTransform = TRUE;
5284 /* Extra transformation specified by caller */
5285 if (!is_identity_MAT2(lpmat))
5287 FT_Matrix extraMat;
5288 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5289 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5290 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5291 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5292 pFT_Matrix_Multiply(&extraMat, &transMat);
5293 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5294 needsTransform = TRUE;
5297 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5298 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5299 format == GGO_GRAY8_BITMAP))
5301 load_flags |= FT_LOAD_NO_BITMAP;
5304 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5306 if(err) {
5307 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5308 return GDI_ERROR;
5311 if(!needsTransform) {
5312 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5313 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5314 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5316 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5317 bottom = (ft_face->glyph->metrics.horiBearingY -
5318 ft_face->glyph->metrics.height) & -64;
5319 lpgm->gmCellIncX = adv;
5320 lpgm->gmCellIncY = 0;
5321 } else {
5322 INT xc, yc;
5323 FT_Vector vec;
5325 left = right = 0;
5327 for(xc = 0; xc < 2; xc++) {
5328 for(yc = 0; yc < 2; yc++) {
5329 vec.x = (ft_face->glyph->metrics.horiBearingX +
5330 xc * ft_face->glyph->metrics.width);
5331 vec.y = ft_face->glyph->metrics.horiBearingY -
5332 yc * ft_face->glyph->metrics.height;
5333 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5334 pFT_Vector_Transform(&vec, &transMat);
5335 if(xc == 0 && yc == 0) {
5336 left = right = vec.x;
5337 top = bottom = vec.y;
5338 } else {
5339 if(vec.x < left) left = vec.x;
5340 else if(vec.x > right) right = vec.x;
5341 if(vec.y < bottom) bottom = vec.y;
5342 else if(vec.y > top) top = vec.y;
5346 left = left & -64;
5347 right = (right + 63) & -64;
5348 bottom = bottom & -64;
5349 top = (top + 63) & -64;
5351 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5352 vec.x = ft_face->glyph->metrics.horiAdvance;
5353 vec.y = 0;
5354 pFT_Vector_Transform(&vec, &transMat);
5355 lpgm->gmCellIncX = (vec.x+63) >> 6;
5356 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5358 vec.x = ft_face->glyph->metrics.horiAdvance;
5359 vec.y = 0;
5360 pFT_Vector_Transform(&vec, &transMatUnrotated);
5361 adv = (vec.x+63) >> 6;
5364 lsb = left >> 6;
5365 bbx = (right - left) >> 6;
5366 lpgm->gmBlackBoxX = (right - left) >> 6;
5367 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5368 lpgm->gmptGlyphOrigin.x = left >> 6;
5369 lpgm->gmptGlyphOrigin.y = top >> 6;
5371 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5372 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5373 lpgm->gmCellIncX, lpgm->gmCellIncY);
5375 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5376 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5378 FONT_GM(font,original_index)->gm = *lpgm;
5379 FONT_GM(font,original_index)->adv = adv;
5380 FONT_GM(font,original_index)->lsb = lsb;
5381 FONT_GM(font,original_index)->bbx = bbx;
5382 FONT_GM(font,original_index)->init = TRUE;
5385 if(format == GGO_METRICS)
5387 return 1; /* FIXME */
5390 if(ft_face->glyph->format != ft_glyph_format_outline &&
5391 (format == GGO_NATIVE || format == GGO_BEZIER))
5393 TRACE("loaded a bitmap\n");
5394 return GDI_ERROR;
5397 switch(format) {
5398 case GGO_BITMAP:
5399 width = lpgm->gmBlackBoxX;
5400 height = lpgm->gmBlackBoxY;
5401 pitch = ((width + 31) >> 5) << 2;
5402 needed = pitch * height;
5404 if(!buf || !buflen) break;
5406 switch(ft_face->glyph->format) {
5407 case ft_glyph_format_bitmap:
5409 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5410 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5411 INT h = ft_face->glyph->bitmap.rows;
5412 while(h--) {
5413 memcpy(dst, src, w);
5414 src += ft_face->glyph->bitmap.pitch;
5415 dst += pitch;
5417 break;
5420 case ft_glyph_format_outline:
5421 ft_bitmap.width = width;
5422 ft_bitmap.rows = height;
5423 ft_bitmap.pitch = pitch;
5424 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5425 ft_bitmap.buffer = buf;
5427 if(needsTransform)
5428 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5430 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5432 /* Note: FreeType will only set 'black' bits for us. */
5433 memset(buf, 0, needed);
5434 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5435 break;
5437 default:
5438 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5439 return GDI_ERROR;
5441 break;
5443 case GGO_GRAY2_BITMAP:
5444 case GGO_GRAY4_BITMAP:
5445 case GGO_GRAY8_BITMAP:
5446 case WINE_GGO_GRAY16_BITMAP:
5448 unsigned int max_level, row, col;
5449 BYTE *start, *ptr;
5451 width = lpgm->gmBlackBoxX;
5452 height = lpgm->gmBlackBoxY;
5453 pitch = (width + 3) / 4 * 4;
5454 needed = pitch * height;
5456 if(!buf || !buflen) break;
5458 max_level = get_max_level( format );
5460 switch(ft_face->glyph->format) {
5461 case ft_glyph_format_bitmap:
5463 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5464 INT h = ft_face->glyph->bitmap.rows;
5465 INT x;
5466 memset( buf, 0, needed );
5467 while(h--) {
5468 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5469 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5470 src += ft_face->glyph->bitmap.pitch;
5471 dst += pitch;
5473 return needed;
5475 case ft_glyph_format_outline:
5477 ft_bitmap.width = width;
5478 ft_bitmap.rows = height;
5479 ft_bitmap.pitch = pitch;
5480 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5481 ft_bitmap.buffer = buf;
5483 if(needsTransform)
5484 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5486 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5488 memset(ft_bitmap.buffer, 0, buflen);
5490 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5492 if (max_level != 255)
5494 for (row = 0, start = buf; row < height; row++)
5496 for (col = 0, ptr = start; col < width; col++, ptr++)
5497 *ptr = (((int)*ptr) * max_level + 128) / 256;
5498 start += pitch;
5501 return needed;
5504 default:
5505 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5506 return GDI_ERROR;
5508 break;
5511 case WINE_GGO_HRGB_BITMAP:
5512 case WINE_GGO_HBGR_BITMAP:
5513 case WINE_GGO_VRGB_BITMAP:
5514 case WINE_GGO_VBGR_BITMAP:
5515 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5517 switch (ft_face->glyph->format)
5519 case FT_GLYPH_FORMAT_BITMAP:
5521 BYTE *src, *dst;
5522 INT src_pitch, x;
5524 width = lpgm->gmBlackBoxX;
5525 height = lpgm->gmBlackBoxY;
5526 pitch = width * 4;
5527 needed = pitch * height;
5529 if (!buf || !buflen) break;
5531 memset(buf, 0, buflen);
5532 dst = buf;
5533 src = ft_face->glyph->bitmap.buffer;
5534 src_pitch = ft_face->glyph->bitmap.pitch;
5536 height = min( height, ft_face->glyph->bitmap.rows );
5537 while ( height-- )
5539 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5541 if ( src[x / 8] & masks[x % 8] )
5542 ((unsigned int *)dst)[x] = ~0u;
5544 src += src_pitch;
5545 dst += pitch;
5548 break;
5551 case FT_GLYPH_FORMAT_OUTLINE:
5553 unsigned int *dst;
5554 BYTE *src;
5555 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5556 INT x_shift, y_shift;
5557 BOOL rgb;
5558 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5559 FT_Render_Mode render_mode =
5560 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5561 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5563 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5565 if ( render_mode == FT_RENDER_MODE_LCD)
5567 lpgm->gmBlackBoxX += 2;
5568 lpgm->gmptGlyphOrigin.x -= 1;
5570 else
5572 lpgm->gmBlackBoxY += 2;
5573 lpgm->gmptGlyphOrigin.y += 1;
5577 width = lpgm->gmBlackBoxX;
5578 height = lpgm->gmBlackBoxY;
5579 pitch = width * 4;
5580 needed = pitch * height;
5582 if (!buf || !buflen) break;
5584 memset(buf, 0, buflen);
5585 dst = buf;
5586 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5588 if ( needsTransform )
5589 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5591 if ( pFT_Library_SetLcdFilter )
5592 pFT_Library_SetLcdFilter( library, lcdfilter );
5593 pFT_Render_Glyph (ft_face->glyph, render_mode);
5595 src = ft_face->glyph->bitmap.buffer;
5596 src_pitch = ft_face->glyph->bitmap.pitch;
5597 src_width = ft_face->glyph->bitmap.width;
5598 src_height = ft_face->glyph->bitmap.rows;
5600 if ( render_mode == FT_RENDER_MODE_LCD)
5602 rgb_interval = 1;
5603 hmul = 3;
5604 vmul = 1;
5606 else
5608 rgb_interval = src_pitch;
5609 hmul = 1;
5610 vmul = 3;
5613 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5614 if ( x_shift < 0 ) x_shift = 0;
5615 if ( x_shift + (src_width / hmul) > width )
5616 x_shift = width - (src_width / hmul);
5618 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5619 if ( y_shift < 0 ) y_shift = 0;
5620 if ( y_shift + (src_height / vmul) > height )
5621 y_shift = height - (src_height / vmul);
5623 dst += x_shift + y_shift * ( pitch / 4 );
5624 while ( src_height )
5626 for ( x = 0; x < src_width / hmul; x++ )
5628 if ( rgb )
5630 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5631 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5632 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5633 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5635 else
5637 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5638 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5639 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5640 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5643 src += src_pitch * vmul;
5644 dst += pitch / 4;
5645 src_height -= vmul;
5648 break;
5651 default:
5652 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5653 return GDI_ERROR;
5656 break;
5658 #else
5659 return GDI_ERROR;
5660 #endif
5662 case GGO_NATIVE:
5664 int contour, point = 0, first_pt;
5665 FT_Outline *outline = &ft_face->glyph->outline;
5666 TTPOLYGONHEADER *pph;
5667 TTPOLYCURVE *ppc;
5668 DWORD pph_start, cpfx, type;
5670 if(buflen == 0) buf = NULL;
5672 if (needsTransform && buf) {
5673 pFT_Outline_Transform(outline, &transMat);
5676 for(contour = 0; contour < outline->n_contours; contour++) {
5677 pph_start = needed;
5678 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5679 first_pt = point;
5680 if(buf) {
5681 pph->dwType = TT_POLYGON_TYPE;
5682 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5684 needed += sizeof(*pph);
5685 point++;
5686 while(point <= outline->contours[contour]) {
5687 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5688 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5689 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5690 cpfx = 0;
5691 do {
5692 if(buf)
5693 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5694 cpfx++;
5695 point++;
5696 } while(point <= outline->contours[contour] &&
5697 (outline->tags[point] & FT_Curve_Tag_On) ==
5698 (outline->tags[point-1] & FT_Curve_Tag_On));
5699 /* At the end of a contour Windows adds the start point, but
5700 only for Beziers */
5701 if(point > outline->contours[contour] &&
5702 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5703 if(buf)
5704 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5705 cpfx++;
5706 } else if(point <= outline->contours[contour] &&
5707 outline->tags[point] & FT_Curve_Tag_On) {
5708 /* add closing pt for bezier */
5709 if(buf)
5710 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5711 cpfx++;
5712 point++;
5714 if(buf) {
5715 ppc->wType = type;
5716 ppc->cpfx = cpfx;
5718 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5720 if(buf)
5721 pph->cb = needed - pph_start;
5723 break;
5725 case GGO_BEZIER:
5727 /* Convert the quadratic Beziers to cubic Beziers.
5728 The parametric eqn for a cubic Bezier is, from PLRM:
5729 r(t) = at^3 + bt^2 + ct + r0
5730 with the control points:
5731 r1 = r0 + c/3
5732 r2 = r1 + (c + b)/3
5733 r3 = r0 + c + b + a
5735 A quadratic Bezier has the form:
5736 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5738 So equating powers of t leads to:
5739 r1 = 2/3 p1 + 1/3 p0
5740 r2 = 2/3 p1 + 1/3 p2
5741 and of course r0 = p0, r3 = p2
5744 int contour, point = 0, first_pt;
5745 FT_Outline *outline = &ft_face->glyph->outline;
5746 TTPOLYGONHEADER *pph;
5747 TTPOLYCURVE *ppc;
5748 DWORD pph_start, cpfx, type;
5749 FT_Vector cubic_control[4];
5750 if(buflen == 0) buf = NULL;
5752 if (needsTransform && buf) {
5753 pFT_Outline_Transform(outline, &transMat);
5756 for(contour = 0; contour < outline->n_contours; contour++) {
5757 pph_start = needed;
5758 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5759 first_pt = point;
5760 if(buf) {
5761 pph->dwType = TT_POLYGON_TYPE;
5762 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5764 needed += sizeof(*pph);
5765 point++;
5766 while(point <= outline->contours[contour]) {
5767 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5768 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5769 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5770 cpfx = 0;
5771 do {
5772 if(type == TT_PRIM_LINE) {
5773 if(buf)
5774 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5775 cpfx++;
5776 point++;
5777 } else {
5778 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5779 so cpfx = 3n */
5781 /* FIXME: Possible optimization in endpoint calculation
5782 if there are two consecutive curves */
5783 cubic_control[0] = outline->points[point-1];
5784 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5785 cubic_control[0].x += outline->points[point].x + 1;
5786 cubic_control[0].y += outline->points[point].y + 1;
5787 cubic_control[0].x >>= 1;
5788 cubic_control[0].y >>= 1;
5790 if(point+1 > outline->contours[contour])
5791 cubic_control[3] = outline->points[first_pt];
5792 else {
5793 cubic_control[3] = outline->points[point+1];
5794 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5795 cubic_control[3].x += outline->points[point].x + 1;
5796 cubic_control[3].y += outline->points[point].y + 1;
5797 cubic_control[3].x >>= 1;
5798 cubic_control[3].y >>= 1;
5801 /* r1 = 1/3 p0 + 2/3 p1
5802 r2 = 1/3 p2 + 2/3 p1 */
5803 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5804 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5805 cubic_control[2] = cubic_control[1];
5806 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5807 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5808 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5809 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5810 if(buf) {
5811 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5812 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5813 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5815 cpfx += 3;
5816 point++;
5818 } while(point <= outline->contours[contour] &&
5819 (outline->tags[point] & FT_Curve_Tag_On) ==
5820 (outline->tags[point-1] & FT_Curve_Tag_On));
5821 /* At the end of a contour Windows adds the start point,
5822 but only for Beziers and we've already done that.
5824 if(point <= outline->contours[contour] &&
5825 outline->tags[point] & FT_Curve_Tag_On) {
5826 /* This is the closing pt of a bezier, but we've already
5827 added it, so just inc point and carry on */
5828 point++;
5830 if(buf) {
5831 ppc->wType = type;
5832 ppc->cpfx = cpfx;
5834 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5836 if(buf)
5837 pph->cb = needed - pph_start;
5839 break;
5842 default:
5843 FIXME("Unsupported format %d\n", format);
5844 return GDI_ERROR;
5846 return needed;
5849 static BOOL get_bitmap_text_metrics(GdiFont *font)
5851 FT_Face ft_face = font->ft_face;
5852 FT_WinFNT_HeaderRec winfnt_header;
5853 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5854 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5855 font->potm->otmSize = size;
5857 #define TM font->potm->otmTextMetrics
5858 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5860 TM.tmHeight = winfnt_header.pixel_height;
5861 TM.tmAscent = winfnt_header.ascent;
5862 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5863 TM.tmInternalLeading = winfnt_header.internal_leading;
5864 TM.tmExternalLeading = winfnt_header.external_leading;
5865 TM.tmAveCharWidth = winfnt_header.avg_width;
5866 TM.tmMaxCharWidth = winfnt_header.max_width;
5867 TM.tmWeight = winfnt_header.weight;
5868 TM.tmOverhang = 0;
5869 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5870 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5871 TM.tmFirstChar = winfnt_header.first_char;
5872 TM.tmLastChar = winfnt_header.last_char;
5873 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5874 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5875 TM.tmItalic = winfnt_header.italic;
5876 TM.tmUnderlined = font->underline;
5877 TM.tmStruckOut = font->strikeout;
5878 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5879 TM.tmCharSet = winfnt_header.charset;
5881 else
5883 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5884 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5885 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5886 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5887 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5888 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5889 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5890 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5891 TM.tmOverhang = 0;
5892 TM.tmDigitizedAspectX = 96; /* FIXME */
5893 TM.tmDigitizedAspectY = 96; /* FIXME */
5894 TM.tmFirstChar = 1;
5895 TM.tmLastChar = 255;
5896 TM.tmDefaultChar = 32;
5897 TM.tmBreakChar = 32;
5898 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5899 TM.tmUnderlined = font->underline;
5900 TM.tmStruckOut = font->strikeout;
5901 /* NB inverted meaning of TMPF_FIXED_PITCH */
5902 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5903 TM.tmCharSet = font->charset;
5905 #undef TM
5907 return TRUE;
5911 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5913 double scale_x, scale_y;
5915 if (font->aveWidth)
5917 scale_x = (double)font->aveWidth;
5918 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5920 else
5921 scale_x = font->scale_y;
5923 scale_x *= fabs(font->font_desc.matrix.eM11);
5924 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5926 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5927 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5929 SCALE_Y(ptm->tmHeight);
5930 SCALE_Y(ptm->tmAscent);
5931 SCALE_Y(ptm->tmDescent);
5932 SCALE_Y(ptm->tmInternalLeading);
5933 SCALE_Y(ptm->tmExternalLeading);
5934 SCALE_Y(ptm->tmOverhang);
5936 SCALE_X(ptm->tmAveCharWidth);
5937 SCALE_X(ptm->tmMaxCharWidth);
5939 #undef SCALE_X
5940 #undef SCALE_Y
5943 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5945 double scale_x, scale_y;
5947 if (font->aveWidth)
5949 scale_x = (double)font->aveWidth;
5950 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5952 else
5953 scale_x = font->scale_y;
5955 scale_x *= fabs(font->font_desc.matrix.eM11);
5956 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5958 scale_font_metrics(font, &potm->otmTextMetrics);
5960 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5961 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5963 SCALE_Y(potm->otmAscent);
5964 SCALE_Y(potm->otmDescent);
5965 SCALE_Y(potm->otmLineGap);
5966 SCALE_Y(potm->otmsCapEmHeight);
5967 SCALE_Y(potm->otmsXHeight);
5968 SCALE_Y(potm->otmrcFontBox.top);
5969 SCALE_Y(potm->otmrcFontBox.bottom);
5970 SCALE_X(potm->otmrcFontBox.left);
5971 SCALE_X(potm->otmrcFontBox.right);
5972 SCALE_Y(potm->otmMacAscent);
5973 SCALE_Y(potm->otmMacDescent);
5974 SCALE_Y(potm->otmMacLineGap);
5975 SCALE_X(potm->otmptSubscriptSize.x);
5976 SCALE_Y(potm->otmptSubscriptSize.y);
5977 SCALE_X(potm->otmptSubscriptOffset.x);
5978 SCALE_Y(potm->otmptSubscriptOffset.y);
5979 SCALE_X(potm->otmptSuperscriptSize.x);
5980 SCALE_Y(potm->otmptSuperscriptSize.y);
5981 SCALE_X(potm->otmptSuperscriptOffset.x);
5982 SCALE_Y(potm->otmptSuperscriptOffset.y);
5983 SCALE_Y(potm->otmsStrikeoutSize);
5984 SCALE_Y(potm->otmsStrikeoutPosition);
5985 SCALE_Y(potm->otmsUnderscoreSize);
5986 SCALE_Y(potm->otmsUnderscorePosition);
5988 #undef SCALE_X
5989 #undef SCALE_Y
5992 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5994 if(!font->potm)
5996 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
5998 /* Make sure that the font has sane width/height ratio */
5999 if (font->aveWidth)
6001 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6003 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6004 font->aveWidth = 0;
6008 *ptm = font->potm->otmTextMetrics;
6009 scale_font_metrics(font, ptm);
6010 return TRUE;
6013 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6015 int i;
6017 for(i = 0; i < ft_face->num_charmaps; i++)
6019 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6020 return TRUE;
6022 return FALSE;
6025 static BOOL get_outline_text_metrics(GdiFont *font)
6027 BOOL ret = FALSE;
6028 FT_Face ft_face = font->ft_face;
6029 UINT needed, lenfam, lensty;
6030 TT_OS2 *pOS2;
6031 TT_HoriHeader *pHori;
6032 TT_Postscript *pPost;
6033 FT_Fixed x_scale, y_scale;
6034 WCHAR *family_nameW, *style_nameW;
6035 static const WCHAR spaceW[] = {' ', '\0'};
6036 char *cp;
6037 INT ascent, descent;
6039 TRACE("font=%p\n", font);
6041 if(!FT_IS_SCALABLE(ft_face))
6042 return FALSE;
6044 needed = sizeof(*font->potm);
6046 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6047 family_nameW = strdupW(font->name);
6049 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6050 * sizeof(WCHAR);
6051 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6052 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6053 style_nameW, lensty/sizeof(WCHAR));
6055 /* These names should be read from the TT name table */
6057 /* length of otmpFamilyName */
6058 needed += lenfam;
6060 /* length of otmpFaceName */
6061 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6062 needed += lenfam; /* just the family name */
6063 } else {
6064 needed += lenfam + lensty; /* family + " " + style */
6067 /* length of otmpStyleName */
6068 needed += lensty;
6070 /* length of otmpFullName */
6071 needed += lenfam + lensty;
6074 x_scale = ft_face->size->metrics.x_scale;
6075 y_scale = ft_face->size->metrics.y_scale;
6077 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6078 if(!pOS2) {
6079 FIXME("Can't find OS/2 table - not TT font?\n");
6080 goto end;
6083 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6084 if(!pHori) {
6085 FIXME("Can't find HHEA table - not TT font?\n");
6086 goto end;
6089 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6091 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",
6092 pOS2->usWinAscent, pOS2->usWinDescent,
6093 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6094 ft_face->ascender, ft_face->descender, ft_face->height,
6095 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6096 ft_face->bbox.yMax, ft_face->bbox.yMin);
6098 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6099 font->potm->otmSize = needed;
6101 #define TM font->potm->otmTextMetrics
6103 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6104 ascent = pHori->Ascender;
6105 descent = -pHori->Descender;
6106 } else {
6107 ascent = pOS2->usWinAscent;
6108 descent = pOS2->usWinDescent;
6111 if(font->yMax) {
6112 TM.tmAscent = font->yMax;
6113 TM.tmDescent = -font->yMin;
6114 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6115 } else {
6116 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6117 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6118 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6119 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6122 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6124 /* MSDN says:
6125 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6127 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6128 ((ascent + descent) -
6129 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6131 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6132 if (TM.tmAveCharWidth == 0) {
6133 TM.tmAveCharWidth = 1;
6135 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6136 TM.tmWeight = FW_REGULAR;
6137 if (font->fake_bold)
6138 TM.tmWeight = FW_BOLD;
6139 else
6141 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6143 if (pOS2->usWeightClass > FW_MEDIUM)
6144 TM.tmWeight = pOS2->usWeightClass;
6146 else if (pOS2->usWeightClass <= FW_MEDIUM)
6147 TM.tmWeight = pOS2->usWeightClass;
6149 TM.tmOverhang = 0;
6150 TM.tmDigitizedAspectX = 300;
6151 TM.tmDigitizedAspectY = 300;
6152 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6153 * symbol range to 0 - f0ff
6156 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6158 TM.tmFirstChar = 0;
6159 switch(GetACP())
6161 case 1257: /* Baltic */
6162 TM.tmLastChar = 0xf8fd;
6163 break;
6164 default:
6165 TM.tmLastChar = 0xf0ff;
6167 TM.tmBreakChar = 0x20;
6168 TM.tmDefaultChar = 0x1f;
6170 else
6172 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6173 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6175 if(pOS2->usFirstCharIndex <= 1)
6176 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6177 else if (pOS2->usFirstCharIndex > 0xff)
6178 TM.tmBreakChar = 0x20;
6179 else
6180 TM.tmBreakChar = pOS2->usFirstCharIndex;
6181 TM.tmDefaultChar = TM.tmBreakChar - 1;
6183 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6184 TM.tmUnderlined = font->underline;
6185 TM.tmStruckOut = font->strikeout;
6187 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6188 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6189 (pOS2->version == 0xFFFFU ||
6190 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6191 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6192 else
6193 TM.tmPitchAndFamily = 0;
6195 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6197 case PAN_FAMILY_SCRIPT:
6198 TM.tmPitchAndFamily |= FF_SCRIPT;
6199 break;
6201 case PAN_FAMILY_DECORATIVE:
6202 TM.tmPitchAndFamily |= FF_DECORATIVE;
6203 break;
6205 case PAN_ANY:
6206 case PAN_NO_FIT:
6207 case PAN_FAMILY_TEXT_DISPLAY:
6208 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6209 /* which is clearly not what the panose spec says. */
6210 default:
6211 if(TM.tmPitchAndFamily == 0 || /* fixed */
6212 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6213 TM.tmPitchAndFamily = FF_MODERN;
6214 else
6216 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6218 case PAN_ANY:
6219 case PAN_NO_FIT:
6220 default:
6221 TM.tmPitchAndFamily |= FF_DONTCARE;
6222 break;
6224 case PAN_SERIF_COVE:
6225 case PAN_SERIF_OBTUSE_COVE:
6226 case PAN_SERIF_SQUARE_COVE:
6227 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6228 case PAN_SERIF_SQUARE:
6229 case PAN_SERIF_THIN:
6230 case PAN_SERIF_BONE:
6231 case PAN_SERIF_EXAGGERATED:
6232 case PAN_SERIF_TRIANGLE:
6233 TM.tmPitchAndFamily |= FF_ROMAN;
6234 break;
6236 case PAN_SERIF_NORMAL_SANS:
6237 case PAN_SERIF_OBTUSE_SANS:
6238 case PAN_SERIF_PERP_SANS:
6239 case PAN_SERIF_FLARED:
6240 case PAN_SERIF_ROUNDED:
6241 TM.tmPitchAndFamily |= FF_SWISS;
6242 break;
6245 break;
6248 if(FT_IS_SCALABLE(ft_face))
6249 TM.tmPitchAndFamily |= TMPF_VECTOR;
6251 if(FT_IS_SFNT(ft_face))
6253 if (font->ntmFlags & NTM_PS_OPENTYPE)
6254 TM.tmPitchAndFamily |= TMPF_DEVICE;
6255 else
6256 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6259 TM.tmCharSet = font->charset;
6261 font->potm->otmFiller = 0;
6262 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6263 font->potm->otmfsSelection = pOS2->fsSelection;
6264 font->potm->otmfsType = pOS2->fsType;
6265 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6266 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6267 font->potm->otmItalicAngle = 0; /* POST table */
6268 font->potm->otmEMSquare = ft_face->units_per_EM;
6269 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6270 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6271 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6272 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6273 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6274 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6275 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6276 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6277 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6278 font->potm->otmMacAscent = TM.tmAscent;
6279 font->potm->otmMacDescent = -TM.tmDescent;
6280 font->potm->otmMacLineGap = font->potm->otmLineGap;
6281 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6282 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6283 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6284 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6285 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6286 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6287 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6288 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6289 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6290 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6291 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6292 if(!pPost) {
6293 font->potm->otmsUnderscoreSize = 0;
6294 font->potm->otmsUnderscorePosition = 0;
6295 } else {
6296 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6297 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6299 #undef TM
6301 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6302 cp = (char*)font->potm + sizeof(*font->potm);
6303 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6304 strcpyW((WCHAR*)cp, family_nameW);
6305 cp += lenfam;
6306 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6307 strcpyW((WCHAR*)cp, style_nameW);
6308 cp += lensty;
6309 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6310 strcpyW((WCHAR*)cp, family_nameW);
6311 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6312 strcatW((WCHAR*)cp, spaceW);
6313 strcatW((WCHAR*)cp, style_nameW);
6314 cp += lenfam + lensty;
6315 } else
6316 cp += lenfam;
6317 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6318 strcpyW((WCHAR*)cp, family_nameW);
6319 strcatW((WCHAR*)cp, spaceW);
6320 strcatW((WCHAR*)cp, style_nameW);
6321 ret = TRUE;
6323 end:
6324 HeapFree(GetProcessHeap(), 0, style_nameW);
6325 HeapFree(GetProcessHeap(), 0, family_nameW);
6326 return ret;
6329 /*************************************************************
6330 * freetype_GetGlyphOutline
6332 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6333 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6335 struct freetype_physdev *physdev = get_freetype_dev( dev );
6336 DWORD ret;
6338 if (!physdev->font)
6340 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6341 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6344 GDI_CheckNotLock();
6345 EnterCriticalSection( &freetype_cs );
6346 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6347 LeaveCriticalSection( &freetype_cs );
6348 return ret;
6351 /*************************************************************
6352 * freetype_GetTextMetrics
6354 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6356 struct freetype_physdev *physdev = get_freetype_dev( dev );
6357 BOOL ret;
6359 if (!physdev->font)
6361 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6362 return dev->funcs->pGetTextMetrics( dev, metrics );
6365 GDI_CheckNotLock();
6366 EnterCriticalSection( &freetype_cs );
6367 ret = get_text_metrics( physdev->font, metrics );
6368 LeaveCriticalSection( &freetype_cs );
6369 return ret;
6372 /*************************************************************
6373 * freetype_GetOutlineTextMetrics
6375 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6377 struct freetype_physdev *physdev = get_freetype_dev( dev );
6378 UINT ret = 0;
6380 if (!physdev->font)
6382 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6383 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6386 TRACE("font=%p\n", physdev->font);
6388 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6390 GDI_CheckNotLock();
6391 EnterCriticalSection( &freetype_cs );
6393 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6395 if(cbSize >= physdev->font->potm->otmSize)
6397 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6398 scale_outline_font_metrics(physdev->font, potm);
6400 ret = physdev->font->potm->otmSize;
6402 LeaveCriticalSection( &freetype_cs );
6403 return ret;
6406 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6408 HFONTLIST *hfontlist;
6409 child->font = alloc_font();
6410 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6411 if(!child->font->ft_face)
6413 free_font(child->font);
6414 child->font = NULL;
6415 return FALSE;
6418 child->font->font_desc = font->font_desc;
6419 child->font->ntmFlags = child->face->ntmFlags;
6420 child->font->orientation = font->orientation;
6421 child->font->scale_y = font->scale_y;
6422 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6423 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6424 child->font->name = strdupW(child->face->family->FamilyName);
6425 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6426 child->font->base_font = font;
6427 list_add_head(&child_font_list, &child->font->entry);
6428 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6429 return TRUE;
6432 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6434 FT_UInt g;
6435 CHILD_FONT *child_font;
6437 if(font->base_font)
6438 font = font->base_font;
6440 *linked_font = font;
6442 if((*glyph = get_glyph_index(font, c)))
6444 *glyph = get_GSUB_vert_glyph(font, *glyph);
6445 return TRUE;
6448 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6450 if(!child_font->font)
6451 if(!load_child_font(font, child_font))
6452 continue;
6454 if(!child_font->font->ft_face)
6455 continue;
6456 g = get_glyph_index(child_font->font, c);
6457 g = get_GSUB_vert_glyph(child_font->font, g);
6458 if(g)
6460 *glyph = g;
6461 *linked_font = child_font->font;
6462 return TRUE;
6465 return FALSE;
6468 /*************************************************************
6469 * freetype_GetCharWidth
6471 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6473 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6474 UINT c;
6475 GLYPHMETRICS gm;
6476 FT_UInt glyph_index;
6477 GdiFont *linked_font;
6478 struct freetype_physdev *physdev = get_freetype_dev( dev );
6480 if (!physdev->font)
6482 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6483 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6486 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6488 GDI_CheckNotLock();
6489 EnterCriticalSection( &freetype_cs );
6490 for(c = firstChar; c <= lastChar; c++) {
6491 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6492 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6493 &gm, 0, NULL, &identity);
6494 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6496 LeaveCriticalSection( &freetype_cs );
6497 return TRUE;
6500 /*************************************************************
6501 * freetype_GetCharABCWidths
6503 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6505 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6506 UINT c;
6507 GLYPHMETRICS gm;
6508 FT_UInt glyph_index;
6509 GdiFont *linked_font;
6510 struct freetype_physdev *physdev = get_freetype_dev( dev );
6512 if (!physdev->font)
6514 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6515 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6518 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6520 GDI_CheckNotLock();
6521 EnterCriticalSection( &freetype_cs );
6523 for(c = firstChar; c <= lastChar; c++) {
6524 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6525 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6526 &gm, 0, NULL, &identity);
6527 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6528 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6529 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6530 FONT_GM(linked_font,glyph_index)->bbx;
6532 LeaveCriticalSection( &freetype_cs );
6533 return TRUE;
6536 /*************************************************************
6537 * freetype_GetCharABCWidthsI
6539 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6541 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6542 UINT c;
6543 GLYPHMETRICS gm;
6544 FT_UInt glyph_index;
6545 GdiFont *linked_font;
6546 struct freetype_physdev *physdev = get_freetype_dev( dev );
6548 if (!physdev->font)
6550 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6551 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6554 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6555 return FALSE;
6557 GDI_CheckNotLock();
6558 EnterCriticalSection( &freetype_cs );
6560 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6561 if (!pgi)
6562 for(c = firstChar; c < firstChar+count; c++) {
6563 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6564 &gm, 0, NULL, &identity);
6565 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6566 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6567 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6568 - FONT_GM(linked_font,c)->bbx;
6570 else
6571 for(c = 0; c < count; c++) {
6572 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6573 &gm, 0, NULL, &identity);
6574 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6575 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6576 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6577 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6580 LeaveCriticalSection( &freetype_cs );
6581 return TRUE;
6584 /*************************************************************
6585 * freetype_GetTextExtentExPoint
6587 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6588 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6590 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6591 INT idx;
6592 INT nfit = 0, ext;
6593 GLYPHMETRICS gm;
6594 TEXTMETRICW tm;
6595 FT_UInt glyph_index;
6596 GdiFont *linked_font;
6597 struct freetype_physdev *physdev = get_freetype_dev( dev );
6599 if (!physdev->font)
6601 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6602 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6605 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6607 GDI_CheckNotLock();
6608 EnterCriticalSection( &freetype_cs );
6610 size->cx = 0;
6611 get_text_metrics( physdev->font, &tm );
6612 size->cy = tm.tmHeight;
6614 for(idx = 0; idx < count; idx++) {
6615 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6616 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6617 &gm, 0, NULL, &identity);
6618 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6619 ext = size->cx;
6620 if (! pnfit || ext <= max_ext) {
6621 ++nfit;
6622 if (dxs)
6623 dxs[idx] = ext;
6627 if (pnfit)
6628 *pnfit = nfit;
6630 LeaveCriticalSection( &freetype_cs );
6631 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6632 return TRUE;
6635 /*************************************************************
6636 * freetype_GetTextExtentExPointI
6638 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6639 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6641 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6642 INT idx;
6643 INT nfit = 0, ext;
6644 GLYPHMETRICS gm;
6645 TEXTMETRICW tm;
6646 struct freetype_physdev *physdev = get_freetype_dev( dev );
6648 if (!physdev->font)
6650 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6651 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6654 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6656 GDI_CheckNotLock();
6657 EnterCriticalSection( &freetype_cs );
6659 size->cx = 0;
6660 get_text_metrics(physdev->font, &tm);
6661 size->cy = tm.tmHeight;
6663 for(idx = 0; idx < count; idx++) {
6664 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6665 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6666 ext = size->cx;
6667 if (! pnfit || ext <= max_ext) {
6668 ++nfit;
6669 if (dxs)
6670 dxs[idx] = ext;
6674 if (pnfit)
6675 *pnfit = nfit;
6677 LeaveCriticalSection( &freetype_cs );
6678 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6679 return TRUE;
6682 /*************************************************************
6683 * freetype_GetFontData
6685 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6687 struct freetype_physdev *physdev = get_freetype_dev( dev );
6689 if (!physdev->font)
6691 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6692 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6695 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6696 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6697 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6699 return get_font_data( physdev->font, table, offset, buf, cbData );
6702 /*************************************************************
6703 * freetype_GetTextFace
6705 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6707 INT n;
6708 struct freetype_physdev *physdev = get_freetype_dev( dev );
6710 if (!physdev->font)
6712 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6713 return dev->funcs->pGetTextFace( dev, count, str );
6716 n = strlenW(physdev->font->name) + 1;
6717 if (str)
6719 lstrcpynW(str, physdev->font->name, count);
6720 n = min(count, n);
6722 return n;
6725 /*************************************************************
6726 * freetype_GetTextCharsetInfo
6728 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6730 struct freetype_physdev *physdev = get_freetype_dev( dev );
6732 if (!physdev->font)
6734 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6735 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6737 if (fs) *fs = physdev->font->fs;
6738 return physdev->font->charset;
6741 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6743 GdiFont *font = dc->gdiFont, *linked_font;
6744 struct list *first_hfont;
6745 BOOL ret;
6747 GDI_CheckNotLock();
6748 EnterCriticalSection( &freetype_cs );
6749 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6750 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6751 if(font == linked_font)
6752 *new_hfont = dc->hFont;
6753 else
6755 first_hfont = list_head(&linked_font->hfontlist);
6756 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6758 LeaveCriticalSection( &freetype_cs );
6759 return ret;
6762 /* Retrieve a list of supported Unicode ranges for a given font.
6763 * Can be called with NULL gs to calculate the buffer size. Returns
6764 * the number of ranges found.
6766 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6768 DWORD num_ranges = 0;
6770 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6772 FT_UInt glyph_code;
6773 FT_ULong char_code, char_code_prev;
6775 glyph_code = 0;
6776 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6778 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6779 face->num_glyphs, glyph_code, char_code);
6781 if (!glyph_code) return 0;
6783 if (gs)
6785 gs->ranges[0].wcLow = (USHORT)char_code;
6786 gs->ranges[0].cGlyphs = 0;
6787 gs->cGlyphsSupported = 0;
6790 num_ranges = 1;
6791 while (glyph_code)
6793 if (char_code < char_code_prev)
6795 ERR("expected increasing char code from FT_Get_Next_Char\n");
6796 return 0;
6798 if (char_code - char_code_prev > 1)
6800 num_ranges++;
6801 if (gs)
6803 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6804 gs->ranges[num_ranges - 1].cGlyphs = 1;
6805 gs->cGlyphsSupported++;
6808 else if (gs)
6810 gs->ranges[num_ranges - 1].cGlyphs++;
6811 gs->cGlyphsSupported++;
6813 char_code_prev = char_code;
6814 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6817 else
6818 FIXME("encoding %u not supported\n", face->charmap->encoding);
6820 return num_ranges;
6823 /*************************************************************
6824 * freetype_GetFontUnicodeRanges
6826 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6828 struct freetype_physdev *physdev = get_freetype_dev( dev );
6829 DWORD size, num_ranges;
6831 if (!physdev->font)
6833 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6834 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6837 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6838 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6839 if (glyphset)
6841 glyphset->cbThis = size;
6842 glyphset->cRanges = num_ranges;
6843 glyphset->flAccel = 0;
6845 return size;
6848 /*************************************************************
6849 * freetype_FontIsLinked
6851 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6853 struct freetype_physdev *physdev = get_freetype_dev( dev );
6854 BOOL ret;
6856 if (!physdev->font)
6858 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6859 return dev->funcs->pFontIsLinked( dev );
6862 GDI_CheckNotLock();
6863 EnterCriticalSection( &freetype_cs );
6864 ret = !list_empty(&physdev->font->child_fonts);
6865 LeaveCriticalSection( &freetype_cs );
6866 return ret;
6869 static BOOL is_hinting_enabled(void)
6871 /* Use the >= 2.2.0 function if available */
6872 if(pFT_Get_TrueType_Engine_Type)
6874 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6875 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6877 #ifdef FT_DRIVER_HAS_HINTER
6878 else
6880 FT_Module mod;
6882 /* otherwise if we've been compiled with < 2.2.0 headers
6883 use the internal macro */
6884 mod = pFT_Get_Module(library, "truetype");
6885 if(mod && FT_DRIVER_HAS_HINTER(mod))
6886 return TRUE;
6888 #endif
6890 return FALSE;
6893 static BOOL is_subpixel_rendering_enabled( void )
6895 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6896 return pFT_Library_SetLcdFilter &&
6897 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6898 #else
6899 return FALSE;
6900 #endif
6903 /*************************************************************************
6904 * GetRasterizerCaps (GDI32.@)
6906 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6908 static int hinting = -1;
6909 static int subpixel = -1;
6911 if(hinting == -1)
6913 hinting = is_hinting_enabled();
6914 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6917 if ( subpixel == -1 )
6919 subpixel = is_subpixel_rendering_enabled();
6920 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6923 lprs->nSize = sizeof(RASTERIZER_STATUS);
6924 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6925 if ( subpixel )
6926 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6927 lprs->nLanguageID = 0;
6928 return TRUE;
6931 /*************************************************************
6932 * freetype_GdiRealizationInfo
6934 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6936 struct freetype_physdev *physdev = get_freetype_dev( dev );
6937 realization_info_t *info = ptr;
6939 if (!physdev->font)
6941 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6942 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6945 FIXME("(%p, %p): stub!\n", physdev->font, info);
6947 info->flags = 1;
6948 if(FT_IS_SCALABLE(physdev->font->ft_face))
6949 info->flags |= 2;
6951 info->cache_num = physdev->font->cache_num;
6952 info->unknown2 = -1;
6953 return TRUE;
6956 /*************************************************************************
6957 * Kerning support for TrueType fonts
6959 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6961 struct TT_kern_table
6963 USHORT version;
6964 USHORT nTables;
6967 struct TT_kern_subtable
6969 USHORT version;
6970 USHORT length;
6971 union
6973 USHORT word;
6974 struct
6976 USHORT horizontal : 1;
6977 USHORT minimum : 1;
6978 USHORT cross_stream: 1;
6979 USHORT override : 1;
6980 USHORT reserved1 : 4;
6981 USHORT format : 8;
6982 } bits;
6983 } coverage;
6986 struct TT_format0_kern_subtable
6988 USHORT nPairs;
6989 USHORT searchRange;
6990 USHORT entrySelector;
6991 USHORT rangeShift;
6994 struct TT_kern_pair
6996 USHORT left;
6997 USHORT right;
6998 short value;
7001 static DWORD parse_format0_kern_subtable(GdiFont *font,
7002 const struct TT_format0_kern_subtable *tt_f0_ks,
7003 const USHORT *glyph_to_char,
7004 KERNINGPAIR *kern_pair, DWORD cPairs)
7006 USHORT i, nPairs;
7007 const struct TT_kern_pair *tt_kern_pair;
7009 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7011 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7013 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7014 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7015 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7017 if (!kern_pair || !cPairs)
7018 return nPairs;
7020 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7022 nPairs = min(nPairs, cPairs);
7024 for (i = 0; i < nPairs; i++)
7026 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7027 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7028 /* this algorithm appears to better match what Windows does */
7029 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7030 if (kern_pair->iKernAmount < 0)
7032 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7033 kern_pair->iKernAmount -= font->ppem;
7035 else if (kern_pair->iKernAmount > 0)
7037 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7038 kern_pair->iKernAmount += font->ppem;
7040 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7042 TRACE("left %u right %u value %d\n",
7043 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7045 kern_pair++;
7047 TRACE("copied %u entries\n", nPairs);
7048 return nPairs;
7051 /*************************************************************
7052 * freetype_GetKerningPairs
7054 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7056 DWORD length;
7057 void *buf;
7058 const struct TT_kern_table *tt_kern_table;
7059 const struct TT_kern_subtable *tt_kern_subtable;
7060 USHORT i, nTables;
7061 USHORT *glyph_to_char;
7062 GdiFont *font;
7063 struct freetype_physdev *physdev = get_freetype_dev( dev );
7065 if (!(font = physdev->font))
7067 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7068 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7071 GDI_CheckNotLock();
7072 EnterCriticalSection( &freetype_cs );
7073 if (font->total_kern_pairs != (DWORD)-1)
7075 if (cPairs && kern_pair)
7077 cPairs = min(cPairs, font->total_kern_pairs);
7078 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7080 else cPairs = font->total_kern_pairs;
7082 LeaveCriticalSection( &freetype_cs );
7083 return cPairs;
7086 font->total_kern_pairs = 0;
7088 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7090 if (length == GDI_ERROR)
7092 TRACE("no kerning data in the font\n");
7093 LeaveCriticalSection( &freetype_cs );
7094 return 0;
7097 buf = HeapAlloc(GetProcessHeap(), 0, length);
7098 if (!buf)
7100 WARN("Out of memory\n");
7101 LeaveCriticalSection( &freetype_cs );
7102 return 0;
7105 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7107 /* build a glyph index to char code map */
7108 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7109 if (!glyph_to_char)
7111 WARN("Out of memory allocating a glyph index to char code map\n");
7112 HeapFree(GetProcessHeap(), 0, buf);
7113 LeaveCriticalSection( &freetype_cs );
7114 return 0;
7117 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7119 FT_UInt glyph_code;
7120 FT_ULong char_code;
7122 glyph_code = 0;
7123 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7125 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7126 font->ft_face->num_glyphs, glyph_code, char_code);
7128 while (glyph_code)
7130 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7132 /* FIXME: This doesn't match what Windows does: it does some fancy
7133 * things with duplicate glyph index to char code mappings, while
7134 * we just avoid overriding existing entries.
7136 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7137 glyph_to_char[glyph_code] = (USHORT)char_code;
7139 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7142 else
7144 ULONG n;
7146 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7147 for (n = 0; n <= 65535; n++)
7148 glyph_to_char[n] = (USHORT)n;
7151 tt_kern_table = buf;
7152 nTables = GET_BE_WORD(tt_kern_table->nTables);
7153 TRACE("version %u, nTables %u\n",
7154 GET_BE_WORD(tt_kern_table->version), nTables);
7156 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7158 for (i = 0; i < nTables; i++)
7160 struct TT_kern_subtable tt_kern_subtable_copy;
7162 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7163 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7164 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7166 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7167 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7168 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7170 /* According to the TrueType specification this is the only format
7171 * that will be properly interpreted by Windows and OS/2
7173 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7175 DWORD new_chunk, old_total = font->total_kern_pairs;
7177 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7178 glyph_to_char, NULL, 0);
7179 font->total_kern_pairs += new_chunk;
7181 if (!font->kern_pairs)
7182 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7183 font->total_kern_pairs * sizeof(*font->kern_pairs));
7184 else
7185 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7186 font->total_kern_pairs * sizeof(*font->kern_pairs));
7188 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7189 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7191 else
7192 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7194 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7197 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7198 HeapFree(GetProcessHeap(), 0, buf);
7200 if (cPairs && kern_pair)
7202 cPairs = min(cPairs, font->total_kern_pairs);
7203 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7205 else cPairs = font->total_kern_pairs;
7207 LeaveCriticalSection( &freetype_cs );
7208 return cPairs;
7211 static const struct gdi_dc_funcs freetype_funcs =
7213 NULL, /* pAbortDoc */
7214 NULL, /* pAbortPath */
7215 NULL, /* pAlphaBlend */
7216 NULL, /* pAngleArc */
7217 NULL, /* pArc */
7218 NULL, /* pArcTo */
7219 NULL, /* pBeginPath */
7220 NULL, /* pBlendImage */
7221 NULL, /* pChoosePixelFormat */
7222 NULL, /* pChord */
7223 NULL, /* pCloseFigure */
7224 NULL, /* pCopyBitmap */
7225 NULL, /* pCreateBitmap */
7226 NULL, /* pCreateCompatibleDC */
7227 freetype_CreateDC, /* pCreateDC */
7228 NULL, /* pDeleteBitmap */
7229 freetype_DeleteDC, /* pDeleteDC */
7230 NULL, /* pDeleteObject */
7231 NULL, /* pDescribePixelFormat */
7232 NULL, /* pDeviceCapabilities */
7233 NULL, /* pEllipse */
7234 NULL, /* pEndDoc */
7235 NULL, /* pEndPage */
7236 NULL, /* pEndPath */
7237 freetype_EnumFonts, /* pEnumFonts */
7238 NULL, /* pEnumICMProfiles */
7239 NULL, /* pExcludeClipRect */
7240 NULL, /* pExtDeviceMode */
7241 NULL, /* pExtEscape */
7242 NULL, /* pExtFloodFill */
7243 NULL, /* pExtSelectClipRgn */
7244 NULL, /* pExtTextOut */
7245 NULL, /* pFillPath */
7246 NULL, /* pFillRgn */
7247 NULL, /* pFlattenPath */
7248 freetype_FontIsLinked, /* pFontIsLinked */
7249 NULL, /* pFrameRgn */
7250 NULL, /* pGdiComment */
7251 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7252 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7253 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7254 freetype_GetCharWidth, /* pGetCharWidth */
7255 NULL, /* pGetDeviceCaps */
7256 NULL, /* pGetDeviceGammaRamp */
7257 freetype_GetFontData, /* pGetFontData */
7258 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7259 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7260 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7261 NULL, /* pGetICMProfile */
7262 NULL, /* pGetImage */
7263 freetype_GetKerningPairs, /* pGetKerningPairs */
7264 NULL, /* pGetNearestColor */
7265 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7266 NULL, /* pGetPixel */
7267 NULL, /* pGetPixelFormat */
7268 NULL, /* pGetSystemPaletteEntries */
7269 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7270 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7271 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7272 freetype_GetTextFace, /* pGetTextFace */
7273 freetype_GetTextMetrics, /* pGetTextMetrics */
7274 NULL, /* pGradientFill */
7275 NULL, /* pIntersectClipRect */
7276 NULL, /* pInvertRgn */
7277 NULL, /* pLineTo */
7278 NULL, /* pModifyWorldTransform */
7279 NULL, /* pMoveTo */
7280 NULL, /* pOffsetClipRgn */
7281 NULL, /* pOffsetViewportOrg */
7282 NULL, /* pOffsetWindowOrg */
7283 NULL, /* pPaintRgn */
7284 NULL, /* pPatBlt */
7285 NULL, /* pPie */
7286 NULL, /* pPolyBezier */
7287 NULL, /* pPolyBezierTo */
7288 NULL, /* pPolyDraw */
7289 NULL, /* pPolyPolygon */
7290 NULL, /* pPolyPolyline */
7291 NULL, /* pPolygon */
7292 NULL, /* pPolyline */
7293 NULL, /* pPolylineTo */
7294 NULL, /* pPutImage */
7295 NULL, /* pRealizeDefaultPalette */
7296 NULL, /* pRealizePalette */
7297 NULL, /* pRectangle */
7298 NULL, /* pResetDC */
7299 NULL, /* pRestoreDC */
7300 NULL, /* pRoundRect */
7301 NULL, /* pSaveDC */
7302 NULL, /* pScaleViewportExt */
7303 NULL, /* pScaleWindowExt */
7304 NULL, /* pSelectBitmap */
7305 NULL, /* pSelectBrush */
7306 NULL, /* pSelectClipPath */
7307 freetype_SelectFont, /* pSelectFont */
7308 NULL, /* pSelectPalette */
7309 NULL, /* pSelectPen */
7310 NULL, /* pSetArcDirection */
7311 NULL, /* pSetBkColor */
7312 NULL, /* pSetBkMode */
7313 NULL, /* pSetDCBrushColor */
7314 NULL, /* pSetDCPenColor */
7315 NULL, /* pSetDIBColorTable */
7316 NULL, /* pSetDIBitsToDevice */
7317 NULL, /* pSetDeviceClipping */
7318 NULL, /* pSetDeviceGammaRamp */
7319 NULL, /* pSetLayout */
7320 NULL, /* pSetMapMode */
7321 NULL, /* pSetMapperFlags */
7322 NULL, /* pSetPixel */
7323 NULL, /* pSetPixelFormat */
7324 NULL, /* pSetPolyFillMode */
7325 NULL, /* pSetROP2 */
7326 NULL, /* pSetRelAbs */
7327 NULL, /* pSetStretchBltMode */
7328 NULL, /* pSetTextAlign */
7329 NULL, /* pSetTextCharacterExtra */
7330 NULL, /* pSetTextColor */
7331 NULL, /* pSetTextJustification */
7332 NULL, /* pSetViewportExt */
7333 NULL, /* pSetViewportOrg */
7334 NULL, /* pSetWindowExt */
7335 NULL, /* pSetWindowOrg */
7336 NULL, /* pSetWorldTransform */
7337 NULL, /* pStartDoc */
7338 NULL, /* pStartPage */
7339 NULL, /* pStretchBlt */
7340 NULL, /* pStretchDIBits */
7341 NULL, /* pStrokeAndFillPath */
7342 NULL, /* pStrokePath */
7343 NULL, /* pSwapBuffers */
7344 NULL, /* pUnrealizePalette */
7345 NULL, /* pWidenPath */
7346 /* OpenGL not supported */
7349 #else /* HAVE_FREETYPE */
7351 /*************************************************************************/
7353 BOOL WineEngInit(void)
7355 return FALSE;
7357 BOOL WineEngDestroyFontInstance(HFONT hfont)
7359 return FALSE;
7362 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7364 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7365 return 1;
7368 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7370 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7371 return TRUE;
7374 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7376 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7377 return NULL;
7380 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7382 return FALSE;
7385 /*************************************************************************
7386 * GetRasterizerCaps (GDI32.@)
7388 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7390 lprs->nSize = sizeof(RASTERIZER_STATUS);
7391 lprs->wFlags = 0;
7392 lprs->nLanguageID = 0;
7393 return TRUE;
7396 #endif /* HAVE_FREETYPE */