msxml3/tests: Tests for IMXAttributes::clear().
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob8a0c0961faf541eb14caa466c30c4659f80f4975
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #ifdef HAVE_DIRENT_H
37 # include <dirent.h>
38 #endif
39 #include <stdio.h>
40 #include <assert.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
60 #undef LoadResource
61 #undef CompareString
62 #undef GetCurrentThread
63 #undef _CDECL
64 #undef DPRINTF
65 #undef GetCurrentProcess
66 #undef AnimatePalette
67 #undef EqualRgn
68 #undef FillRgn
69 #undef FrameRgn
70 #undef GetPixel
71 #undef InvertRgn
72 #undef LineTo
73 #undef OffsetRgn
74 #undef PaintRgn
75 #undef Polygon
76 #undef ResizePalette
77 #undef SetRectRgn
78 #endif /* HAVE_CARBON_CARBON_H */
80 #include "windef.h"
81 #include "winbase.h"
82 #include "winternl.h"
83 #include "winerror.h"
84 #include "winreg.h"
85 #include "wingdi.h"
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
92 #include "resource.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
96 #ifdef HAVE_FREETYPE
98 #ifdef HAVE_FT2BUILD_H
99 #include <ft2build.h>
100 #endif
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
103 #endif
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
106 #endif
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
109 #endif
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
112 #endif
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
115 #endif
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
118 #endif
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
121 #endif
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
124 #endif
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
127 #endif
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
130 #endif
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
173 #else
174 MAKE_FUNCPTR(FT_MulFix);
175 #endif
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #endif
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetString);
205 #endif
207 #undef MAKE_FUNCPTR
209 #ifndef FT_MAKE_TAG
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
213 #endif
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
217 #endif
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
220 #endif
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
223 #endif
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
226 #endif
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
230 #else
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
232 #endif
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
235 typedef struct {
236 FT_Short height;
237 FT_Short width;
238 FT_Pos size;
239 FT_Pos x_ppem;
240 FT_Pos y_ppem;
241 FT_Short internal_leading;
242 } Bitmap_Size;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
247 typedef struct {
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
250 } My_FT_Bitmap_Size;
252 struct enum_data
254 ENUMLOGFONTEXW elf;
255 NEWTEXTMETRICEXW ntm;
256 DWORD type;
259 typedef struct tagFace {
260 struct list entry;
261 WCHAR *StyleName;
262 WCHAR *FullName;
263 char *file;
264 void *font_data_ptr;
265 DWORD font_data_size;
266 FT_Long face_index;
267 FONTSIGNATURE fs;
268 FONTSIGNATURE fs_links;
269 DWORD ntmFlags;
270 FT_Fixed font_version;
271 BOOL scalable;
272 BOOL vertical;
273 Bitmap_Size size; /* set if face is a bitmap */
274 BOOL external; /* TRUE if we should manually add this font to the registry */
275 struct tagFamily *family;
276 /* Cached data for Enum */
277 struct enum_data *cached_enum_data;
278 } Face;
280 typedef struct tagFamily {
281 struct list entry;
282 const WCHAR *FamilyName;
283 const WCHAR *EnglishName;
284 struct list faces;
285 } Family;
287 typedef struct {
288 GLYPHMETRICS gm;
289 INT adv; /* These three hold to widths of the unrotated chars */
290 INT lsb;
291 INT bbx;
292 BOOL init;
293 } GM;
295 typedef struct {
296 FLOAT eM11, eM12;
297 FLOAT eM21, eM22;
298 } FMAT2;
300 typedef struct {
301 DWORD hash;
302 LOGFONTW lf;
303 FMAT2 matrix;
304 BOOL can_use_bitmap;
305 } FONT_DESC;
307 typedef struct tagHFONTLIST {
308 struct list entry;
309 HFONT hfont;
310 } HFONTLIST;
312 typedef struct {
313 struct list entry;
314 Face *face;
315 GdiFont *font;
316 } CHILD_FONT;
318 struct tagGdiFont {
319 struct list entry;
320 GM **gm;
321 DWORD gmsize;
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
329 FT_Face ft_face;
330 struct font_mapping *mapping;
331 LPWSTR name;
332 int charset;
333 int codepage;
334 BOOL fake_italic;
335 BOOL fake_bold;
336 BYTE underline;
337 BYTE strikeout;
338 INT orientation;
339 FONT_DESC font_desc;
340 LONG aveWidth, ppem;
341 double scale_y;
342 SHORT yMax;
343 SHORT yMin;
344 DWORD ntmFlags;
345 FONTSIGNATURE fs;
346 GdiFont *base_font;
347 VOID *GSUB_Table;
348 DWORD cache_num;
351 typedef struct {
352 struct list entry;
353 const WCHAR *font_name;
354 struct list links;
355 } SYSTEM_LINKS;
357 struct enum_charset_element {
358 DWORD mask;
359 DWORD charset;
360 WCHAR name[LF_FACESIZE];
363 struct enum_charset_list {
364 DWORD total;
365 struct enum_charset_element element[32];
368 #define GM_BLOCK_SIZE 128
369 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
371 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
372 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
373 #define UNUSED_CACHE_SIZE 10
374 static struct list child_font_list = LIST_INIT(child_font_list);
375 static struct list system_links = LIST_INIT(system_links);
377 static struct list font_subst_list = LIST_INIT(font_subst_list);
379 static struct list font_list = LIST_INIT(font_list);
381 struct freetype_physdev
383 struct gdi_physdev dev;
384 GdiFont *font;
387 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
389 return (struct freetype_physdev *)dev;
392 static const struct gdi_dc_funcs freetype_funcs;
394 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
395 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
396 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
398 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
399 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
400 'W','i','n','d','o','w','s','\\',
401 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
402 'F','o','n','t','s','\0'};
404 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
405 'W','i','n','d','o','w','s',' ','N','T','\\',
406 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
407 'F','o','n','t','s','\0'};
409 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
410 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
411 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
412 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
414 static const WCHAR * const SystemFontValues[] = {
415 System_Value,
416 OEMFont_Value,
417 FixedSys_Value,
418 NULL
421 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
422 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
424 /* Interesting and well-known (frequently-assumed!) font names */
425 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
426 static const WCHAR Microsoft_Sans_Serif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
427 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
428 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
429 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
430 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
431 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
432 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
434 static const WCHAR arial[] = {'A','r','i','a','l',0};
435 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
436 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
437 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
438 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
439 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
440 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
441 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
442 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
443 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
445 static const WCHAR *default_serif_list[] =
447 times_new_roman,
448 liberation_serif,
449 bitstream_vera_serif,
450 NULL
453 static const WCHAR *default_fixed_list[] =
455 courier_new,
456 liberation_mono,
457 bitstream_vera_sans_mono,
458 NULL
461 static const WCHAR *default_sans_list[] =
463 arial,
464 liberation_sans,
465 bitstream_vera_sans,
466 NULL
469 typedef struct {
470 WCHAR *name;
471 INT charset;
472 } NameCs;
474 typedef struct tagFontSubst {
475 struct list entry;
476 NameCs from;
477 NameCs to;
478 } FontSubst;
480 /* Registry font cache key and value names */
481 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
482 'F','o','n','t','s',0};
483 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
484 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
485 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
486 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
487 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
488 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
489 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','a','l',0};
490 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
491 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
492 static const WCHAR face_size_value[] = {'S','i','z','e',0};
493 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
494 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
495 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
496 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
497 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
500 struct font_mapping
502 struct list entry;
503 int refcount;
504 dev_t dev;
505 ino_t ino;
506 void *data;
507 size_t size;
510 static struct list mappings_list = LIST_INIT( mappings_list );
512 static CRITICAL_SECTION freetype_cs;
513 static CRITICAL_SECTION_DEBUG critsect_debug =
515 0, 0, &freetype_cs,
516 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
517 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
519 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
521 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
523 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
524 static BOOL use_default_fallback = FALSE;
526 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
527 static BOOL get_outline_text_metrics(GdiFont *font);
528 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
530 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
531 'W','i','n','d','o','w','s',' ','N','T','\\',
532 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
533 'S','y','s','t','e','m','L','i','n','k',0};
535 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
536 'F','o','n','t','L','i','n','k','\\',
537 'S','y','s','t','e','m','L','i','n','k',0};
539 /****************************************
540 * Notes on .fon files
542 * The fonts System, FixedSys and Terminal are special. There are typically multiple
543 * versions installed for different resolutions and codepages. Windows stores which one to use
544 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
545 * Key Meaning
546 * FIXEDFON.FON FixedSys
547 * FONTS.FON System
548 * OEMFONT.FON Terminal
549 * LogPixels Current dpi set by the display control panel applet
550 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
551 * also has a LogPixels value that appears to mirror this)
553 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
554 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
555 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
556 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
557 * so that makes sense.
559 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
560 * to be mapped into the registry on Windows 2000 at least).
561 * I have
562 * woafont=app850.fon
563 * ega80woa.fon=ega80850.fon
564 * ega40woa.fon=ega40850.fon
565 * cga80woa.fon=cga80850.fon
566 * cga40woa.fon=cga40850.fon
569 /* These are all structures needed for the GSUB table */
571 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
572 #define TATEGAKI_LOWER_BOUND 0x02F1
574 typedef struct {
575 DWORD version;
576 WORD ScriptList;
577 WORD FeatureList;
578 WORD LookupList;
579 } GSUB_Header;
581 typedef struct {
582 CHAR ScriptTag[4];
583 WORD Script;
584 } GSUB_ScriptRecord;
586 typedef struct {
587 WORD ScriptCount;
588 GSUB_ScriptRecord ScriptRecord[1];
589 } GSUB_ScriptList;
591 typedef struct {
592 CHAR LangSysTag[4];
593 WORD LangSys;
594 } GSUB_LangSysRecord;
596 typedef struct {
597 WORD DefaultLangSys;
598 WORD LangSysCount;
599 GSUB_LangSysRecord LangSysRecord[1];
600 } GSUB_Script;
602 typedef struct {
603 WORD LookupOrder; /* Reserved */
604 WORD ReqFeatureIndex;
605 WORD FeatureCount;
606 WORD FeatureIndex[1];
607 } GSUB_LangSys;
609 typedef struct {
610 CHAR FeatureTag[4];
611 WORD Feature;
612 } GSUB_FeatureRecord;
614 typedef struct {
615 WORD FeatureCount;
616 GSUB_FeatureRecord FeatureRecord[1];
617 } GSUB_FeatureList;
619 typedef struct {
620 WORD FeatureParams; /* Reserved */
621 WORD LookupCount;
622 WORD LookupListIndex[1];
623 } GSUB_Feature;
625 typedef struct {
626 WORD LookupCount;
627 WORD Lookup[1];
628 } GSUB_LookupList;
630 typedef struct {
631 WORD LookupType;
632 WORD LookupFlag;
633 WORD SubTableCount;
634 WORD SubTable[1];
635 } GSUB_LookupTable;
637 typedef struct {
638 WORD CoverageFormat;
639 WORD GlyphCount;
640 WORD GlyphArray[1];
641 } GSUB_CoverageFormat1;
643 typedef struct {
644 WORD Start;
645 WORD End;
646 WORD StartCoverageIndex;
647 } GSUB_RangeRecord;
649 typedef struct {
650 WORD CoverageFormat;
651 WORD RangeCount;
652 GSUB_RangeRecord RangeRecord[1];
653 } GSUB_CoverageFormat2;
655 typedef struct {
656 WORD SubstFormat; /* = 1 */
657 WORD Coverage;
658 WORD DeltaGlyphID;
659 } GSUB_SingleSubstFormat1;
661 typedef struct {
662 WORD SubstFormat; /* = 2 */
663 WORD Coverage;
664 WORD GlyphCount;
665 WORD Substitute[1];
666 }GSUB_SingleSubstFormat2;
668 #ifdef HAVE_CARBON_CARBON_H
669 static char *find_cache_dir(void)
671 FSRef ref;
672 OSErr err;
673 static char cached_path[MAX_PATH];
674 static const char *wine = "/Wine", *fonts = "/Fonts";
676 if(*cached_path) return cached_path;
678 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
679 if(err != noErr)
681 WARN("can't create cached data folder\n");
682 return NULL;
684 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
685 if(err != noErr)
687 WARN("can't create cached data path\n");
688 *cached_path = '\0';
689 return NULL;
691 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
693 ERR("Could not create full path\n");
694 *cached_path = '\0';
695 return NULL;
697 strcat(cached_path, wine);
699 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
701 WARN("Couldn't mkdir %s\n", cached_path);
702 *cached_path = '\0';
703 return NULL;
705 strcat(cached_path, fonts);
706 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
708 WARN("Couldn't mkdir %s\n", cached_path);
709 *cached_path = '\0';
710 return NULL;
712 return cached_path;
715 /******************************************************************
716 * expand_mac_font
718 * Extracts individual TrueType font files from a Mac suitcase font
719 * and saves them into the user's caches directory (see
720 * find_cache_dir()).
721 * Returns a NULL terminated array of filenames.
723 * We do this because they are apps that try to read ttf files
724 * themselves and they don't like Mac suitcase files.
726 static char **expand_mac_font(const char *path)
728 FSRef ref;
729 SInt16 res_ref;
730 OSStatus s;
731 unsigned int idx;
732 const char *out_dir;
733 const char *filename;
734 int output_len;
735 struct {
736 char **array;
737 unsigned int size, max_size;
738 } ret;
740 TRACE("path %s\n", path);
742 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
743 if(s != noErr)
745 WARN("failed to get ref\n");
746 return NULL;
749 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
750 if(s != noErr)
752 TRACE("no data fork, so trying resource fork\n");
753 res_ref = FSOpenResFile(&ref, fsRdPerm);
754 if(res_ref == -1)
756 TRACE("unable to open resource fork\n");
757 return NULL;
761 ret.size = 0;
762 ret.max_size = 10;
763 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
764 if(!ret.array)
766 CloseResFile(res_ref);
767 return NULL;
770 out_dir = find_cache_dir();
772 filename = strrchr(path, '/');
773 if(!filename) filename = path;
774 else filename++;
776 /* output filename has the form out_dir/filename_%04x.ttf */
777 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
779 UseResFile(res_ref);
780 idx = 1;
781 while(1)
783 FamRec *fam_rec;
784 unsigned short *num_faces_ptr, num_faces, face;
785 AsscEntry *assoc;
786 Handle fond;
787 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
789 fond = Get1IndResource(fond_res, idx);
790 if(!fond) break;
791 TRACE("got fond resource %d\n", idx);
792 HLock(fond);
794 fam_rec = *(FamRec**)fond;
795 num_faces_ptr = (unsigned short *)(fam_rec + 1);
796 num_faces = GET_BE_WORD(*num_faces_ptr);
797 num_faces++;
798 assoc = (AsscEntry*)(num_faces_ptr + 1);
799 TRACE("num faces %04x\n", num_faces);
800 for(face = 0; face < num_faces; face++, assoc++)
802 Handle sfnt;
803 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
804 unsigned short size, font_id;
805 char *output;
807 size = GET_BE_WORD(assoc->fontSize);
808 font_id = GET_BE_WORD(assoc->fontID);
809 if(size != 0)
811 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
812 continue;
815 TRACE("trying to load sfnt id %04x\n", font_id);
816 sfnt = GetResource(sfnt_res, font_id);
817 if(!sfnt)
819 TRACE("can't get sfnt resource %04x\n", font_id);
820 continue;
823 output = HeapAlloc(GetProcessHeap(), 0, output_len);
824 if(output)
826 int fd;
828 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
830 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
831 if(fd != -1 || errno == EEXIST)
833 if(fd != -1)
835 unsigned char *sfnt_data;
837 HLock(sfnt);
838 sfnt_data = *(unsigned char**)sfnt;
839 write(fd, sfnt_data, GetHandleSize(sfnt));
840 HUnlock(sfnt);
841 close(fd);
843 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
845 ret.max_size *= 2;
846 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
848 ret.array[ret.size++] = output;
850 else
852 WARN("unable to create %s\n", output);
853 HeapFree(GetProcessHeap(), 0, output);
856 ReleaseResource(sfnt);
858 HUnlock(fond);
859 ReleaseResource(fond);
860 idx++;
862 CloseResFile(res_ref);
864 return ret.array;
867 #endif /* HAVE_CARBON_CARBON_H */
869 static inline BOOL is_win9x(void)
871 return GetVersion() & 0x80000000;
874 This function builds an FT_Fixed from a double. It fails if the absolute
875 value of the float number is greater than 32768.
877 static inline FT_Fixed FT_FixedFromFloat(double f)
879 return f * 0x10000;
883 This function builds an FT_Fixed from a FIXED. It simply put f.value
884 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
886 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
888 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
892 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
894 Family *family;
895 Face *face;
896 const char *file;
897 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
898 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
900 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
901 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
903 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
905 if(face_name && strcmpiW(face_name, family->FamilyName))
906 continue;
907 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
909 if (!face->file)
910 continue;
911 file = strrchr(face->file, '/');
912 if(!file)
913 file = face->file;
914 else
915 file++;
916 if(!strcasecmp(file, file_nameA))
918 HeapFree(GetProcessHeap(), 0, file_nameA);
919 return face;
923 HeapFree(GetProcessHeap(), 0, file_nameA);
924 return NULL;
927 static Family *find_family_from_name(const WCHAR *name)
929 Family *family;
931 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
933 if(!strcmpiW(family->FamilyName, name))
934 return family;
937 return NULL;
940 static Family *find_family_from_any_name(const WCHAR *name)
942 Family *family;
944 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
946 if(!strcmpiW(family->FamilyName, name))
947 return family;
948 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
949 return family;
952 return NULL;
955 static void DumpSubstList(void)
957 FontSubst *psub;
959 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
961 if(psub->from.charset != -1 || psub->to.charset != -1)
962 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
963 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
964 else
965 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
966 debugstr_w(psub->to.name));
968 return;
971 static LPWSTR strdupW(LPCWSTR p)
973 LPWSTR ret;
974 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
975 ret = HeapAlloc(GetProcessHeap(), 0, len);
976 memcpy(ret, p, len);
977 return ret;
980 static LPSTR strdupA(LPCSTR p)
982 LPSTR ret;
983 DWORD len = (strlen(p) + 1);
984 ret = HeapAlloc(GetProcessHeap(), 0, len);
985 memcpy(ret, p, len);
986 return ret;
989 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
990 INT from_charset)
992 FontSubst *element;
994 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
996 if(!strcmpiW(element->from.name, from_name) &&
997 (element->from.charset == from_charset ||
998 element->from.charset == -1))
999 return element;
1002 return NULL;
1005 #define ADD_FONT_SUBST_FORCE 1
1007 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1009 FontSubst *from_exist, *to_exist;
1011 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1013 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1015 list_remove(&from_exist->entry);
1016 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1017 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1018 HeapFree(GetProcessHeap(), 0, from_exist);
1019 from_exist = NULL;
1022 if(!from_exist)
1024 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1026 if(to_exist)
1028 HeapFree(GetProcessHeap(), 0, subst->to.name);
1029 subst->to.name = strdupW(to_exist->to.name);
1032 list_add_tail(subst_list, &subst->entry);
1034 return TRUE;
1037 HeapFree(GetProcessHeap(), 0, subst->from.name);
1038 HeapFree(GetProcessHeap(), 0, subst->to.name);
1039 HeapFree(GetProcessHeap(), 0, subst);
1040 return FALSE;
1043 static WCHAR *towstr(UINT cp, const char *str)
1045 int len;
1046 WCHAR *wstr;
1048 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1049 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1050 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1051 return wstr;
1054 static void split_subst_info(NameCs *nc, LPSTR str)
1056 CHAR *p = strrchr(str, ',');
1058 nc->charset = -1;
1059 if(p && *(p+1)) {
1060 nc->charset = strtol(p+1, NULL, 10);
1061 *p = '\0';
1063 nc->name = towstr(CP_ACP, str);
1066 static void LoadSubstList(void)
1068 FontSubst *psub;
1069 HKEY hkey;
1070 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1071 LPSTR value;
1072 LPVOID data;
1074 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1075 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1076 &hkey) == ERROR_SUCCESS) {
1078 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1079 &valuelen, &datalen, NULL, NULL);
1081 valuelen++; /* returned value doesn't include room for '\0' */
1082 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1083 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1085 dlen = datalen;
1086 vlen = valuelen;
1087 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1088 &dlen) == ERROR_SUCCESS) {
1089 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1091 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1092 split_subst_info(&psub->from, value);
1093 split_subst_info(&psub->to, data);
1095 /* Win 2000 doesn't allow mapping between different charsets
1096 or mapping of DEFAULT_CHARSET */
1097 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1098 psub->to.charset == DEFAULT_CHARSET) {
1099 HeapFree(GetProcessHeap(), 0, psub->to.name);
1100 HeapFree(GetProcessHeap(), 0, psub->from.name);
1101 HeapFree(GetProcessHeap(), 0, psub);
1102 } else {
1103 add_font_subst(&font_subst_list, psub, 0);
1105 /* reset dlen and vlen */
1106 dlen = datalen;
1107 vlen = valuelen;
1109 HeapFree(GetProcessHeap(), 0, data);
1110 HeapFree(GetProcessHeap(), 0, value);
1111 RegCloseKey(hkey);
1116 /*****************************************************************
1117 * get_name_table_entry
1119 * Supply the platform, encoding, language and name ids in req
1120 * and if the name exists the function will fill in the string
1121 * and string_len members. The string is owned by FreeType so
1122 * don't free it. Returns TRUE if the name is found else FALSE.
1124 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1126 FT_SfntName name;
1127 FT_UInt num_names, name_index;
1129 if(FT_IS_SFNT(ft_face))
1131 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1133 for(name_index = 0; name_index < num_names; name_index++)
1135 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1137 if((name.platform_id == req->platform_id) &&
1138 (name.encoding_id == req->encoding_id) &&
1139 (name.language_id == req->language_id) &&
1140 (name.name_id == req->name_id))
1142 req->string = name.string;
1143 req->string_len = name.string_len;
1144 return TRUE;
1149 req->string = NULL;
1150 req->string_len = 0;
1151 return FALSE;
1154 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1156 WCHAR *ret = NULL;
1157 FT_SfntName name;
1159 name.platform_id = TT_PLATFORM_MICROSOFT;
1160 name.encoding_id = TT_MS_ID_UNICODE_CS;
1161 name.language_id = language_id;
1162 name.name_id = name_id;
1164 if(get_name_table_entry(ft_face, &name))
1166 FT_UInt i;
1168 /* String is not nul terminated and string_len is a byte length. */
1169 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1170 for(i = 0; i < name.string_len / 2; i++)
1172 WORD *tmp = (WORD *)&name.string[i * 2];
1173 ret[i] = GET_BE_WORD(*tmp);
1175 ret[i] = 0;
1176 TRACE("Got localised name %s\n", debugstr_w(ret));
1179 return ret;
1182 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1184 DWORD type, needed;
1185 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1186 if(r != ERROR_SUCCESS) return r;
1187 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1188 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1191 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1193 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1196 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1198 DWORD needed;
1199 DWORD num_strikes, max_strike_key_len;
1201 /* If we have a File Name key then this is a real font, not just the parent
1202 key of a bunch of non-scalable strikes */
1203 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1205 DWORD italic, bold;
1206 Face *face;
1207 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1208 face->cached_enum_data = NULL;
1210 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1211 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1213 face->StyleName = strdupW(face_name);
1214 face->family = family;
1215 face->vertical = (family->FamilyName[0] == '@');
1217 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1219 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1220 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1221 face->FullName = fullName;
1223 else
1224 face->FullName = NULL;
1226 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1227 reg_load_dword(hkey_face, face_italic_value, &italic);
1228 reg_load_dword(hkey_face, face_bold_value, &bold);
1229 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1230 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1232 needed = sizeof(face->fs);
1233 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1234 memset(&face->fs_links, 0, sizeof(face->fs_links));
1236 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1238 face->scalable = TRUE;
1239 memset(&face->size, 0, sizeof(face->size));
1241 else
1243 face->scalable = FALSE;
1244 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1245 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1246 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1247 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1248 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1250 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1251 face->size.height, face->size.width, face->size.size >> 6,
1252 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1255 face->ntmFlags = 0;
1256 if (italic) face->ntmFlags |= NTM_ITALIC;
1257 if (bold) face->ntmFlags |= NTM_BOLD;
1258 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1260 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1261 face->fs.fsCsb[0], face->fs.fsCsb[1],
1262 face->fs.fsUsb[0], face->fs.fsUsb[1],
1263 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1265 if(!italic && !bold)
1266 list_add_head(&family->faces, &face->entry);
1267 else
1268 list_add_tail(&family->faces, &face->entry);
1270 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1273 /* do we have any bitmap strikes? */
1274 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1275 NULL, NULL, NULL, NULL);
1276 if(num_strikes != 0)
1278 WCHAR strike_name[10];
1279 DWORD strike_index = 0;
1281 needed = sizeof(strike_name) / sizeof(WCHAR);
1282 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1283 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1285 HKEY hkey_strike;
1286 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1287 load_face(hkey_strike, face_name, family);
1288 RegCloseKey(hkey_strike);
1289 needed = sizeof(strike_name) / sizeof(WCHAR);
1294 static void load_font_list_from_cache(HKEY hkey_font_cache)
1296 DWORD max_family_key_len, size;
1297 WCHAR *family_name;
1298 DWORD family_index = 0;
1299 Family *family;
1300 HKEY hkey_family;
1302 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1303 NULL, NULL, NULL, NULL);
1304 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1306 size = max_family_key_len + 1;
1307 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1308 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1310 WCHAR *english_family = NULL;
1311 DWORD face_index = 0;
1312 WCHAR *face_name;
1313 DWORD max_face_key_len;
1315 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1316 TRACE("opened family key %s\n", debugstr_w(family_name));
1317 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1319 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1320 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1323 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1324 family->FamilyName = strdupW(family_name);
1325 family->EnglishName = english_family;
1326 list_init(&family->faces);
1327 list_add_tail(&font_list, &family->entry);
1329 if(english_family)
1331 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1332 subst->from.name = strdupW(english_family);
1333 subst->from.charset = -1;
1334 subst->to.name = strdupW(family_name);
1335 subst->to.charset = -1;
1336 add_font_subst(&font_subst_list, subst, 0);
1339 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1340 NULL, NULL, NULL, NULL);
1342 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1343 size = max_face_key_len + 1;
1344 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1345 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1347 HKEY hkey_face;
1349 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1350 load_face(hkey_face, face_name, family);
1351 RegCloseKey(hkey_face);
1352 size = max_face_key_len + 1;
1354 HeapFree(GetProcessHeap(), 0, face_name);
1355 RegCloseKey(hkey_family);
1356 size = max_family_key_len + 1;
1359 HeapFree(GetProcessHeap(), 0, family_name);
1362 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1364 LONG ret;
1365 HKEY hkey_wine_fonts;
1367 /* We don't want to create the fonts key as volatile, so open this first */
1368 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1369 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1370 if(ret != ERROR_SUCCESS)
1372 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1373 return ret;
1376 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1377 KEY_ALL_ACCESS, NULL, hkey, disposition);
1378 RegCloseKey(hkey_wine_fonts);
1379 return ret;
1382 static void add_face_to_cache(Face *face)
1384 HKEY hkey_font_cache, hkey_family, hkey_face;
1385 WCHAR *face_key_name;
1387 create_font_cache_key(&hkey_font_cache, NULL);
1389 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1390 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1391 if(face->family->EnglishName)
1392 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1393 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1395 if(face->scalable)
1396 face_key_name = face->StyleName;
1397 else
1399 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1400 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1401 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1403 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1404 &hkey_face, NULL);
1405 if(!face->scalable)
1406 HeapFree(GetProcessHeap(), 0, face_key_name);
1408 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1409 if (face->FullName)
1410 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1411 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1413 reg_save_dword(hkey_face, face_index_value, face->face_index);
1414 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1415 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1416 reg_save_dword(hkey_face, face_version_value, face->font_version);
1417 reg_save_dword(hkey_face, face_external_value, face->external);
1419 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1421 if(!face->scalable)
1423 reg_save_dword(hkey_face, face_height_value, face->size.height);
1424 reg_save_dword(hkey_face, face_width_value, face->size.width);
1425 reg_save_dword(hkey_face, face_size_value, face->size.size);
1426 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1427 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1428 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1430 RegCloseKey(hkey_face);
1431 RegCloseKey(hkey_family);
1432 RegCloseKey(hkey_font_cache);
1435 static inline int TestStyles(DWORD flags, DWORD styles)
1437 return (flags & styles) == styles;
1440 static int StyleOrdering(Face *face)
1442 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1443 return 3;
1444 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1445 return 2;
1446 if (TestStyles(face->ntmFlags, NTM_BOLD))
1447 return 1;
1448 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1449 return 0;
1451 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1452 debugstr_w(face->family->FamilyName),
1453 debugstr_w(face->StyleName),
1454 face->ntmFlags);
1456 return 9999;
1459 /* Add a style of face to a font family using an ordering of the list such
1460 that regular fonts come before bold and italic, and single styles come
1461 before compound styles. */
1462 static void AddFaceToFamily(Face *face, Family *family)
1464 struct list *entry;
1466 LIST_FOR_EACH( entry, &family->faces )
1468 Face *ent = LIST_ENTRY(entry, Face, entry);
1469 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1471 list_add_before( entry, &face->entry );
1474 static WCHAR *prepend_at(WCHAR *family)
1476 WCHAR *str;
1478 if (!family)
1479 return NULL;
1481 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1482 str[0] = '@';
1483 strcpyW(str + 1, family);
1484 HeapFree(GetProcessHeap(), 0, family);
1485 return str;
1488 #define ADDFONT_EXTERNAL_FONT 0x01
1489 #define ADDFONT_FORCE_BITMAP 0x02
1490 #define ADDFONT_ADD_TO_CACHE 0x04
1492 static void AddFaceToList(FT_Face ft_face, char *fake_family, const char *file, void *font_data_ptr, DWORD font_data_size, FT_Long face_index, DWORD flags, BOOL vertical)
1494 int bitmap_num = 0;
1495 Family *family;
1496 WCHAR *StyleW;
1498 do {
1499 TT_OS2 *pOS2;
1500 TT_Header *pHeader;
1501 WCHAR *english_family, *localised_family;
1502 Face *face;
1503 struct list *face_elem_ptr;
1504 FT_WinFNT_HeaderRec winfnt_header;
1505 int internal_leading;
1506 FONTSIGNATURE fs;
1507 My_FT_Bitmap_Size *size = NULL;
1508 FT_ULong tmp_size;
1510 if(!FT_IS_SCALABLE(ft_face))
1511 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1513 if (fake_family)
1515 english_family = towstr(CP_ACP, fake_family);
1516 localised_family = NULL;
1518 else
1520 english_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1521 if (!english_family)
1522 english_family = towstr(CP_ACP, ft_face->family_name);
1524 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1525 if (localised_family && !strcmpiW(localised_family, english_family))
1527 HeapFree(GetProcessHeap(), 0, localised_family);
1528 localised_family = NULL;
1532 if (vertical)
1534 english_family = prepend_at(english_family);
1535 localised_family = prepend_at(localised_family);
1538 family = find_family_from_name(localised_family ? localised_family : english_family);
1539 if(!family) {
1540 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1541 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1542 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1543 list_init(&family->faces);
1544 list_add_tail(&font_list, &family->entry);
1546 if(localised_family) {
1547 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1548 subst->from.name = strdupW(english_family);
1549 subst->from.charset = -1;
1550 subst->to.name = strdupW(localised_family);
1551 subst->to.charset = -1;
1552 add_font_subst(&font_subst_list, subst, 0);
1555 HeapFree(GetProcessHeap(), 0, localised_family);
1556 HeapFree(GetProcessHeap(), 0, english_family);
1558 StyleW = towstr(CP_ACP, ft_face->style_name);
1560 internal_leading = 0;
1561 memset(&fs, 0, sizeof(fs));
1563 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1564 if(pOS2) {
1565 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1566 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1567 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1568 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1569 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1570 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1571 if(pOS2->version == 0) {
1572 FT_UInt dummy;
1574 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1575 fs.fsCsb[0] |= FS_LATIN1;
1576 else
1577 fs.fsCsb[0] |= FS_SYMBOL;
1580 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1581 CHARSETINFO csi;
1582 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1583 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1584 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1585 fs = csi.fs;
1586 internal_leading = winfnt_header.internal_leading;
1589 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1590 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1591 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1592 if(!strcmpiW(face->StyleName, StyleW) &&
1593 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1594 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1595 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1596 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1598 if(fake_family) {
1599 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1600 HeapFree(GetProcessHeap(), 0, StyleW);
1601 return;
1603 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1604 TRACE("Original font is newer so skipping this one\n");
1605 HeapFree(GetProcessHeap(), 0, StyleW);
1606 return;
1607 } else {
1608 TRACE("Replacing original with this one\n");
1609 list_remove(&face->entry);
1610 HeapFree(GetProcessHeap(), 0, face->file);
1611 HeapFree(GetProcessHeap(), 0, face->StyleName);
1612 HeapFree(GetProcessHeap(), 0, face->FullName);
1613 HeapFree(GetProcessHeap(), 0, face);
1614 break;
1618 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1619 face->cached_enum_data = NULL;
1620 face->StyleName = StyleW;
1621 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1622 if (file)
1624 face->file = strdupA(file);
1625 face->font_data_ptr = NULL;
1626 face->font_data_size = 0;
1628 else
1630 face->file = NULL;
1631 face->font_data_ptr = font_data_ptr;
1632 face->font_data_size = font_data_size;
1634 face->face_index = face_index;
1635 face->ntmFlags = 0;
1636 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1637 face->ntmFlags |= NTM_ITALIC;
1638 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1639 face->ntmFlags |= NTM_BOLD;
1640 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1641 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1642 face->family = family;
1643 face->vertical = vertical;
1644 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1645 face->fs = fs;
1646 memset(&face->fs_links, 0, sizeof(face->fs_links));
1648 if(FT_IS_SCALABLE(ft_face)) {
1649 memset(&face->size, 0, sizeof(face->size));
1650 face->scalable = TRUE;
1651 } else {
1652 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1653 size->height, size->width, size->size >> 6,
1654 size->x_ppem >> 6, size->y_ppem >> 6);
1655 face->size.height = size->height;
1656 face->size.width = size->width;
1657 face->size.size = size->size;
1658 face->size.x_ppem = size->x_ppem;
1659 face->size.y_ppem = size->y_ppem;
1660 face->size.internal_leading = internal_leading;
1661 face->scalable = FALSE;
1664 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1665 tmp_size = 0;
1666 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1668 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1669 face->ntmFlags |= NTM_PS_OPENTYPE;
1672 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1673 face->fs.fsCsb[0], face->fs.fsCsb[1],
1674 face->fs.fsUsb[0], face->fs.fsUsb[1],
1675 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1677 if(face->fs.fsCsb[0] == 0)
1679 int i;
1681 /* let's see if we can find any interesting cmaps */
1682 for(i = 0; i < ft_face->num_charmaps; i++) {
1683 switch(ft_face->charmaps[i]->encoding) {
1684 case FT_ENCODING_UNICODE:
1685 case FT_ENCODING_APPLE_ROMAN:
1686 face->fs.fsCsb[0] |= FS_LATIN1;
1687 break;
1688 case FT_ENCODING_MS_SYMBOL:
1689 face->fs.fsCsb[0] |= FS_SYMBOL;
1690 break;
1691 default:
1692 break;
1697 if(flags & ADDFONT_ADD_TO_CACHE)
1698 add_face_to_cache(face);
1700 AddFaceToFamily(face, family);
1702 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1704 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1705 debugstr_w(StyleW));
1708 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1710 FT_Face ft_face;
1711 TT_OS2 *pOS2;
1712 TT_Header *pHeader = NULL;
1713 WCHAR *localised_family;
1714 FT_Error err;
1715 FT_Long face_index = 0, num_faces;
1716 INT ret = 0;
1718 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1719 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1721 #ifdef HAVE_CARBON_CARBON_H
1722 if(file && !fake_family)
1724 char **mac_list = expand_mac_font(file);
1725 if(mac_list)
1727 BOOL had_one = FALSE;
1728 char **cursor;
1729 for(cursor = mac_list; *cursor; cursor++)
1731 had_one = TRUE;
1732 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1733 HeapFree(GetProcessHeap(), 0, *cursor);
1735 HeapFree(GetProcessHeap(), 0, mac_list);
1736 if(had_one)
1737 return 1;
1740 #endif /* HAVE_CARBON_CARBON_H */
1742 do {
1743 if (file)
1745 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1746 err = pFT_New_Face(library, file, face_index, &ft_face);
1747 } else
1749 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1750 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1753 if(err != 0) {
1754 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1755 return 0;
1758 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1759 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1760 pFT_Done_Face(ft_face);
1761 return 0;
1764 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1765 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1766 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1767 pFT_Done_Face(ft_face);
1768 return 0;
1771 if(FT_IS_SFNT(ft_face))
1773 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1774 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1775 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1777 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1778 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1779 pFT_Done_Face(ft_face);
1780 return 0;
1783 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1784 we don't want to load these. */
1785 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1787 FT_ULong len = 0;
1789 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1791 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1792 pFT_Done_Face(ft_face);
1793 return 0;
1798 if(!ft_face->family_name || !ft_face->style_name) {
1799 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1800 pFT_Done_Face(ft_face);
1801 return 0;
1804 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1806 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1807 pFT_Done_Face(ft_face);
1808 return 0;
1811 if (target_family)
1813 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1814 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1816 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1817 HeapFree(GetProcessHeap(), 0, localised_family);
1818 num_faces = ft_face->num_faces;
1819 pFT_Done_Face(ft_face);
1820 continue;
1822 HeapFree(GetProcessHeap(), 0, localised_family);
1825 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1826 ++ret;
1828 if (FT_HAS_VERTICAL(ft_face))
1830 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1831 ++ret;
1834 num_faces = ft_face->num_faces;
1835 pFT_Done_Face(ft_face);
1836 } while(num_faces > ++face_index);
1837 return ret;
1840 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1842 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1845 static void DumpFontList(void)
1847 Family *family;
1848 Face *face;
1849 struct list *family_elem_ptr, *face_elem_ptr;
1851 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1852 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1853 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1854 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1855 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1856 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1857 if(!face->scalable)
1858 TRACE(" %d", face->size.height);
1859 TRACE("\n");
1862 return;
1865 /***********************************************************
1866 * The replacement list is a way to map an entire font
1867 * family onto another family. For example adding
1869 * [HKCU\Software\Wine\Fonts\Replacements]
1870 * "Wingdings"="Winedings"
1872 * would enumerate the Winedings font both as Winedings and
1873 * Wingdings. However if a real Wingdings font is present the
1874 * replacement does not take place.
1877 static void LoadReplaceList(void)
1879 HKEY hkey;
1880 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1881 LPWSTR value;
1882 LPVOID data;
1883 CHAR familyA[400];
1885 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1886 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1888 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1889 &valuelen, &datalen, NULL, NULL);
1891 valuelen++; /* returned value doesn't include room for '\0' */
1892 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1893 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1895 dlen = datalen;
1896 vlen = valuelen;
1897 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1898 &dlen) == ERROR_SUCCESS) {
1899 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1900 /* "NewName"="Oldname" */
1901 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1903 if(!find_family_from_any_name(value))
1905 /* Find the old family and hence all of the font files
1906 in that family */
1907 const Family * const family = find_family_from_any_name(data);
1908 if (family != NULL)
1910 const struct list *face_elem_ptr;
1911 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1912 const Face * const face = LIST_ENTRY(face_elem_ptr, Face, entry);
1913 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1914 debugstr_w(face->StyleName), familyA);
1915 /* Now add a new entry with the new family name */
1916 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1917 familyA, family->FamilyName,
1918 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1921 else
1923 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1926 else
1928 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
1930 /* reset dlen and vlen */
1931 dlen = datalen;
1932 vlen = valuelen;
1934 HeapFree(GetProcessHeap(), 0, data);
1935 HeapFree(GetProcessHeap(), 0, value);
1936 RegCloseKey(hkey);
1940 static const WCHAR *font_links_list[] =
1942 Lucida_Sans_Unicode,
1943 Microsoft_Sans_Serif,
1944 Tahoma
1947 static const struct font_links_defaults_list
1949 /* Keyed off substitution for "MS Shell Dlg" */
1950 const WCHAR *shelldlg;
1951 /* Maximum of four substitutes, plus terminating NULL pointer */
1952 const WCHAR *substitutes[5];
1953 } font_links_defaults_list[] =
1955 /* Non East-Asian */
1956 { Tahoma, /* FIXME unverified ordering */
1957 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
1959 /* Below lists are courtesy of
1960 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
1962 /* Japanese */
1963 { MS_UI_Gothic,
1964 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
1966 /* Chinese Simplified */
1967 { SimSun,
1968 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
1970 /* Korean */
1971 { Gulim,
1972 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
1974 /* Chinese Traditional */
1975 { PMingLiU,
1976 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
1981 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
1983 const WCHAR *value;
1984 int i;
1985 FontSubst *psub;
1986 Family *family;
1987 Face *face;
1988 const char *file;
1989 WCHAR *fileW;
1990 FONTSIGNATURE fs;
1992 if (values)
1994 SYSTEM_LINKS *font_link;
1995 BOOL existing = FALSE;
1997 memset(&fs, 0, sizeof(fs));
1998 psub = get_font_subst(&font_subst_list, name, -1);
1999 /* Don't store fonts that are only substitutes for other fonts */
2000 if(psub)
2002 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2003 return;
2006 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2008 if(!strcmpiW(font_link->font_name, name))
2010 existing = TRUE;
2011 break;
2015 if (!existing)
2017 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2018 font_link->font_name = strdupW(name);
2019 list_init(&font_link->links);
2022 for (i = 0; values[i] != NULL; i++)
2024 CHILD_FONT *child_font;
2026 value = values[i];
2027 if (!strcmpiW(name,value))
2028 continue;
2029 psub = get_font_subst(&font_subst_list, value, -1);
2030 if(psub)
2031 value = psub->to.name;
2032 family = find_family_from_name(value);
2033 if (!family)
2034 continue;
2035 file = NULL;
2036 /* Use first extant filename for this Family */
2037 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2039 if (!face->file)
2040 continue;
2041 file = strrchr(face->file, '/');
2042 if (!file)
2043 file = face->file;
2044 else
2045 file++;
2046 break;
2048 if (!file)
2049 continue;
2050 fileW = towstr(CP_UNIXCP, file);
2052 face = find_face_from_filename(fileW, value);
2053 if(!face)
2055 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2056 continue;
2059 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2060 child_font->face = face;
2061 child_font->font = NULL;
2062 fs.fsCsb[0] |= face->fs.fsCsb[0];
2063 fs.fsCsb[1] |= face->fs.fsCsb[1];
2064 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2065 list_add_tail(&font_link->links, &child_font->entry);
2067 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2068 HeapFree(GetProcessHeap(), 0, fileW);
2071 family = find_family_from_name(font_link->font_name);
2072 if(family)
2074 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2076 face->fs_links = fs;
2079 if (!existing)
2080 list_add_tail(&system_links, &font_link->entry);
2085 /*************************************************************
2086 * init_system_links
2088 static BOOL init_system_links(void)
2090 HKEY hkey;
2091 BOOL ret = FALSE;
2092 DWORD type, max_val, max_data, val_len, data_len, index;
2093 WCHAR *value, *data;
2094 WCHAR *entry, *next;
2095 SYSTEM_LINKS *font_link, *system_font_link;
2096 CHILD_FONT *child_font;
2097 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2098 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2099 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2100 FONTSIGNATURE fs;
2101 Family *family;
2102 Face *face;
2103 FontSubst *psub;
2104 UINT i, j;
2106 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2108 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2109 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2110 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2111 val_len = max_val + 1;
2112 data_len = max_data;
2113 index = 0;
2114 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2116 memset(&fs, 0, sizeof(fs));
2117 psub = get_font_subst(&font_subst_list, value, -1);
2118 /* Don't store fonts that are only substitutes for other fonts */
2119 if(psub)
2121 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2122 goto next;
2124 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2125 font_link->font_name = strdupW(value);
2126 list_init(&font_link->links);
2127 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2129 WCHAR *face_name;
2130 CHILD_FONT *child_font;
2132 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2134 next = entry + strlenW(entry) + 1;
2136 face_name = strchrW(entry, ',');
2137 if(face_name)
2139 *face_name++ = 0;
2140 while(isspaceW(*face_name))
2141 face_name++;
2143 psub = get_font_subst(&font_subst_list, face_name, -1);
2144 if(psub)
2145 face_name = psub->to.name;
2147 face = find_face_from_filename(entry, face_name);
2148 if(!face)
2150 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2151 continue;
2154 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2155 child_font->face = face;
2156 child_font->font = NULL;
2157 fs.fsCsb[0] |= face->fs.fsCsb[0];
2158 fs.fsCsb[1] |= face->fs.fsCsb[1];
2159 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2160 list_add_tail(&font_link->links, &child_font->entry);
2162 family = find_family_from_name(font_link->font_name);
2163 if(family)
2165 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2167 face->fs_links = fs;
2170 list_add_tail(&system_links, &font_link->entry);
2171 next:
2172 val_len = max_val + 1;
2173 data_len = max_data;
2176 HeapFree(GetProcessHeap(), 0, value);
2177 HeapFree(GetProcessHeap(), 0, data);
2178 RegCloseKey(hkey);
2182 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2183 if (!psub) {
2184 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2185 goto skip_internal;
2188 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2190 const FontSubst *psub2;
2191 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2193 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2195 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2196 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2198 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2199 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2201 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2203 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2207 skip_internal:
2209 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2210 that Tahoma has */
2212 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2213 system_font_link->font_name = strdupW(System);
2214 list_init(&system_font_link->links);
2215 memset(&fs, 0, sizeof(fs));
2217 face = find_face_from_filename(tahoma_ttf, Tahoma);
2218 if(face)
2220 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2221 child_font->face = face;
2222 child_font->font = NULL;
2223 fs.fsCsb[0] |= face->fs.fsCsb[0];
2224 fs.fsCsb[1] |= face->fs.fsCsb[1];
2225 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2226 list_add_tail(&system_font_link->links, &child_font->entry);
2228 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2230 if(!strcmpiW(font_link->font_name, Tahoma))
2232 CHILD_FONT *font_link_entry;
2233 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2235 CHILD_FONT *new_child;
2236 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2237 new_child->face = font_link_entry->face;
2238 new_child->font = NULL;
2239 fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2240 fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2241 list_add_tail(&system_font_link->links, &new_child->entry);
2243 break;
2246 family = find_family_from_name(system_font_link->font_name);
2247 if(family)
2249 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2251 face->fs_links = fs;
2254 list_add_tail(&system_links, &system_font_link->entry);
2255 return ret;
2258 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2260 DIR *dir;
2261 struct dirent *dent;
2262 char path[MAX_PATH];
2264 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2266 dir = opendir(dirname);
2267 if(!dir) {
2268 WARN("Can't open directory %s\n", debugstr_a(dirname));
2269 return FALSE;
2271 while((dent = readdir(dir)) != NULL) {
2272 struct stat statbuf;
2274 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2275 continue;
2277 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2279 sprintf(path, "%s/%s", dirname, dent->d_name);
2281 if(stat(path, &statbuf) == -1)
2283 WARN("Can't stat %s\n", debugstr_a(path));
2284 continue;
2286 if(S_ISDIR(statbuf.st_mode))
2287 ReadFontDir(path, external_fonts);
2288 else
2290 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2291 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2292 AddFontFileToList(path, NULL, NULL, addfont_flags);
2295 closedir(dir);
2296 return TRUE;
2299 static void load_fontconfig_fonts(void)
2301 #ifdef SONAME_LIBFONTCONFIG
2302 void *fc_handle = NULL;
2303 FcConfig *config;
2304 FcPattern *pat;
2305 FcObjectSet *os;
2306 FcFontSet *fontset;
2307 int i, len;
2308 char *file;
2309 const char *ext;
2311 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2312 if(!fc_handle) {
2313 TRACE("Wine cannot find the fontconfig library (%s).\n",
2314 SONAME_LIBFONTCONFIG);
2315 return;
2317 #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;}
2318 LOAD_FUNCPTR(FcConfigGetCurrent);
2319 LOAD_FUNCPTR(FcFontList);
2320 LOAD_FUNCPTR(FcFontSetDestroy);
2321 LOAD_FUNCPTR(FcInit);
2322 LOAD_FUNCPTR(FcObjectSetAdd);
2323 LOAD_FUNCPTR(FcObjectSetCreate);
2324 LOAD_FUNCPTR(FcObjectSetDestroy);
2325 LOAD_FUNCPTR(FcPatternCreate);
2326 LOAD_FUNCPTR(FcPatternDestroy);
2327 LOAD_FUNCPTR(FcPatternGetBool);
2328 LOAD_FUNCPTR(FcPatternGetString);
2329 #undef LOAD_FUNCPTR
2331 if(!pFcInit()) return;
2333 config = pFcConfigGetCurrent();
2334 pat = pFcPatternCreate();
2335 os = pFcObjectSetCreate();
2336 pFcObjectSetAdd(os, FC_FILE);
2337 pFcObjectSetAdd(os, FC_SCALABLE);
2338 fontset = pFcFontList(config, pat, os);
2339 if(!fontset) return;
2340 for(i = 0; i < fontset->nfont; i++) {
2341 FcBool scalable;
2343 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2344 continue;
2345 TRACE("fontconfig: %s\n", file);
2347 /* We're just interested in OT/TT fonts for now, so this hack just
2348 picks up the scalable fonts without extensions .pf[ab] to save time
2349 loading every other font */
2351 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2353 TRACE("not scalable\n");
2354 continue;
2357 len = strlen( file );
2358 if(len < 4) continue;
2359 ext = &file[ len - 3 ];
2360 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2361 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2363 pFcFontSetDestroy(fontset);
2364 pFcObjectSetDestroy(os);
2365 pFcPatternDestroy(pat);
2366 sym_not_found:
2367 #endif
2368 return;
2371 static BOOL load_font_from_data_dir(LPCWSTR file)
2373 BOOL ret = FALSE;
2374 const char *data_dir = wine_get_data_dir();
2376 if (!data_dir) data_dir = wine_get_build_dir();
2378 if (data_dir)
2380 INT len;
2381 char *unix_name;
2383 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2385 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2387 strcpy(unix_name, data_dir);
2388 strcat(unix_name, "/fonts/");
2390 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2392 EnterCriticalSection( &freetype_cs );
2393 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2394 LeaveCriticalSection( &freetype_cs );
2395 HeapFree(GetProcessHeap(), 0, unix_name);
2397 return ret;
2400 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2402 static const WCHAR slashW[] = {'\\','\0'};
2403 BOOL ret = FALSE;
2404 WCHAR windowsdir[MAX_PATH];
2405 char *unixname;
2407 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2408 strcatW(windowsdir, fontsW);
2409 strcatW(windowsdir, slashW);
2410 strcatW(windowsdir, file);
2411 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2412 EnterCriticalSection( &freetype_cs );
2413 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2414 LeaveCriticalSection( &freetype_cs );
2415 HeapFree(GetProcessHeap(), 0, unixname);
2417 return ret;
2420 static void load_system_fonts(void)
2422 HKEY hkey;
2423 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2424 const WCHAR * const *value;
2425 DWORD dlen, type;
2426 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2427 char *unixname;
2429 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2430 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2431 strcatW(windowsdir, fontsW);
2432 for(value = SystemFontValues; *value; value++) {
2433 dlen = sizeof(data);
2434 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2435 type == REG_SZ) {
2436 BOOL added = FALSE;
2438 sprintfW(pathW, fmtW, windowsdir, data);
2439 if((unixname = wine_get_unix_file_name(pathW))) {
2440 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2441 HeapFree(GetProcessHeap(), 0, unixname);
2443 if (!added)
2444 load_font_from_data_dir(data);
2447 RegCloseKey(hkey);
2451 /*************************************************************
2453 * This adds registry entries for any externally loaded fonts
2454 * (fonts from fontconfig or FontDirs). It also deletes entries
2455 * of no longer existing fonts.
2458 static void update_reg_entries(void)
2460 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2461 LPWSTR valueW;
2462 DWORD len, len_fam;
2463 Family *family;
2464 Face *face;
2465 struct list *family_elem_ptr, *face_elem_ptr;
2466 WCHAR *file;
2467 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2468 static const WCHAR spaceW[] = {' ', '\0'};
2469 char *path;
2471 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2472 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2473 ERR("Can't create Windows font reg key\n");
2474 goto end;
2477 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2478 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2479 ERR("Can't create Windows font reg key\n");
2480 goto end;
2483 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2484 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2485 ERR("Can't create external font reg key\n");
2486 goto end;
2489 /* enumerate the fonts and add external ones to the two keys */
2491 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2492 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2493 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2494 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2495 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2496 if(!face->external) continue;
2497 len = len_fam;
2498 if (!(face->ntmFlags & NTM_REGULAR))
2499 len = len_fam + strlenW(face->StyleName) + 1;
2500 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2501 strcpyW(valueW, family->FamilyName);
2502 if(len != len_fam) {
2503 strcatW(valueW, spaceW);
2504 strcatW(valueW, face->StyleName);
2506 strcatW(valueW, TrueType);
2508 file = wine_get_dos_file_name(face->file);
2509 if(file)
2510 len = strlenW(file) + 1;
2511 else
2513 if((path = strrchr(face->file, '/')) == NULL)
2514 path = face->file;
2515 else
2516 path++;
2517 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2519 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2520 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2522 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2523 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2524 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2526 HeapFree(GetProcessHeap(), 0, file);
2527 HeapFree(GetProcessHeap(), 0, valueW);
2530 end:
2531 if(external_key) RegCloseKey(external_key);
2532 if(win9x_key) RegCloseKey(win9x_key);
2533 if(winnt_key) RegCloseKey(winnt_key);
2534 return;
2537 static void delete_external_font_keys(void)
2539 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2540 DWORD dlen, vlen, datalen, valuelen, i, type;
2541 LPWSTR valueW;
2542 LPVOID data;
2544 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2545 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2546 ERR("Can't create Windows font reg key\n");
2547 goto end;
2550 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2551 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2552 ERR("Can't create Windows font reg key\n");
2553 goto end;
2556 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2557 ERR("Can't create external font reg key\n");
2558 goto end;
2561 /* Delete all external fonts added last time */
2563 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2564 &valuelen, &datalen, NULL, NULL);
2565 valuelen++; /* returned value doesn't include room for '\0' */
2566 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2567 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2569 dlen = datalen * sizeof(WCHAR);
2570 vlen = valuelen;
2571 i = 0;
2572 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2573 &dlen) == ERROR_SUCCESS) {
2575 RegDeleteValueW(winnt_key, valueW);
2576 RegDeleteValueW(win9x_key, valueW);
2577 /* reset dlen and vlen */
2578 dlen = datalen;
2579 vlen = valuelen;
2581 HeapFree(GetProcessHeap(), 0, data);
2582 HeapFree(GetProcessHeap(), 0, valueW);
2584 /* Delete the old external fonts key */
2585 RegCloseKey(external_key);
2586 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2588 end:
2589 if(win9x_key) RegCloseKey(win9x_key);
2590 if(winnt_key) RegCloseKey(winnt_key);
2593 /*************************************************************
2594 * WineEngAddFontResourceEx
2597 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2599 INT ret = 0;
2601 GDI_CheckNotLock();
2603 if (ft_handle) /* do it only if we have freetype up and running */
2605 char *unixname;
2607 if(flags)
2608 FIXME("Ignoring flags %x\n", flags);
2610 if((unixname = wine_get_unix_file_name(file)))
2612 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2614 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2615 EnterCriticalSection( &freetype_cs );
2616 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2617 LeaveCriticalSection( &freetype_cs );
2618 HeapFree(GetProcessHeap(), 0, unixname);
2620 if (!ret && !strchrW(file, '\\')) {
2621 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2622 ret = load_font_from_winfonts_dir(file);
2623 if (!ret) {
2624 /* Try in datadir/fonts (or builddir/fonts),
2625 * needed for Magic the Gathering Online
2627 ret = load_font_from_data_dir(file);
2631 return ret;
2634 /*************************************************************
2635 * WineEngAddFontMemResourceEx
2638 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2640 GDI_CheckNotLock();
2642 if (ft_handle) /* do it only if we have freetype up and running */
2644 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2646 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2647 memcpy(pFontCopy, pbFont, cbFont);
2649 EnterCriticalSection( &freetype_cs );
2650 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2651 LeaveCriticalSection( &freetype_cs );
2653 if (*pcFonts == 0)
2655 TRACE("AddFontToList failed\n");
2656 HeapFree(GetProcessHeap(), 0, pFontCopy);
2657 return 0;
2659 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2660 * For now return something unique but quite random
2662 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2663 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2666 *pcFonts = 0;
2667 return 0;
2670 /*************************************************************
2671 * WineEngRemoveFontResourceEx
2674 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2676 GDI_CheckNotLock();
2677 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2678 return TRUE;
2681 static const struct nls_update_font_list
2683 UINT ansi_cp, oem_cp;
2684 const char *oem, *fixed, *system;
2685 const char *courier, *serif, *small, *sserif;
2686 /* these are for font substitutes */
2687 const char *shelldlg, *tmsrmn;
2688 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2689 *helv_0, *tmsrmn_0;
2690 const struct subst
2692 const char *from, *to;
2693 } arial_0, courier_new_0, times_new_roman_0;
2694 } nls_update_font_list[] =
2696 /* Latin 1 (United States) */
2697 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2698 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2699 "Tahoma","Times New Roman",
2700 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2701 { 0 }, { 0 }, { 0 }
2703 /* Latin 1 (Multilingual) */
2704 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2705 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2706 "Tahoma","Times New Roman", /* FIXME unverified */
2707 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2708 { 0 }, { 0 }, { 0 }
2710 /* Eastern Europe */
2711 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2712 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2713 "Tahoma","Times New Roman", /* FIXME unverified */
2714 "Fixedsys,238", "System,238",
2715 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2716 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2717 { "Arial CE,0", "Arial,238" },
2718 { "Courier New CE,0", "Courier New,238" },
2719 { "Times New Roman CE,0", "Times New Roman,238" }
2721 /* Cyrillic */
2722 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2723 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2724 "Tahoma","Times New Roman", /* FIXME unverified */
2725 "Fixedsys,204", "System,204",
2726 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2727 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2728 { "Arial Cyr,0", "Arial,204" },
2729 { "Courier New Cyr,0", "Courier New,204" },
2730 { "Times New Roman Cyr,0", "Times New Roman,204" }
2732 /* Greek */
2733 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2734 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2735 "Tahoma","Times New Roman", /* FIXME unverified */
2736 "Fixedsys,161", "System,161",
2737 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2738 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2739 { "Arial Greek,0", "Arial,161" },
2740 { "Courier New Greek,0", "Courier New,161" },
2741 { "Times New Roman Greek,0", "Times New Roman,161" }
2743 /* Turkish */
2744 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2745 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2746 "Tahoma","Times New Roman", /* FIXME unverified */
2747 "Fixedsys,162", "System,162",
2748 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2749 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2750 { "Arial Tur,0", "Arial,162" },
2751 { "Courier New Tur,0", "Courier New,162" },
2752 { "Times New Roman Tur,0", "Times New Roman,162" }
2754 /* Hebrew */
2755 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2756 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2757 "Tahoma","Times New Roman", /* FIXME unverified */
2758 "Fixedsys,177", "System,177",
2759 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2760 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2761 { 0 }, { 0 }, { 0 }
2763 /* Arabic */
2764 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2765 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2766 "Tahoma","Times New Roman", /* FIXME unverified */
2767 "Fixedsys,178", "System,178",
2768 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2769 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2770 { 0 }, { 0 }, { 0 }
2772 /* Baltic */
2773 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2774 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2775 "Tahoma","Times New Roman", /* FIXME unverified */
2776 "Fixedsys,186", "System,186",
2777 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2778 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2779 { "Arial Baltic,0", "Arial,186" },
2780 { "Courier New Baltic,0", "Courier New,186" },
2781 { "Times New Roman Baltic,0", "Times New Roman,186" }
2783 /* Vietnamese */
2784 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2785 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2786 "Tahoma","Times New Roman", /* FIXME unverified */
2787 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2788 { 0 }, { 0 }, { 0 }
2790 /* Thai */
2791 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2792 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2793 "Tahoma","Times New Roman", /* FIXME unverified */
2794 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2795 { 0 }, { 0 }, { 0 }
2797 /* Japanese */
2798 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2799 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2800 "MS UI Gothic","MS Serif",
2801 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2802 { 0 }, { 0 }, { 0 }
2804 /* Chinese Simplified */
2805 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2806 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2807 "SimSun", "NSimSun",
2808 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2809 { 0 }, { 0 }, { 0 }
2811 /* Korean */
2812 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2813 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2814 "Gulim", "Batang",
2815 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2816 { 0 }, { 0 }, { 0 }
2818 /* Chinese Traditional */
2819 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2820 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2821 "PMingLiU", "MingLiU",
2822 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2823 { 0 }, { 0 }, { 0 }
2827 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2829 return ( ansi_cp == 932 /* CP932 for Japanese */
2830 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2831 || ansi_cp == 949 /* CP949 for Korean */
2832 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2835 static inline HKEY create_fonts_NT_registry_key(void)
2837 HKEY hkey = 0;
2839 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2840 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2841 return hkey;
2844 static inline HKEY create_fonts_9x_registry_key(void)
2846 HKEY hkey = 0;
2848 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2849 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2850 return hkey;
2853 static inline HKEY create_config_fonts_registry_key(void)
2855 HKEY hkey = 0;
2857 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2858 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2859 return hkey;
2862 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2864 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2865 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2866 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2867 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2870 static void set_value_key(HKEY hkey, const char *name, const char *value)
2872 if (value)
2873 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2874 else if (name)
2875 RegDeleteValueA(hkey, name);
2878 static void update_font_info(void)
2880 char buf[40], cpbuf[40];
2881 DWORD len, type;
2882 HKEY hkey = 0;
2883 UINT i, ansi_cp = 0, oem_cp = 0;
2884 BOOL done = FALSE;
2886 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2887 return;
2889 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2890 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2891 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2892 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2893 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2895 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2896 if (is_dbcs_ansi_cp(ansi_cp))
2897 use_default_fallback = TRUE;
2899 len = sizeof(buf);
2900 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2902 if (!strcmp( buf, cpbuf )) /* already set correctly */
2904 RegCloseKey(hkey);
2905 return;
2907 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2909 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2911 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2912 RegCloseKey(hkey);
2914 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2916 HKEY hkey;
2918 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2919 nls_update_font_list[i].oem_cp == oem_cp)
2921 hkey = create_config_fonts_registry_key();
2922 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2923 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2924 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2925 RegCloseKey(hkey);
2927 hkey = create_fonts_NT_registry_key();
2928 add_font_list(hkey, &nls_update_font_list[i]);
2929 RegCloseKey(hkey);
2931 hkey = create_fonts_9x_registry_key();
2932 add_font_list(hkey, &nls_update_font_list[i]);
2933 RegCloseKey(hkey);
2935 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2937 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2938 strlen(nls_update_font_list[i].shelldlg)+1);
2939 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2940 strlen(nls_update_font_list[i].tmsrmn)+1);
2942 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2943 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2944 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2945 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2946 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2947 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2948 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2949 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2951 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2952 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2953 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2955 RegCloseKey(hkey);
2957 done = TRUE;
2959 else
2961 /* Delete the FontSubstitutes from other locales */
2962 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2964 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2965 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2966 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2967 RegCloseKey(hkey);
2971 if (!done)
2972 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2975 static BOOL init_freetype(void)
2977 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2978 if(!ft_handle) {
2979 WINE_MESSAGE(
2980 "Wine cannot find the FreeType font library. To enable Wine to\n"
2981 "use TrueType fonts please install a version of FreeType greater than\n"
2982 "or equal to 2.0.5.\n"
2983 "http://www.freetype.org\n");
2984 return FALSE;
2987 #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;}
2989 LOAD_FUNCPTR(FT_Done_Face)
2990 LOAD_FUNCPTR(FT_Get_Char_Index)
2991 LOAD_FUNCPTR(FT_Get_First_Char)
2992 LOAD_FUNCPTR(FT_Get_Module)
2993 LOAD_FUNCPTR(FT_Get_Next_Char)
2994 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2995 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2996 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2997 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2998 LOAD_FUNCPTR(FT_Init_FreeType)
2999 LOAD_FUNCPTR(FT_Library_Version)
3000 LOAD_FUNCPTR(FT_Load_Glyph)
3001 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3002 LOAD_FUNCPTR(FT_Matrix_Multiply)
3003 #ifndef FT_MULFIX_INLINED
3004 LOAD_FUNCPTR(FT_MulFix)
3005 #endif
3006 LOAD_FUNCPTR(FT_New_Face)
3007 LOAD_FUNCPTR(FT_New_Memory_Face)
3008 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3009 LOAD_FUNCPTR(FT_Outline_Transform)
3010 LOAD_FUNCPTR(FT_Outline_Translate)
3011 LOAD_FUNCPTR(FT_Render_Glyph)
3012 LOAD_FUNCPTR(FT_Select_Charmap)
3013 LOAD_FUNCPTR(FT_Set_Charmap)
3014 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3015 LOAD_FUNCPTR(FT_Vector_Transform)
3016 LOAD_FUNCPTR(FT_Vector_Unit)
3017 #undef LOAD_FUNCPTR
3018 /* Don't warn if these ones are missing */
3019 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3020 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3021 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3022 #endif
3024 if(pFT_Init_FreeType(&library) != 0) {
3025 ERR("Can't init FreeType library\n");
3026 wine_dlclose(ft_handle, NULL, 0);
3027 ft_handle = NULL;
3028 return FALSE;
3030 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3032 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3033 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3034 ((FT_Version.minor << 8) & 0x00ff00) |
3035 ((FT_Version.patch ) & 0x0000ff);
3037 font_driver = &freetype_funcs;
3038 return TRUE;
3040 sym_not_found:
3041 WINE_MESSAGE(
3042 "Wine cannot find certain functions that it needs inside the FreeType\n"
3043 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3044 "FreeType to at least version 2.1.4.\n"
3045 "http://www.freetype.org\n");
3046 wine_dlclose(ft_handle, NULL, 0);
3047 ft_handle = NULL;
3048 return FALSE;
3051 static void init_font_list(void)
3053 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3054 static const WCHAR pathW[] = {'P','a','t','h',0};
3055 HKEY hkey;
3056 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3057 WCHAR windowsdir[MAX_PATH];
3058 char *unixname;
3059 const char *home;
3060 const char *data_dir;
3062 delete_external_font_keys();
3064 /* load the system bitmap fonts */
3065 load_system_fonts();
3067 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3068 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3069 strcatW(windowsdir, fontsW);
3070 if((unixname = wine_get_unix_file_name(windowsdir)))
3072 ReadFontDir(unixname, FALSE);
3073 HeapFree(GetProcessHeap(), 0, unixname);
3076 /* load the system truetype fonts */
3077 data_dir = wine_get_data_dir();
3078 if (!data_dir) data_dir = wine_get_build_dir();
3079 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3081 strcpy(unixname, data_dir);
3082 strcat(unixname, "/fonts/");
3083 ReadFontDir(unixname, TRUE);
3084 HeapFree(GetProcessHeap(), 0, unixname);
3087 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3088 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3089 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3090 will skip these. */
3091 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3092 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3093 &hkey) == ERROR_SUCCESS)
3095 LPWSTR data, valueW;
3096 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3097 &valuelen, &datalen, NULL, NULL);
3099 valuelen++; /* returned value doesn't include room for '\0' */
3100 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3101 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3102 if (valueW && data)
3104 dlen = datalen * sizeof(WCHAR);
3105 vlen = valuelen;
3106 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3107 &dlen) == ERROR_SUCCESS)
3109 if(data[0] && (data[1] == ':'))
3111 if((unixname = wine_get_unix_file_name(data)))
3113 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3114 HeapFree(GetProcessHeap(), 0, unixname);
3117 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3119 WCHAR pathW[MAX_PATH];
3120 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3121 BOOL added = FALSE;
3123 sprintfW(pathW, fmtW, windowsdir, data);
3124 if((unixname = wine_get_unix_file_name(pathW)))
3126 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3127 HeapFree(GetProcessHeap(), 0, unixname);
3129 if (!added)
3130 load_font_from_data_dir(data);
3132 /* reset dlen and vlen */
3133 dlen = datalen;
3134 vlen = valuelen;
3137 HeapFree(GetProcessHeap(), 0, data);
3138 HeapFree(GetProcessHeap(), 0, valueW);
3139 RegCloseKey(hkey);
3142 load_fontconfig_fonts();
3144 /* then look in any directories that we've specified in the config file */
3145 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3146 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3148 DWORD len;
3149 LPWSTR valueW;
3150 LPSTR valueA, ptr;
3152 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3154 len += sizeof(WCHAR);
3155 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3156 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3158 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3159 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3160 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3161 TRACE( "got font path %s\n", debugstr_a(valueA) );
3162 ptr = valueA;
3163 while (ptr)
3165 LPSTR next = strchr( ptr, ':' );
3166 if (next) *next++ = 0;
3167 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3168 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3170 strcpy( unixname, home );
3171 strcat( unixname, ptr + 1 );
3172 ReadFontDir( unixname, TRUE );
3173 HeapFree( GetProcessHeap(), 0, unixname );
3175 else
3176 ReadFontDir( ptr, TRUE );
3177 ptr = next;
3179 HeapFree( GetProcessHeap(), 0, valueA );
3181 HeapFree( GetProcessHeap(), 0, valueW );
3183 RegCloseKey(hkey);
3186 #ifdef __APPLE__
3187 /* Mac default font locations. */
3188 ReadFontDir( "/Library/Fonts", TRUE );
3189 ReadFontDir( "/Network/Library/Fonts", TRUE );
3190 ReadFontDir( "/System/Library/Fonts", TRUE );
3191 if ((home = getenv( "HOME" )))
3193 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3194 strcpy( unixname, home );
3195 strcat( unixname, "/Library/Fonts" );
3196 ReadFontDir( unixname, TRUE);
3197 HeapFree( GetProcessHeap(), 0, unixname );
3199 #endif
3202 static BOOL move_to_front(const WCHAR *name)
3204 Family *family, *cursor2;
3205 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3207 if(!strcmpiW(family->FamilyName, name))
3209 list_remove(&family->entry);
3210 list_add_head(&font_list, &family->entry);
3211 return TRUE;
3214 return FALSE;
3217 static BOOL set_default(const WCHAR **name_list)
3219 while (*name_list)
3221 if (move_to_front(*name_list)) return TRUE;
3222 name_list++;
3225 return FALSE;
3228 static void reorder_font_list(void)
3230 set_default( default_serif_list );
3231 set_default( default_fixed_list );
3232 set_default( default_sans_list );
3235 /*************************************************************
3236 * WineEngInit
3238 * Initialize FreeType library and create a list of available faces
3240 BOOL WineEngInit(void)
3242 HKEY hkey_font_cache;
3243 DWORD disposition;
3244 HANDLE font_mutex;
3246 /* update locale dependent font info in registry */
3247 update_font_info();
3249 if(!init_freetype()) return FALSE;
3251 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3253 ERR("Failed to create font mutex\n");
3254 return FALSE;
3256 WaitForSingleObject(font_mutex, INFINITE);
3258 create_font_cache_key(&hkey_font_cache, &disposition);
3260 if(disposition == REG_CREATED_NEW_KEY)
3261 init_font_list();
3262 else
3263 load_font_list_from_cache(hkey_font_cache);
3265 RegCloseKey(hkey_font_cache);
3267 reorder_font_list();
3269 DumpFontList();
3270 LoadSubstList();
3271 DumpSubstList();
3272 LoadReplaceList();
3274 if(disposition == REG_CREATED_NEW_KEY)
3275 update_reg_entries();
3277 init_system_links();
3279 ReleaseMutex(font_mutex);
3280 return TRUE;
3284 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3286 TT_OS2 *pOS2;
3287 TT_HoriHeader *pHori;
3289 LONG ppem;
3291 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3292 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3294 if(height == 0) height = 16;
3296 /* Calc. height of EM square:
3298 * For +ve lfHeight we have
3299 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3300 * Re-arranging gives:
3301 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3303 * For -ve lfHeight we have
3304 * |lfHeight| = ppem
3305 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3306 * with il = winAscent + winDescent - units_per_em]
3310 if(height > 0) {
3311 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3312 ppem = MulDiv(ft_face->units_per_EM, height,
3313 pHori->Ascender - pHori->Descender);
3314 else
3315 ppem = MulDiv(ft_face->units_per_EM, height,
3316 pOS2->usWinAscent + pOS2->usWinDescent);
3318 else
3319 ppem = -height;
3321 return ppem;
3324 static struct font_mapping *map_font_file( const char *name )
3326 struct font_mapping *mapping;
3327 struct stat st;
3328 int fd;
3330 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3331 if (fstat( fd, &st ) == -1) goto error;
3333 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3335 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3337 mapping->refcount++;
3338 close( fd );
3339 return mapping;
3342 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3343 goto error;
3345 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3346 close( fd );
3348 if (mapping->data == MAP_FAILED)
3350 HeapFree( GetProcessHeap(), 0, mapping );
3351 return NULL;
3353 mapping->refcount = 1;
3354 mapping->dev = st.st_dev;
3355 mapping->ino = st.st_ino;
3356 mapping->size = st.st_size;
3357 list_add_tail( &mappings_list, &mapping->entry );
3358 return mapping;
3360 error:
3361 close( fd );
3362 return NULL;
3365 static void unmap_font_file( struct font_mapping *mapping )
3367 if (!--mapping->refcount)
3369 list_remove( &mapping->entry );
3370 munmap( mapping->data, mapping->size );
3371 HeapFree( GetProcessHeap(), 0, mapping );
3375 static LONG load_VDMX(GdiFont*, LONG);
3377 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3379 FT_Error err;
3380 FT_Face ft_face;
3381 void *data_ptr;
3382 DWORD data_size;
3384 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3386 if (face->file)
3388 if (!(font->mapping = map_font_file( face->file )))
3390 WARN("failed to map %s\n", debugstr_a(face->file));
3391 return 0;
3393 data_ptr = font->mapping->data;
3394 data_size = font->mapping->size;
3396 else
3398 data_ptr = face->font_data_ptr;
3399 data_size = face->font_data_size;
3402 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3403 if(err) {
3404 ERR("FT_New_Face rets %d\n", err);
3405 return 0;
3408 /* set it here, as load_VDMX needs it */
3409 font->ft_face = ft_face;
3411 if(FT_IS_SCALABLE(ft_face)) {
3412 /* load the VDMX table if we have one */
3413 font->ppem = load_VDMX(font, height);
3414 if(font->ppem == 0)
3415 font->ppem = calc_ppem_for_height(ft_face, height);
3416 TRACE("height %d => ppem %d\n", height, font->ppem);
3418 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3419 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3420 } else {
3421 font->ppem = height;
3422 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3423 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3425 return ft_face;
3429 static int get_nearest_charset(Face *face, int *cp)
3431 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3432 a single face with the requested charset. The idea is to check if
3433 the selected font supports the current ANSI codepage, if it does
3434 return the corresponding charset, else return the first charset */
3436 CHARSETINFO csi;
3437 int acp = GetACP(), i;
3438 DWORD fs0;
3440 *cp = acp;
3441 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3442 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3443 return csi.ciCharset;
3445 for(i = 0; i < 32; i++) {
3446 fs0 = 1L << i;
3447 if(face->fs.fsCsb[0] & fs0) {
3448 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3449 *cp = csi.ciACP;
3450 return csi.ciCharset;
3452 else
3453 FIXME("TCI failing on %x\n", fs0);
3457 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3458 face->fs.fsCsb[0], face->file);
3459 *cp = acp;
3460 return DEFAULT_CHARSET;
3463 static GdiFont *alloc_font(void)
3465 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3466 ret->gmsize = 1;
3467 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3468 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3469 ret->potm = NULL;
3470 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3471 ret->total_kern_pairs = (DWORD)-1;
3472 ret->kern_pairs = NULL;
3473 list_init(&ret->hfontlist);
3474 list_init(&ret->child_fonts);
3475 return ret;
3478 static void free_font(GdiFont *font)
3480 struct list *cursor, *cursor2;
3481 DWORD i;
3483 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3485 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3486 list_remove(cursor);
3487 if(child->font)
3488 free_font(child->font);
3489 HeapFree(GetProcessHeap(), 0, child);
3492 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3494 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3495 DeleteObject(hfontlist->hfont);
3496 list_remove(&hfontlist->entry);
3497 HeapFree(GetProcessHeap(), 0, hfontlist);
3500 if (font->ft_face) pFT_Done_Face(font->ft_face);
3501 if (font->mapping) unmap_font_file( font->mapping );
3502 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3503 HeapFree(GetProcessHeap(), 0, font->potm);
3504 HeapFree(GetProcessHeap(), 0, font->name);
3505 for (i = 0; i < font->gmsize; i++)
3506 HeapFree(GetProcessHeap(),0,font->gm[i]);
3507 HeapFree(GetProcessHeap(), 0, font->gm);
3508 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3509 HeapFree(GetProcessHeap(), 0, font);
3513 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3515 FT_Face ft_face = font->ft_face;
3516 FT_ULong len;
3517 FT_Error err;
3519 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3521 if(!buf)
3522 len = 0;
3523 else
3524 len = cbData;
3526 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3528 /* make sure value of len is the value freetype says it needs */
3529 if (buf && len)
3531 FT_ULong needed = 0;
3532 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3533 if( !err && needed < len) len = needed;
3535 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3536 if (err)
3538 TRACE("Can't find table %c%c%c%c\n",
3539 /* bytes were reversed */
3540 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3541 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3542 return GDI_ERROR;
3544 return len;
3547 /*************************************************************
3548 * load_VDMX
3550 * load the vdmx entry for the specified height
3553 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3554 ( ( (FT_ULong)_x4 << 24 ) | \
3555 ( (FT_ULong)_x3 << 16 ) | \
3556 ( (FT_ULong)_x2 << 8 ) | \
3557 (FT_ULong)_x1 )
3559 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3561 typedef struct {
3562 BYTE bCharSet;
3563 BYTE xRatio;
3564 BYTE yStartRatio;
3565 BYTE yEndRatio;
3566 } Ratios;
3568 typedef struct {
3569 WORD recs;
3570 BYTE startsz;
3571 BYTE endsz;
3572 } VDMX_group;
3574 static LONG load_VDMX(GdiFont *font, LONG height)
3576 WORD hdr[3], tmp;
3577 VDMX_group group;
3578 BYTE devXRatio, devYRatio;
3579 USHORT numRecs, numRatios;
3580 DWORD result, offset = -1;
3581 LONG ppem = 0;
3582 int i;
3584 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3586 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3587 return ppem;
3589 /* FIXME: need the real device aspect ratio */
3590 devXRatio = 1;
3591 devYRatio = 1;
3593 numRecs = GET_BE_WORD(hdr[1]);
3594 numRatios = GET_BE_WORD(hdr[2]);
3596 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3597 for(i = 0; i < numRatios; i++) {
3598 Ratios ratio;
3600 offset = (3 * 2) + (i * sizeof(Ratios));
3601 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3602 offset = -1;
3604 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3606 if((ratio.xRatio == 0 &&
3607 ratio.yStartRatio == 0 &&
3608 ratio.yEndRatio == 0) ||
3609 (devXRatio == ratio.xRatio &&
3610 devYRatio >= ratio.yStartRatio &&
3611 devYRatio <= ratio.yEndRatio))
3613 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3614 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3615 offset = GET_BE_WORD(tmp);
3616 break;
3620 if(offset == -1) {
3621 FIXME("No suitable ratio found\n");
3622 return ppem;
3625 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3626 USHORT recs;
3627 BYTE startsz, endsz;
3628 WORD *vTable;
3630 recs = GET_BE_WORD(group.recs);
3631 startsz = group.startsz;
3632 endsz = group.endsz;
3634 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3636 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3637 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3638 if(result == GDI_ERROR) {
3639 FIXME("Failed to retrieve vTable\n");
3640 goto end;
3643 if(height > 0) {
3644 for(i = 0; i < recs; i++) {
3645 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3646 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3647 ppem = GET_BE_WORD(vTable[i * 3]);
3649 if(yMax + -yMin == height) {
3650 font->yMax = yMax;
3651 font->yMin = yMin;
3652 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3653 break;
3655 if(yMax + -yMin > height) {
3656 if(--i < 0) {
3657 ppem = 0;
3658 goto end; /* failed */
3660 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3661 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3662 ppem = GET_BE_WORD(vTable[i * 3]);
3663 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3664 break;
3667 if(!font->yMax) {
3668 ppem = 0;
3669 TRACE("ppem not found for height %d\n", height);
3672 end:
3673 HeapFree(GetProcessHeap(), 0, vTable);
3676 return ppem;
3679 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3681 if(font->font_desc.hash != fd->hash) return TRUE;
3682 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3683 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3684 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3685 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3688 static void calc_hash(FONT_DESC *pfd)
3690 DWORD hash = 0, *ptr, two_chars;
3691 WORD *pwc;
3692 unsigned int i;
3694 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3695 hash ^= *ptr;
3696 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3697 hash ^= *ptr;
3698 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3699 two_chars = *ptr;
3700 pwc = (WCHAR *)&two_chars;
3701 if(!*pwc) break;
3702 *pwc = toupperW(*pwc);
3703 pwc++;
3704 *pwc = toupperW(*pwc);
3705 hash ^= two_chars;
3706 if(!*pwc) break;
3708 hash ^= !pfd->can_use_bitmap;
3709 pfd->hash = hash;
3710 return;
3713 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3715 GdiFont *ret;
3716 FONT_DESC fd;
3717 HFONTLIST *hflist;
3718 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3720 fd.lf = *plf;
3721 fd.matrix = *pmat;
3722 fd.can_use_bitmap = can_use_bitmap;
3723 calc_hash(&fd);
3725 /* try the child list */
3726 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3727 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3728 if(!fontcmp(ret, &fd)) {
3729 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3730 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3731 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3732 if(hflist->hfont == hfont)
3733 return ret;
3738 /* try the in-use list */
3739 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3740 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3741 if(!fontcmp(ret, &fd)) {
3742 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3743 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3744 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3745 if(hflist->hfont == hfont)
3746 return ret;
3748 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3749 hflist->hfont = hfont;
3750 list_add_head(&ret->hfontlist, &hflist->entry);
3751 return ret;
3755 /* then the unused list */
3756 font_elem_ptr = list_head(&unused_gdi_font_list);
3757 while(font_elem_ptr) {
3758 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3759 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3760 if(!fontcmp(ret, &fd)) {
3761 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3762 assert(list_empty(&ret->hfontlist));
3763 TRACE("Found %p in unused list\n", ret);
3764 list_remove(&ret->entry);
3765 list_add_head(&gdi_font_list, &ret->entry);
3766 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3767 hflist->hfont = hfont;
3768 list_add_head(&ret->hfontlist, &hflist->entry);
3769 return ret;
3772 return NULL;
3775 static void add_to_cache(GdiFont *font)
3777 static DWORD cache_num = 1;
3779 font->cache_num = cache_num++;
3780 list_add_head(&gdi_font_list, &font->entry);
3783 /*************************************************************
3784 * create_child_font_list
3786 static BOOL create_child_font_list(GdiFont *font)
3788 BOOL ret = FALSE;
3789 SYSTEM_LINKS *font_link;
3790 CHILD_FONT *font_link_entry, *new_child;
3791 FontSubst *psub;
3792 WCHAR* font_name;
3794 psub = get_font_subst(&font_subst_list, font->name, -1);
3795 font_name = psub ? psub->to.name : font->name;
3796 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3798 if(!strcmpiW(font_link->font_name, font_name))
3800 TRACE("found entry in system list\n");
3801 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3803 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3804 new_child->face = font_link_entry->face;
3805 new_child->font = NULL;
3806 list_add_tail(&font->child_fonts, &new_child->entry);
3807 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3809 ret = TRUE;
3810 break;
3814 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3815 * Sans Serif. This is how asian windows get default fallbacks for fonts
3817 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3818 font->charset != OEM_CHARSET &&
3819 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3820 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3822 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3824 TRACE("found entry in default fallback list\n");
3825 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3827 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3828 new_child->face = font_link_entry->face;
3829 new_child->font = NULL;
3830 list_add_tail(&font->child_fonts, &new_child->entry);
3831 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3833 ret = TRUE;
3834 break;
3838 return ret;
3841 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3843 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3845 if (pFT_Set_Charmap)
3847 FT_Int i;
3848 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3850 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3852 for (i = 0; i < ft_face->num_charmaps; i++)
3854 if (ft_face->charmaps[i]->encoding == encoding)
3856 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3857 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3859 switch (ft_face->charmaps[i]->platform_id)
3861 default:
3862 cmap_def = ft_face->charmaps[i];
3863 break;
3864 case 0: /* Apple Unicode */
3865 cmap0 = ft_face->charmaps[i];
3866 break;
3867 case 1: /* Macintosh */
3868 cmap1 = ft_face->charmaps[i];
3869 break;
3870 case 2: /* ISO */
3871 cmap2 = ft_face->charmaps[i];
3872 break;
3873 case 3: /* Microsoft */
3874 cmap3 = ft_face->charmaps[i];
3875 break;
3879 if (cmap3) /* prefer Microsoft cmap table */
3880 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3881 else if (cmap1)
3882 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3883 else if (cmap2)
3884 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3885 else if (cmap0)
3886 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3887 else if (cmap_def)
3888 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3890 return ft_err == FT_Err_Ok;
3893 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3897 /*************************************************************
3898 * freetype_CreateDC
3900 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3901 LPCWSTR output, const DEVMODEW *devmode )
3903 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3905 if (!physdev) return FALSE;
3906 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3907 return TRUE;
3911 /*************************************************************
3912 * freetype_DeleteDC
3914 static BOOL freetype_DeleteDC( PHYSDEV dev )
3916 struct freetype_physdev *physdev = get_freetype_dev( dev );
3917 HeapFree( GetProcessHeap(), 0, physdev );
3918 return TRUE;
3922 /*************************************************************
3923 * freetype_SelectFont
3925 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3927 struct freetype_physdev *physdev = get_freetype_dev( dev );
3928 GdiFont *ret;
3929 Face *face, *best, *best_bitmap;
3930 Family *family, *last_resort_family;
3931 struct list *family_elem_ptr, *face_elem_ptr;
3932 INT height, width = 0;
3933 unsigned int score = 0, new_score;
3934 signed int diff = 0, newdiff;
3935 BOOL bd, it, can_use_bitmap, want_vertical;
3936 LOGFONTW lf;
3937 CHARSETINFO csi;
3938 HFONTLIST *hflist;
3939 FMAT2 dcmat;
3940 FontSubst *psub = NULL;
3941 DC *dc = get_dc_ptr( dev->hdc );
3943 if (!hfont) /* notification that the font has been changed by another driver */
3945 dc->gdiFont = NULL;
3946 physdev->font = NULL;
3947 release_dc_ptr( dc );
3948 return 0;
3951 GetObjectW( hfont, sizeof(lf), &lf );
3952 lf.lfWidth = abs(lf.lfWidth);
3954 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3956 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3957 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3958 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3959 lf.lfEscapement);
3961 if(dc->GraphicsMode == GM_ADVANCED)
3963 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3964 /* Try to avoid not necessary glyph transformations */
3965 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3967 lf.lfHeight *= fabs(dcmat.eM11);
3968 lf.lfWidth *= fabs(dcmat.eM11);
3969 dcmat.eM11 = dcmat.eM22 = 1.0;
3972 else
3974 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3975 font scaling abilities. */
3976 dcmat.eM11 = dcmat.eM22 = 1.0;
3977 dcmat.eM21 = dcmat.eM12 = 0;
3978 if (dc->vport2WorldValid)
3980 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
3981 lf.lfOrientation = -lf.lfOrientation;
3982 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
3983 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
3987 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3988 dcmat.eM21, dcmat.eM22);
3990 GDI_CheckNotLock();
3991 EnterCriticalSection( &freetype_cs );
3993 /* check the cache first */
3994 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3995 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3996 goto done;
3999 if(list_empty(&font_list)) /* No fonts installed */
4001 TRACE("No fonts installed\n");
4002 goto done;
4005 TRACE("not in cache\n");
4006 ret = alloc_font();
4008 ret->font_desc.matrix = dcmat;
4009 ret->font_desc.lf = lf;
4010 ret->font_desc.can_use_bitmap = can_use_bitmap;
4011 calc_hash(&ret->font_desc);
4012 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4013 hflist->hfont = hfont;
4014 list_add_head(&ret->hfontlist, &hflist->entry);
4016 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4017 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4018 original value lfCharSet. Note this is a special case for
4019 Symbol and doesn't happen at least for "Wingdings*" */
4021 if(!strcmpiW(lf.lfFaceName, SymbolW))
4022 lf.lfCharSet = SYMBOL_CHARSET;
4024 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4025 switch(lf.lfCharSet) {
4026 case DEFAULT_CHARSET:
4027 csi.fs.fsCsb[0] = 0;
4028 break;
4029 default:
4030 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4031 csi.fs.fsCsb[0] = 0;
4032 break;
4036 family = NULL;
4037 if(lf.lfFaceName[0] != '\0') {
4038 SYSTEM_LINKS *font_link;
4039 CHILD_FONT *font_link_entry;
4040 LPWSTR FaceName = lf.lfFaceName;
4042 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4044 if(psub) {
4045 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4046 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4047 if (psub->to.charset != -1)
4048 lf.lfCharSet = psub->to.charset;
4051 /* We want a match on name and charset or just name if
4052 charset was DEFAULT_CHARSET. If the latter then
4053 we fixup the returned charset later in get_nearest_charset
4054 where we'll either use the charset of the current ansi codepage
4055 or if that's unavailable the first charset that the font supports.
4057 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4058 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4059 if (!strcmpiW(family->FamilyName, FaceName) ||
4060 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4062 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4063 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4064 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4065 if(face->scalable || can_use_bitmap)
4066 goto found;
4071 /* Search by full face name. */
4072 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4073 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4074 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4075 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4076 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4077 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
4079 if(face->scalable || can_use_bitmap)
4080 goto found_face;
4086 * Try check the SystemLink list first for a replacement font.
4087 * We may find good replacements there.
4089 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4091 if(!strcmpiW(font_link->font_name, FaceName) ||
4092 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4094 TRACE("found entry in system list\n");
4095 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4097 face = font_link_entry->face;
4098 family = face->family;
4099 if(csi.fs.fsCsb[0] &
4100 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4102 if(face->scalable || can_use_bitmap)
4103 goto found;
4110 psub = NULL; /* substitution is no more relevant */
4112 /* If requested charset was DEFAULT_CHARSET then try using charset
4113 corresponding to the current ansi codepage */
4114 if (!csi.fs.fsCsb[0])
4116 INT acp = GetACP();
4117 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4118 FIXME("TCI failed on codepage %d\n", acp);
4119 csi.fs.fsCsb[0] = 0;
4120 } else
4121 lf.lfCharSet = csi.ciCharset;
4124 want_vertical = (lf.lfFaceName[0] == '@');
4126 /* Face families are in the top 4 bits of lfPitchAndFamily,
4127 so mask with 0xF0 before testing */
4129 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4130 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4131 strcpyW(lf.lfFaceName, defFixed);
4132 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4133 strcpyW(lf.lfFaceName, defSerif);
4134 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4135 strcpyW(lf.lfFaceName, defSans);
4136 else
4137 strcpyW(lf.lfFaceName, defSans);
4138 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4139 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4140 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4141 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4142 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4143 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4144 if(face->scalable || can_use_bitmap)
4145 goto found;
4150 last_resort_family = NULL;
4151 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4152 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4153 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4154 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4155 if(face->vertical == want_vertical &&
4156 (csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))) {
4157 if(face->scalable)
4158 goto found;
4159 if(can_use_bitmap && !last_resort_family)
4160 last_resort_family = family;
4165 if(last_resort_family) {
4166 family = last_resort_family;
4167 csi.fs.fsCsb[0] = 0;
4168 goto found;
4171 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4172 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4173 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4174 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4175 if(face->scalable && face->vertical == want_vertical) {
4176 csi.fs.fsCsb[0] = 0;
4177 WARN("just using first face for now\n");
4178 goto found;
4180 if(can_use_bitmap && !last_resort_family)
4181 last_resort_family = family;
4184 if(!last_resort_family) {
4185 FIXME("can't find a single appropriate font - bailing\n");
4186 free_font(ret);
4187 ret = NULL;
4188 goto done;
4191 WARN("could only find a bitmap font - this will probably look awful!\n");
4192 family = last_resort_family;
4193 csi.fs.fsCsb[0] = 0;
4195 found:
4196 it = lf.lfItalic ? 1 : 0;
4197 bd = lf.lfWeight > 550 ? 1 : 0;
4199 height = lf.lfHeight;
4201 face = best = best_bitmap = NULL;
4202 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4204 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4206 BOOL italic, bold;
4208 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4209 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4210 new_score = (italic ^ it) + (bold ^ bd);
4211 if(!best || new_score <= score)
4213 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4214 italic, bold, it, bd);
4215 score = new_score;
4216 best = face;
4217 if(best->scalable && score == 0) break;
4218 if(!best->scalable)
4220 if(height > 0)
4221 newdiff = height - (signed int)(best->size.height);
4222 else
4223 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4224 if(!best_bitmap || new_score < score ||
4225 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4227 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4228 diff = newdiff;
4229 best_bitmap = best;
4230 if(score == 0 && diff == 0) break;
4236 if(best)
4237 face = best->scalable ? best : best_bitmap;
4238 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4239 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4241 found_face:
4242 height = lf.lfHeight;
4244 ret->fs = face->fs;
4246 if(csi.fs.fsCsb[0]) {
4247 ret->charset = lf.lfCharSet;
4248 ret->codepage = csi.ciACP;
4250 else
4251 ret->charset = get_nearest_charset(face, &ret->codepage);
4253 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4254 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4256 ret->aveWidth = height ? lf.lfWidth : 0;
4258 if(!face->scalable) {
4259 /* Windows uses integer scaling factors for bitmap fonts */
4260 INT scale, scaled_height;
4261 GdiFont *cachedfont;
4263 /* FIXME: rotation of bitmap fonts is ignored */
4264 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4265 if (ret->aveWidth)
4266 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4267 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4268 dcmat.eM11 = dcmat.eM22 = 1.0;
4269 /* As we changed the matrix, we need to search the cache for the font again,
4270 * otherwise we might explode the cache. */
4271 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4272 TRACE("Found cached font after non-scalable matrix rescale!\n");
4273 free_font( ret );
4274 ret = cachedfont;
4275 goto done;
4277 calc_hash(&ret->font_desc);
4279 if (height != 0) height = diff;
4280 height += face->size.height;
4282 scale = (height + face->size.height - 1) / face->size.height;
4283 scaled_height = scale * face->size.height;
4284 /* Only jump to the next height if the difference <= 25% original height */
4285 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4286 /* The jump between unscaled and doubled is delayed by 1 */
4287 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4288 ret->scale_y = scale;
4290 width = face->size.x_ppem >> 6;
4291 height = face->size.y_ppem >> 6;
4293 else
4294 ret->scale_y = 1.0;
4295 TRACE("font scale y: %f\n", ret->scale_y);
4297 ret->ft_face = OpenFontFace(ret, face, width, height);
4299 if (!ret->ft_face)
4301 free_font( ret );
4302 ret = NULL;
4303 goto done;
4306 ret->ntmFlags = face->ntmFlags;
4308 if (ret->charset == SYMBOL_CHARSET &&
4309 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4310 /* No ops */
4312 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4313 /* No ops */
4315 else {
4316 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4319 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4320 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4321 ret->underline = lf.lfUnderline ? 0xff : 0;
4322 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4323 create_child_font_list(ret);
4325 if (face->vertical) /* We need to try to load the GSUB table */
4327 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4328 if (length != GDI_ERROR)
4330 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4331 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4332 TRACE("Loaded GSUB table of %i bytes\n",length);
4336 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4338 add_to_cache(ret);
4339 done:
4340 if (ret)
4342 dc->gdiFont = ret;
4343 physdev->font = ret;
4345 LeaveCriticalSection( &freetype_cs );
4346 release_dc_ptr( dc );
4347 return ret ? hfont : 0;
4350 static void dump_gdi_font_list(void)
4352 GdiFont *gdiFont;
4353 struct list *elem_ptr;
4355 TRACE("---------- gdiFont Cache ----------\n");
4356 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4357 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4358 TRACE("gdiFont=%p %s %d\n",
4359 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4362 TRACE("---------- Unused gdiFont Cache ----------\n");
4363 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4364 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4365 TRACE("gdiFont=%p %s %d\n",
4366 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4369 TRACE("---------- Child gdiFont Cache ----------\n");
4370 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4371 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4372 TRACE("gdiFont=%p %s %d\n",
4373 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4377 /*************************************************************
4378 * WineEngDestroyFontInstance
4380 * free the gdiFont associated with this handle
4383 BOOL WineEngDestroyFontInstance(HFONT handle)
4385 GdiFont *gdiFont;
4386 HFONTLIST *hflist;
4387 BOOL ret = FALSE;
4388 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4389 int i = 0;
4391 GDI_CheckNotLock();
4392 EnterCriticalSection( &freetype_cs );
4394 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4396 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4397 while(hfontlist_elem_ptr) {
4398 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4399 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4400 if(hflist->hfont == handle) {
4401 TRACE("removing child font %p from child list\n", gdiFont);
4402 list_remove(&gdiFont->entry);
4403 LeaveCriticalSection( &freetype_cs );
4404 return TRUE;
4409 TRACE("destroying hfont=%p\n", handle);
4410 if(TRACE_ON(font))
4411 dump_gdi_font_list();
4413 font_elem_ptr = list_head(&gdi_font_list);
4414 while(font_elem_ptr) {
4415 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4416 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4418 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4419 while(hfontlist_elem_ptr) {
4420 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4421 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4422 if(hflist->hfont == handle) {
4423 list_remove(&hflist->entry);
4424 HeapFree(GetProcessHeap(), 0, hflist);
4425 ret = TRUE;
4428 if(list_empty(&gdiFont->hfontlist)) {
4429 TRACE("Moving to Unused list\n");
4430 list_remove(&gdiFont->entry);
4431 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4436 font_elem_ptr = list_head(&unused_gdi_font_list);
4437 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4438 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4439 while(font_elem_ptr) {
4440 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4441 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4442 TRACE("freeing %p\n", gdiFont);
4443 list_remove(&gdiFont->entry);
4444 free_font(gdiFont);
4446 LeaveCriticalSection( &freetype_cs );
4447 return ret;
4450 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4452 HRSRC rsrc;
4453 HGLOBAL hMem;
4454 WCHAR *p;
4455 int i;
4457 id += IDS_FIRST_SCRIPT;
4458 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4459 if (!rsrc) return 0;
4460 hMem = LoadResource( gdi32_module, rsrc );
4461 if (!hMem) return 0;
4463 p = LockResource( hMem );
4464 id &= 0x000f;
4465 while (id--) p += *p + 1;
4467 i = min(LF_FACESIZE - 1, *p);
4468 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4469 buffer[i] = 0;
4470 return i;
4474 /***************************************************
4475 * create_enum_charset_list
4477 * This function creates charset enumeration list because in DEFAULT_CHARSET
4478 * case, the ANSI codepage's charset takes precedence over other charsets.
4479 * This function works as a filter other than DEFAULT_CHARSET case.
4481 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4483 CHARSETINFO csi;
4484 DWORD n = 0;
4486 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4487 csi.fs.fsCsb[0] != 0) {
4488 list->element[n].mask = csi.fs.fsCsb[0];
4489 list->element[n].charset = csi.ciCharset;
4490 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4491 n++;
4493 else { /* charset is DEFAULT_CHARSET or invalid. */
4494 INT acp, i;
4496 /* Set the current codepage's charset as the first element. */
4497 acp = GetACP();
4498 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4499 csi.fs.fsCsb[0] != 0) {
4500 list->element[n].mask = csi.fs.fsCsb[0];
4501 list->element[n].charset = csi.ciCharset;
4502 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4503 n++;
4506 /* Fill out left elements. */
4507 for (i = 0; i < 32; i++) {
4508 FONTSIGNATURE fs;
4509 fs.fsCsb[0] = 1L << i;
4510 fs.fsCsb[1] = 0;
4511 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4512 continue; /* skip, already added. */
4513 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4514 continue; /* skip, this is an invalid fsCsb bit. */
4516 list->element[n].mask = fs.fsCsb[0];
4517 list->element[n].charset = csi.ciCharset;
4518 load_script_name( i, list->element[n].name );
4519 n++;
4522 list->total = n;
4524 return n;
4527 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4528 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4530 GdiFont *font;
4531 LONG width, height;
4533 if (face->cached_enum_data)
4535 TRACE("Cached\n");
4536 *pelf = face->cached_enum_data->elf;
4537 *pntm = face->cached_enum_data->ntm;
4538 *ptype = face->cached_enum_data->type;
4539 return;
4542 font = alloc_font();
4544 if(face->scalable) {
4545 height = -2048; /* 2048 is the most common em size */
4546 width = 0;
4547 } else {
4548 height = face->size.y_ppem >> 6;
4549 width = face->size.x_ppem >> 6;
4551 font->scale_y = 1.0;
4553 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4555 free_font(font);
4556 return;
4559 font->name = strdupW(face->family->FamilyName);
4560 font->ntmFlags = face->ntmFlags;
4562 if (get_outline_text_metrics(font))
4564 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4566 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4568 lstrcpynW(pelf->elfLogFont.lfFaceName,
4569 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4570 LF_FACESIZE);
4571 lstrcpynW(pelf->elfFullName,
4572 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4573 LF_FULLFACESIZE);
4574 lstrcpynW(pelf->elfStyle,
4575 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4576 LF_FACESIZE);
4578 else
4580 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4582 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4584 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4585 if (face->FullName)
4586 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4587 else
4588 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4589 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4592 pntm->ntmTm.ntmFlags = face->ntmFlags;
4593 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4594 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4595 pntm->ntmFontSig = face->fs;
4597 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4599 pelf->elfLogFont.lfEscapement = 0;
4600 pelf->elfLogFont.lfOrientation = 0;
4601 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4602 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4603 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4604 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4605 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4606 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4607 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4608 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4609 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4610 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4611 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4613 *ptype = 0;
4614 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4615 *ptype |= TRUETYPE_FONTTYPE;
4616 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4617 *ptype |= DEVICE_FONTTYPE;
4618 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4619 *ptype |= RASTER_FONTTYPE;
4621 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4622 if (face->cached_enum_data)
4624 face->cached_enum_data->elf = *pelf;
4625 face->cached_enum_data->ntm = *pntm;
4626 face->cached_enum_data->type = *ptype;
4629 free_font(font);
4632 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4634 struct list *face_elem_ptr;
4636 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4638 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4640 static const WCHAR spaceW[] = { ' ',0 };
4641 WCHAR full_family_name[LF_FULLFACESIZE];
4642 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4644 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4646 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4647 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4648 continue;
4651 strcpyW(full_family_name, family->FamilyName);
4652 strcatW(full_family_name, spaceW);
4653 strcatW(full_family_name, face->StyleName);
4654 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4657 return FALSE;
4660 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4662 static const WCHAR spaceW[] = { ' ',0 };
4663 WCHAR full_family_name[LF_FULLFACESIZE];
4665 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4667 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4669 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4670 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4671 return FALSE;
4674 strcpyW(full_family_name, face->family->FamilyName);
4675 strcatW(full_family_name, spaceW);
4676 strcatW(full_family_name, face->StyleName);
4677 return !strcmpiW(lf->lfFaceName, full_family_name);
4680 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4681 FONTENUMPROCW proc, LPARAM lparam)
4683 ENUMLOGFONTEXW elf;
4684 NEWTEXTMETRICEXW ntm;
4685 DWORD type = 0;
4686 int i;
4688 GetEnumStructs(face, &elf, &ntm, &type);
4689 for(i = 0; i < list->total; i++) {
4690 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4691 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4692 load_script_name( IDS_OEM_DOS, elf.elfScript );
4693 i = list->total; /* break out of loop after enumeration */
4694 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4695 continue;
4696 else {
4697 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4698 strcpyW(elf.elfScript, list->element[i].name);
4699 if (!elf.elfScript[0])
4700 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4702 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4703 debugstr_w(elf.elfLogFont.lfFaceName),
4704 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4705 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4706 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4707 ntm.ntmTm.ntmFlags);
4708 /* release section before callback (FIXME) */
4709 LeaveCriticalSection( &freetype_cs );
4710 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4711 EnterCriticalSection( &freetype_cs );
4713 return TRUE;
4716 /*************************************************************
4717 * freetype_EnumFonts
4719 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4721 Family *family;
4722 Face *face;
4723 struct list *family_elem_ptr, *face_elem_ptr;
4724 LOGFONTW lf;
4725 struct enum_charset_list enum_charsets;
4727 if (!plf)
4729 lf.lfCharSet = DEFAULT_CHARSET;
4730 lf.lfPitchAndFamily = 0;
4731 lf.lfFaceName[0] = 0;
4732 plf = &lf;
4735 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4737 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4739 GDI_CheckNotLock();
4740 EnterCriticalSection( &freetype_cs );
4741 if(plf->lfFaceName[0]) {
4742 FontSubst *psub;
4743 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4745 if(psub) {
4746 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4747 debugstr_w(psub->to.name));
4748 lf = *plf;
4749 strcpyW(lf.lfFaceName, psub->to.name);
4750 plf = &lf;
4753 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4754 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4755 if(family_matches(family, plf)) {
4756 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4757 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4758 if (!face_matches(face, plf)) continue;
4759 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4763 } else {
4764 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4765 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4766 face_elem_ptr = list_head(&family->faces);
4767 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4768 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4771 LeaveCriticalSection( &freetype_cs );
4772 return TRUE;
4775 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4777 pt->x.value = vec->x >> 6;
4778 pt->x.fract = (vec->x & 0x3f) << 10;
4779 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4780 pt->y.value = vec->y >> 6;
4781 pt->y.fract = (vec->y & 0x3f) << 10;
4782 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4783 return;
4786 /***************************************************
4787 * According to the MSDN documentation on WideCharToMultiByte,
4788 * certain codepages cannot set the default_used parameter.
4789 * This returns TRUE if the codepage can set that parameter, false else
4790 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4792 static BOOL codepage_sets_default_used(UINT codepage)
4794 switch (codepage)
4796 case CP_UTF7:
4797 case CP_UTF8:
4798 case CP_SYMBOL:
4799 return FALSE;
4800 default:
4801 return TRUE;
4806 * GSUB Table handling functions
4809 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4811 const GSUB_CoverageFormat1* cf1;
4813 cf1 = table;
4815 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4817 int count = GET_BE_WORD(cf1->GlyphCount);
4818 int i;
4819 TRACE("Coverage Format 1, %i glyphs\n",count);
4820 for (i = 0; i < count; i++)
4821 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4822 return i;
4823 return -1;
4825 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4827 const GSUB_CoverageFormat2* cf2;
4828 int i;
4829 int count;
4830 cf2 = (const GSUB_CoverageFormat2*)cf1;
4832 count = GET_BE_WORD(cf2->RangeCount);
4833 TRACE("Coverage Format 2, %i ranges\n",count);
4834 for (i = 0; i < count; i++)
4836 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4837 return -1;
4838 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4839 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4841 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4842 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4845 return -1;
4847 else
4848 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4850 return -1;
4853 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4855 const GSUB_ScriptList *script;
4856 const GSUB_Script *deflt = NULL;
4857 int i;
4858 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4860 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4861 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4863 const GSUB_Script *scr;
4864 int offset;
4866 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4867 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4869 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4870 return scr;
4871 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4872 deflt = scr;
4874 return deflt;
4877 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4879 int i;
4880 int offset;
4881 const GSUB_LangSys *Lang;
4883 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4885 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4887 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4888 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4890 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4891 return Lang;
4893 offset = GET_BE_WORD(script->DefaultLangSys);
4894 if (offset)
4896 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4897 return Lang;
4899 return NULL;
4902 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4904 int i;
4905 const GSUB_FeatureList *feature;
4906 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4908 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4909 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4911 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4912 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4914 const GSUB_Feature *feat;
4915 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4916 return feat;
4919 return NULL;
4922 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4924 int i;
4925 int offset;
4926 const GSUB_LookupList *lookup;
4927 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4929 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4930 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4932 const GSUB_LookupTable *look;
4933 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4934 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4935 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4936 if (GET_BE_WORD(look->LookupType) != 1)
4937 FIXME("We only handle SubType 1\n");
4938 else
4940 int j;
4942 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4944 const GSUB_SingleSubstFormat1 *ssf1;
4945 offset = GET_BE_WORD(look->SubTable[j]);
4946 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4947 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4949 int offset = GET_BE_WORD(ssf1->Coverage);
4950 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4951 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4953 TRACE(" Glyph 0x%x ->",glyph);
4954 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4955 TRACE(" 0x%x\n",glyph);
4958 else
4960 const GSUB_SingleSubstFormat2 *ssf2;
4961 INT index;
4962 INT offset;
4964 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4965 offset = GET_BE_WORD(ssf1->Coverage);
4966 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4967 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4968 TRACE(" Coverage index %i\n",index);
4969 if (index != -1)
4971 TRACE(" Glyph is 0x%x ->",glyph);
4972 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4973 TRACE("0x%x\n",glyph);
4979 return glyph;
4982 static const char* get_opentype_script(const GdiFont *font)
4985 * I am not sure if this is the correct way to generate our script tag
4988 switch (font->charset)
4990 case ANSI_CHARSET: return "latn";
4991 case BALTIC_CHARSET: return "latn"; /* ?? */
4992 case CHINESEBIG5_CHARSET: return "hani";
4993 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4994 case GB2312_CHARSET: return "hani";
4995 case GREEK_CHARSET: return "grek";
4996 case HANGUL_CHARSET: return "hang";
4997 case RUSSIAN_CHARSET: return "cyrl";
4998 case SHIFTJIS_CHARSET: return "kana";
4999 case TURKISH_CHARSET: return "latn"; /* ?? */
5000 case VIETNAMESE_CHARSET: return "latn";
5001 case JOHAB_CHARSET: return "latn"; /* ?? */
5002 case ARABIC_CHARSET: return "arab";
5003 case HEBREW_CHARSET: return "hebr";
5004 case THAI_CHARSET: return "thai";
5005 default: return "latn";
5009 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5011 const GSUB_Header *header;
5012 const GSUB_Script *script;
5013 const GSUB_LangSys *language;
5014 const GSUB_Feature *feature;
5016 if (!font->GSUB_Table)
5017 return glyph;
5019 header = font->GSUB_Table;
5021 script = GSUB_get_script_table(header, get_opentype_script(font));
5022 if (!script)
5024 TRACE("Script not found\n");
5025 return glyph;
5027 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5028 if (!language)
5030 TRACE("Language not found\n");
5031 return glyph;
5033 feature = GSUB_get_feature(header, language, "vrt2");
5034 if (!feature)
5035 feature = GSUB_get_feature(header, language, "vert");
5036 if (!feature)
5038 TRACE("vrt2/vert feature not found\n");
5039 return glyph;
5041 return GSUB_apply_feature(header, feature, glyph);
5044 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5046 FT_UInt glyphId;
5048 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5049 WCHAR wc = (WCHAR)glyph;
5050 BOOL default_used;
5051 BOOL *default_used_pointer;
5052 FT_UInt ret;
5053 char buf;
5054 default_used_pointer = NULL;
5055 default_used = FALSE;
5056 if (codepage_sets_default_used(font->codepage))
5057 default_used_pointer = &default_used;
5058 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5059 ret = 0;
5060 else
5061 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5062 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5063 return ret;
5066 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5068 if (glyph < 0x100) glyph += 0xf000;
5069 /* there is a number of old pre-Unicode "broken" TTFs, which
5070 do have symbols at U+00XX instead of U+f0XX */
5071 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5072 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5074 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5076 return glyphId;
5079 /*************************************************************
5080 * freetype_GetGlyphIndices
5082 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5084 struct freetype_physdev *physdev = get_freetype_dev( dev );
5085 int i;
5086 WORD default_char;
5087 BOOL got_default = FALSE;
5089 if (!physdev->font)
5091 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5092 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5095 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5097 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5098 got_default = TRUE;
5101 GDI_CheckNotLock();
5102 EnterCriticalSection( &freetype_cs );
5104 for(i = 0; i < count; i++)
5106 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5107 if (pgi[i] == 0)
5109 if (!got_default)
5111 if (FT_IS_SFNT(physdev->font->ft_face))
5113 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5114 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5116 else
5118 TEXTMETRICW textm;
5119 get_text_metrics(physdev->font, &textm);
5120 default_char = textm.tmDefaultChar;
5122 got_default = TRUE;
5124 pgi[i] = default_char;
5127 LeaveCriticalSection( &freetype_cs );
5128 return count;
5131 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5133 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5134 return !memcmp(matrix, &identity, sizeof(FMAT2));
5137 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5139 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5140 return !memcmp(matrix, &identity, sizeof(MAT2));
5143 static inline BYTE get_max_level( UINT format )
5145 switch( format )
5147 case GGO_GRAY2_BITMAP: return 4;
5148 case GGO_GRAY4_BITMAP: return 16;
5149 case GGO_GRAY8_BITMAP: return 64;
5151 return 255;
5154 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5156 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5157 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5158 const MAT2* lpmat)
5160 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5161 FT_Face ft_face = incoming_font->ft_face;
5162 GdiFont *font = incoming_font;
5163 FT_UInt glyph_index;
5164 DWORD width, height, pitch, needed = 0;
5165 FT_Bitmap ft_bitmap;
5166 FT_Error err;
5167 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5168 FT_Angle angle = 0;
5169 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5170 double widthRatio = 1.0;
5171 FT_Matrix transMat = identityMat;
5172 FT_Matrix transMatUnrotated;
5173 BOOL needsTransform = FALSE;
5174 BOOL tategaki = (font->GSUB_Table != NULL);
5175 UINT original_index;
5177 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5178 buflen, buf, lpmat);
5180 TRACE("font transform %f %f %f %f\n",
5181 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5182 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5184 if(format & GGO_GLYPH_INDEX) {
5185 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5186 original_index = glyph;
5187 format &= ~GGO_GLYPH_INDEX;
5188 } else {
5189 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5190 ft_face = font->ft_face;
5191 original_index = glyph_index;
5194 if(format & GGO_UNHINTED) {
5195 load_flags |= FT_LOAD_NO_HINTING;
5196 format &= ~GGO_UNHINTED;
5199 /* tategaki never appears to happen to lower glyph index */
5200 if (glyph_index < TATEGAKI_LOWER_BOUND )
5201 tategaki = FALSE;
5203 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5204 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5205 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5206 font->gmsize * sizeof(GM*));
5207 } else {
5208 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5209 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5211 *lpgm = FONT_GM(font,original_index)->gm;
5212 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5213 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5214 lpgm->gmCellIncX, lpgm->gmCellIncY);
5215 return 1; /* FIXME */
5219 if (!font->gm[original_index / GM_BLOCK_SIZE])
5220 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5222 /* Scaling factor */
5223 if (font->aveWidth)
5225 TEXTMETRICW tm;
5227 get_text_metrics(font, &tm);
5229 widthRatio = (double)font->aveWidth;
5230 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5232 else
5233 widthRatio = font->scale_y;
5235 /* Scaling transform */
5236 if (widthRatio != 1.0 || font->scale_y != 1.0)
5238 FT_Matrix scaleMat;
5239 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5240 scaleMat.xy = 0;
5241 scaleMat.yx = 0;
5242 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5244 pFT_Matrix_Multiply(&scaleMat, &transMat);
5245 needsTransform = TRUE;
5248 /* Slant transform */
5249 if (font->fake_italic) {
5250 FT_Matrix slantMat;
5252 slantMat.xx = (1 << 16);
5253 slantMat.xy = ((1 << 16) >> 2);
5254 slantMat.yx = 0;
5255 slantMat.yy = (1 << 16);
5256 pFT_Matrix_Multiply(&slantMat, &transMat);
5257 needsTransform = TRUE;
5260 /* Rotation transform */
5261 transMatUnrotated = transMat;
5262 if(font->orientation && !tategaki) {
5263 FT_Matrix rotationMat;
5264 FT_Vector vecAngle;
5265 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5266 pFT_Vector_Unit(&vecAngle, angle);
5267 rotationMat.xx = vecAngle.x;
5268 rotationMat.xy = -vecAngle.y;
5269 rotationMat.yx = -rotationMat.xy;
5270 rotationMat.yy = rotationMat.xx;
5272 pFT_Matrix_Multiply(&rotationMat, &transMat);
5273 needsTransform = TRUE;
5276 /* World transform */
5277 if (!is_identity_FMAT2(&font->font_desc.matrix))
5279 FT_Matrix worldMat;
5280 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5281 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5282 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5283 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5284 pFT_Matrix_Multiply(&worldMat, &transMat);
5285 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5286 needsTransform = TRUE;
5289 /* Extra transformation specified by caller */
5290 if (!is_identity_MAT2(lpmat))
5292 FT_Matrix extraMat;
5293 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5294 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5295 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5296 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5297 pFT_Matrix_Multiply(&extraMat, &transMat);
5298 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5299 needsTransform = TRUE;
5302 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5303 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5304 format == GGO_GRAY8_BITMAP))
5306 load_flags |= FT_LOAD_NO_BITMAP;
5309 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5311 if(err) {
5312 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5313 return GDI_ERROR;
5316 if(!needsTransform) {
5317 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5318 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5319 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5321 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5322 bottom = (ft_face->glyph->metrics.horiBearingY -
5323 ft_face->glyph->metrics.height) & -64;
5324 lpgm->gmCellIncX = adv;
5325 lpgm->gmCellIncY = 0;
5326 } else {
5327 INT xc, yc;
5328 FT_Vector vec;
5330 left = right = 0;
5332 for(xc = 0; xc < 2; xc++) {
5333 for(yc = 0; yc < 2; yc++) {
5334 vec.x = (ft_face->glyph->metrics.horiBearingX +
5335 xc * ft_face->glyph->metrics.width);
5336 vec.y = ft_face->glyph->metrics.horiBearingY -
5337 yc * ft_face->glyph->metrics.height;
5338 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5339 pFT_Vector_Transform(&vec, &transMat);
5340 if(xc == 0 && yc == 0) {
5341 left = right = vec.x;
5342 top = bottom = vec.y;
5343 } else {
5344 if(vec.x < left) left = vec.x;
5345 else if(vec.x > right) right = vec.x;
5346 if(vec.y < bottom) bottom = vec.y;
5347 else if(vec.y > top) top = vec.y;
5351 left = left & -64;
5352 right = (right + 63) & -64;
5353 bottom = bottom & -64;
5354 top = (top + 63) & -64;
5356 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5357 vec.x = ft_face->glyph->metrics.horiAdvance;
5358 vec.y = 0;
5359 pFT_Vector_Transform(&vec, &transMat);
5360 lpgm->gmCellIncX = (vec.x+63) >> 6;
5361 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5363 vec.x = ft_face->glyph->metrics.horiAdvance;
5364 vec.y = 0;
5365 pFT_Vector_Transform(&vec, &transMatUnrotated);
5366 adv = (vec.x+63) >> 6;
5369 lsb = left >> 6;
5370 bbx = (right - left) >> 6;
5371 lpgm->gmBlackBoxX = (right - left) >> 6;
5372 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5373 lpgm->gmptGlyphOrigin.x = left >> 6;
5374 lpgm->gmptGlyphOrigin.y = top >> 6;
5376 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5377 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5378 lpgm->gmCellIncX, lpgm->gmCellIncY);
5380 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5381 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5383 FONT_GM(font,original_index)->gm = *lpgm;
5384 FONT_GM(font,original_index)->adv = adv;
5385 FONT_GM(font,original_index)->lsb = lsb;
5386 FONT_GM(font,original_index)->bbx = bbx;
5387 FONT_GM(font,original_index)->init = TRUE;
5390 if(format == GGO_METRICS)
5392 return 1; /* FIXME */
5395 if(ft_face->glyph->format != ft_glyph_format_outline &&
5396 (format == GGO_NATIVE || format == GGO_BEZIER))
5398 TRACE("loaded a bitmap\n");
5399 return GDI_ERROR;
5402 switch(format) {
5403 case GGO_BITMAP:
5404 width = lpgm->gmBlackBoxX;
5405 height = lpgm->gmBlackBoxY;
5406 pitch = ((width + 31) >> 5) << 2;
5407 needed = pitch * height;
5409 if(!buf || !buflen) break;
5411 switch(ft_face->glyph->format) {
5412 case ft_glyph_format_bitmap:
5414 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5415 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5416 INT h = ft_face->glyph->bitmap.rows;
5417 while(h--) {
5418 memcpy(dst, src, w);
5419 src += ft_face->glyph->bitmap.pitch;
5420 dst += pitch;
5422 break;
5425 case ft_glyph_format_outline:
5426 ft_bitmap.width = width;
5427 ft_bitmap.rows = height;
5428 ft_bitmap.pitch = pitch;
5429 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5430 ft_bitmap.buffer = buf;
5432 if(needsTransform)
5433 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5435 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5437 /* Note: FreeType will only set 'black' bits for us. */
5438 memset(buf, 0, needed);
5439 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5440 break;
5442 default:
5443 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5444 return GDI_ERROR;
5446 break;
5448 case GGO_GRAY2_BITMAP:
5449 case GGO_GRAY4_BITMAP:
5450 case GGO_GRAY8_BITMAP:
5451 case WINE_GGO_GRAY16_BITMAP:
5453 unsigned int max_level, row, col;
5454 BYTE *start, *ptr;
5456 width = lpgm->gmBlackBoxX;
5457 height = lpgm->gmBlackBoxY;
5458 pitch = (width + 3) / 4 * 4;
5459 needed = pitch * height;
5461 if(!buf || !buflen) break;
5463 max_level = get_max_level( format );
5465 switch(ft_face->glyph->format) {
5466 case ft_glyph_format_bitmap:
5468 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5469 INT h = ft_face->glyph->bitmap.rows;
5470 INT x;
5471 memset( buf, 0, needed );
5472 while(h--) {
5473 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5474 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5475 src += ft_face->glyph->bitmap.pitch;
5476 dst += pitch;
5478 return needed;
5480 case ft_glyph_format_outline:
5482 ft_bitmap.width = width;
5483 ft_bitmap.rows = height;
5484 ft_bitmap.pitch = pitch;
5485 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5486 ft_bitmap.buffer = buf;
5488 if(needsTransform)
5489 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5491 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5493 memset(ft_bitmap.buffer, 0, buflen);
5495 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5497 if (max_level != 255)
5499 for (row = 0, start = buf; row < height; row++)
5501 for (col = 0, ptr = start; col < width; col++, ptr++)
5502 *ptr = (((int)*ptr) * max_level + 128) / 256;
5503 start += pitch;
5506 return needed;
5509 default:
5510 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5511 return GDI_ERROR;
5513 break;
5516 case WINE_GGO_HRGB_BITMAP:
5517 case WINE_GGO_HBGR_BITMAP:
5518 case WINE_GGO_VRGB_BITMAP:
5519 case WINE_GGO_VBGR_BITMAP:
5520 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5522 switch (ft_face->glyph->format)
5524 case FT_GLYPH_FORMAT_BITMAP:
5526 BYTE *src, *dst;
5527 INT src_pitch, x;
5529 width = lpgm->gmBlackBoxX;
5530 height = lpgm->gmBlackBoxY;
5531 pitch = width * 4;
5532 needed = pitch * height;
5534 if (!buf || !buflen) break;
5536 memset(buf, 0, buflen);
5537 dst = buf;
5538 src = ft_face->glyph->bitmap.buffer;
5539 src_pitch = ft_face->glyph->bitmap.pitch;
5541 height = min( height, ft_face->glyph->bitmap.rows );
5542 while ( height-- )
5544 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5546 if ( src[x / 8] & masks[x % 8] )
5547 ((unsigned int *)dst)[x] = ~0u;
5549 src += src_pitch;
5550 dst += pitch;
5553 break;
5556 case FT_GLYPH_FORMAT_OUTLINE:
5558 unsigned int *dst;
5559 BYTE *src;
5560 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5561 INT x_shift, y_shift;
5562 BOOL rgb;
5563 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5564 FT_Render_Mode render_mode =
5565 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5566 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5568 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5570 if ( render_mode == FT_RENDER_MODE_LCD)
5572 lpgm->gmBlackBoxX += 2;
5573 lpgm->gmptGlyphOrigin.x -= 1;
5575 else
5577 lpgm->gmBlackBoxY += 2;
5578 lpgm->gmptGlyphOrigin.y += 1;
5582 width = lpgm->gmBlackBoxX;
5583 height = lpgm->gmBlackBoxY;
5584 pitch = width * 4;
5585 needed = pitch * height;
5587 if (!buf || !buflen) break;
5589 memset(buf, 0, buflen);
5590 dst = buf;
5591 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5593 if ( needsTransform )
5594 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5596 if ( pFT_Library_SetLcdFilter )
5597 pFT_Library_SetLcdFilter( library, lcdfilter );
5598 pFT_Render_Glyph (ft_face->glyph, render_mode);
5600 src = ft_face->glyph->bitmap.buffer;
5601 src_pitch = ft_face->glyph->bitmap.pitch;
5602 src_width = ft_face->glyph->bitmap.width;
5603 src_height = ft_face->glyph->bitmap.rows;
5605 if ( render_mode == FT_RENDER_MODE_LCD)
5607 rgb_interval = 1;
5608 hmul = 3;
5609 vmul = 1;
5611 else
5613 rgb_interval = src_pitch;
5614 hmul = 1;
5615 vmul = 3;
5618 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5619 if ( x_shift < 0 ) x_shift = 0;
5620 if ( x_shift + (src_width / hmul) > width )
5621 x_shift = width - (src_width / hmul);
5623 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5624 if ( y_shift < 0 ) y_shift = 0;
5625 if ( y_shift + (src_height / vmul) > height )
5626 y_shift = height - (src_height / vmul);
5628 dst += x_shift + y_shift * ( pitch / 4 );
5629 while ( src_height )
5631 for ( x = 0; x < src_width / hmul; x++ )
5633 if ( rgb )
5635 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5636 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5637 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5638 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5640 else
5642 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5643 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5644 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5645 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5648 src += src_pitch * vmul;
5649 dst += pitch / 4;
5650 src_height -= vmul;
5653 break;
5656 default:
5657 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5658 return GDI_ERROR;
5661 break;
5663 #else
5664 return GDI_ERROR;
5665 #endif
5667 case GGO_NATIVE:
5669 int contour, point = 0, first_pt;
5670 FT_Outline *outline = &ft_face->glyph->outline;
5671 TTPOLYGONHEADER *pph;
5672 TTPOLYCURVE *ppc;
5673 DWORD pph_start, cpfx, type;
5675 if(buflen == 0) buf = NULL;
5677 if (needsTransform && buf) {
5678 pFT_Outline_Transform(outline, &transMat);
5681 for(contour = 0; contour < outline->n_contours; contour++) {
5682 pph_start = needed;
5683 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5684 first_pt = point;
5685 if(buf) {
5686 pph->dwType = TT_POLYGON_TYPE;
5687 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5689 needed += sizeof(*pph);
5690 point++;
5691 while(point <= outline->contours[contour]) {
5692 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5693 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5694 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5695 cpfx = 0;
5696 do {
5697 if(buf)
5698 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5699 cpfx++;
5700 point++;
5701 } while(point <= outline->contours[contour] &&
5702 (outline->tags[point] & FT_Curve_Tag_On) ==
5703 (outline->tags[point-1] & FT_Curve_Tag_On));
5704 /* At the end of a contour Windows adds the start point, but
5705 only for Beziers */
5706 if(point > outline->contours[contour] &&
5707 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5708 if(buf)
5709 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5710 cpfx++;
5711 } else if(point <= outline->contours[contour] &&
5712 outline->tags[point] & FT_Curve_Tag_On) {
5713 /* add closing pt for bezier */
5714 if(buf)
5715 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5716 cpfx++;
5717 point++;
5719 if(buf) {
5720 ppc->wType = type;
5721 ppc->cpfx = cpfx;
5723 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5725 if(buf)
5726 pph->cb = needed - pph_start;
5728 break;
5730 case GGO_BEZIER:
5732 /* Convert the quadratic Beziers to cubic Beziers.
5733 The parametric eqn for a cubic Bezier is, from PLRM:
5734 r(t) = at^3 + bt^2 + ct + r0
5735 with the control points:
5736 r1 = r0 + c/3
5737 r2 = r1 + (c + b)/3
5738 r3 = r0 + c + b + a
5740 A quadratic Bezier has the form:
5741 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5743 So equating powers of t leads to:
5744 r1 = 2/3 p1 + 1/3 p0
5745 r2 = 2/3 p1 + 1/3 p2
5746 and of course r0 = p0, r3 = p2
5749 int contour, point = 0, first_pt;
5750 FT_Outline *outline = &ft_face->glyph->outline;
5751 TTPOLYGONHEADER *pph;
5752 TTPOLYCURVE *ppc;
5753 DWORD pph_start, cpfx, type;
5754 FT_Vector cubic_control[4];
5755 if(buflen == 0) buf = NULL;
5757 if (needsTransform && buf) {
5758 pFT_Outline_Transform(outline, &transMat);
5761 for(contour = 0; contour < outline->n_contours; contour++) {
5762 pph_start = needed;
5763 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5764 first_pt = point;
5765 if(buf) {
5766 pph->dwType = TT_POLYGON_TYPE;
5767 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5769 needed += sizeof(*pph);
5770 point++;
5771 while(point <= outline->contours[contour]) {
5772 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5773 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5774 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5775 cpfx = 0;
5776 do {
5777 if(type == TT_PRIM_LINE) {
5778 if(buf)
5779 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5780 cpfx++;
5781 point++;
5782 } else {
5783 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5784 so cpfx = 3n */
5786 /* FIXME: Possible optimization in endpoint calculation
5787 if there are two consecutive curves */
5788 cubic_control[0] = outline->points[point-1];
5789 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5790 cubic_control[0].x += outline->points[point].x + 1;
5791 cubic_control[0].y += outline->points[point].y + 1;
5792 cubic_control[0].x >>= 1;
5793 cubic_control[0].y >>= 1;
5795 if(point+1 > outline->contours[contour])
5796 cubic_control[3] = outline->points[first_pt];
5797 else {
5798 cubic_control[3] = outline->points[point+1];
5799 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5800 cubic_control[3].x += outline->points[point].x + 1;
5801 cubic_control[3].y += outline->points[point].y + 1;
5802 cubic_control[3].x >>= 1;
5803 cubic_control[3].y >>= 1;
5806 /* r1 = 1/3 p0 + 2/3 p1
5807 r2 = 1/3 p2 + 2/3 p1 */
5808 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5809 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5810 cubic_control[2] = cubic_control[1];
5811 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5812 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5813 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5814 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5815 if(buf) {
5816 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5817 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5818 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5820 cpfx += 3;
5821 point++;
5823 } while(point <= outline->contours[contour] &&
5824 (outline->tags[point] & FT_Curve_Tag_On) ==
5825 (outline->tags[point-1] & FT_Curve_Tag_On));
5826 /* At the end of a contour Windows adds the start point,
5827 but only for Beziers and we've already done that.
5829 if(point <= outline->contours[contour] &&
5830 outline->tags[point] & FT_Curve_Tag_On) {
5831 /* This is the closing pt of a bezier, but we've already
5832 added it, so just inc point and carry on */
5833 point++;
5835 if(buf) {
5836 ppc->wType = type;
5837 ppc->cpfx = cpfx;
5839 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5841 if(buf)
5842 pph->cb = needed - pph_start;
5844 break;
5847 default:
5848 FIXME("Unsupported format %d\n", format);
5849 return GDI_ERROR;
5851 return needed;
5854 static BOOL get_bitmap_text_metrics(GdiFont *font)
5856 FT_Face ft_face = font->ft_face;
5857 FT_WinFNT_HeaderRec winfnt_header;
5858 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5859 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5860 font->potm->otmSize = size;
5862 #define TM font->potm->otmTextMetrics
5863 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5865 TM.tmHeight = winfnt_header.pixel_height;
5866 TM.tmAscent = winfnt_header.ascent;
5867 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5868 TM.tmInternalLeading = winfnt_header.internal_leading;
5869 TM.tmExternalLeading = winfnt_header.external_leading;
5870 TM.tmAveCharWidth = winfnt_header.avg_width;
5871 TM.tmMaxCharWidth = winfnt_header.max_width;
5872 TM.tmWeight = winfnt_header.weight;
5873 TM.tmOverhang = 0;
5874 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5875 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5876 TM.tmFirstChar = winfnt_header.first_char;
5877 TM.tmLastChar = winfnt_header.last_char;
5878 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5879 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5880 TM.tmItalic = winfnt_header.italic;
5881 TM.tmUnderlined = font->underline;
5882 TM.tmStruckOut = font->strikeout;
5883 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5884 TM.tmCharSet = winfnt_header.charset;
5886 else
5888 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5889 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5890 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5891 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5892 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5893 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5894 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5895 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5896 TM.tmOverhang = 0;
5897 TM.tmDigitizedAspectX = 96; /* FIXME */
5898 TM.tmDigitizedAspectY = 96; /* FIXME */
5899 TM.tmFirstChar = 1;
5900 TM.tmLastChar = 255;
5901 TM.tmDefaultChar = 32;
5902 TM.tmBreakChar = 32;
5903 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5904 TM.tmUnderlined = font->underline;
5905 TM.tmStruckOut = font->strikeout;
5906 /* NB inverted meaning of TMPF_FIXED_PITCH */
5907 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5908 TM.tmCharSet = font->charset;
5910 #undef TM
5912 return TRUE;
5916 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5918 double scale_x, scale_y;
5920 if (font->aveWidth)
5922 scale_x = (double)font->aveWidth;
5923 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5925 else
5926 scale_x = font->scale_y;
5928 scale_x *= fabs(font->font_desc.matrix.eM11);
5929 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5931 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5932 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5934 SCALE_Y(ptm->tmHeight);
5935 SCALE_Y(ptm->tmAscent);
5936 SCALE_Y(ptm->tmDescent);
5937 SCALE_Y(ptm->tmInternalLeading);
5938 SCALE_Y(ptm->tmExternalLeading);
5939 SCALE_Y(ptm->tmOverhang);
5941 SCALE_X(ptm->tmAveCharWidth);
5942 SCALE_X(ptm->tmMaxCharWidth);
5944 #undef SCALE_X
5945 #undef SCALE_Y
5948 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5950 double scale_x, scale_y;
5952 if (font->aveWidth)
5954 scale_x = (double)font->aveWidth;
5955 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5957 else
5958 scale_x = font->scale_y;
5960 scale_x *= fabs(font->font_desc.matrix.eM11);
5961 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5963 scale_font_metrics(font, &potm->otmTextMetrics);
5965 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5966 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5968 SCALE_Y(potm->otmAscent);
5969 SCALE_Y(potm->otmDescent);
5970 SCALE_Y(potm->otmLineGap);
5971 SCALE_Y(potm->otmsCapEmHeight);
5972 SCALE_Y(potm->otmsXHeight);
5973 SCALE_Y(potm->otmrcFontBox.top);
5974 SCALE_Y(potm->otmrcFontBox.bottom);
5975 SCALE_X(potm->otmrcFontBox.left);
5976 SCALE_X(potm->otmrcFontBox.right);
5977 SCALE_Y(potm->otmMacAscent);
5978 SCALE_Y(potm->otmMacDescent);
5979 SCALE_Y(potm->otmMacLineGap);
5980 SCALE_X(potm->otmptSubscriptSize.x);
5981 SCALE_Y(potm->otmptSubscriptSize.y);
5982 SCALE_X(potm->otmptSubscriptOffset.x);
5983 SCALE_Y(potm->otmptSubscriptOffset.y);
5984 SCALE_X(potm->otmptSuperscriptSize.x);
5985 SCALE_Y(potm->otmptSuperscriptSize.y);
5986 SCALE_X(potm->otmptSuperscriptOffset.x);
5987 SCALE_Y(potm->otmptSuperscriptOffset.y);
5988 SCALE_Y(potm->otmsStrikeoutSize);
5989 SCALE_Y(potm->otmsStrikeoutPosition);
5990 SCALE_Y(potm->otmsUnderscoreSize);
5991 SCALE_Y(potm->otmsUnderscorePosition);
5993 #undef SCALE_X
5994 #undef SCALE_Y
5997 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5999 if(!font->potm)
6001 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6003 /* Make sure that the font has sane width/height ratio */
6004 if (font->aveWidth)
6006 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6008 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6009 font->aveWidth = 0;
6013 *ptm = font->potm->otmTextMetrics;
6014 scale_font_metrics(font, ptm);
6015 return TRUE;
6018 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6020 int i;
6022 for(i = 0; i < ft_face->num_charmaps; i++)
6024 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6025 return TRUE;
6027 return FALSE;
6030 static BOOL get_outline_text_metrics(GdiFont *font)
6032 BOOL ret = FALSE;
6033 FT_Face ft_face = font->ft_face;
6034 UINT needed, lenfam, lensty;
6035 TT_OS2 *pOS2;
6036 TT_HoriHeader *pHori;
6037 TT_Postscript *pPost;
6038 FT_Fixed x_scale, y_scale;
6039 WCHAR *family_nameW, *style_nameW;
6040 static const WCHAR spaceW[] = {' ', '\0'};
6041 char *cp;
6042 INT ascent, descent;
6044 TRACE("font=%p\n", font);
6046 if(!FT_IS_SCALABLE(ft_face))
6047 return FALSE;
6049 needed = sizeof(*font->potm);
6051 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6052 family_nameW = strdupW(font->name);
6054 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6055 * sizeof(WCHAR);
6056 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6057 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6058 style_nameW, lensty/sizeof(WCHAR));
6060 /* These names should be read from the TT name table */
6062 /* length of otmpFamilyName */
6063 needed += lenfam;
6065 /* length of otmpFaceName */
6066 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6067 needed += lenfam; /* just the family name */
6068 } else {
6069 needed += lenfam + lensty; /* family + " " + style */
6072 /* length of otmpStyleName */
6073 needed += lensty;
6075 /* length of otmpFullName */
6076 needed += lenfam + lensty;
6079 x_scale = ft_face->size->metrics.x_scale;
6080 y_scale = ft_face->size->metrics.y_scale;
6082 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6083 if(!pOS2) {
6084 FIXME("Can't find OS/2 table - not TT font?\n");
6085 goto end;
6088 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6089 if(!pHori) {
6090 FIXME("Can't find HHEA table - not TT font?\n");
6091 goto end;
6094 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6096 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",
6097 pOS2->usWinAscent, pOS2->usWinDescent,
6098 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6099 ft_face->ascender, ft_face->descender, ft_face->height,
6100 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6101 ft_face->bbox.yMax, ft_face->bbox.yMin);
6103 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6104 font->potm->otmSize = needed;
6106 #define TM font->potm->otmTextMetrics
6108 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6109 ascent = pHori->Ascender;
6110 descent = -pHori->Descender;
6111 } else {
6112 ascent = pOS2->usWinAscent;
6113 descent = pOS2->usWinDescent;
6116 if(font->yMax) {
6117 TM.tmAscent = font->yMax;
6118 TM.tmDescent = -font->yMin;
6119 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6120 } else {
6121 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6122 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6123 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6124 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6127 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6129 /* MSDN says:
6130 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6132 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6133 ((ascent + descent) -
6134 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6136 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6137 if (TM.tmAveCharWidth == 0) {
6138 TM.tmAveCharWidth = 1;
6140 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6141 TM.tmWeight = FW_REGULAR;
6142 if (font->fake_bold)
6143 TM.tmWeight = FW_BOLD;
6144 else
6146 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6148 if (pOS2->usWeightClass > FW_MEDIUM)
6149 TM.tmWeight = pOS2->usWeightClass;
6151 else if (pOS2->usWeightClass <= FW_MEDIUM)
6152 TM.tmWeight = pOS2->usWeightClass;
6154 TM.tmOverhang = 0;
6155 TM.tmDigitizedAspectX = 300;
6156 TM.tmDigitizedAspectY = 300;
6157 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6158 * symbol range to 0 - f0ff
6161 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6163 TM.tmFirstChar = 0;
6164 switch(GetACP())
6166 case 1257: /* Baltic */
6167 TM.tmLastChar = 0xf8fd;
6168 break;
6169 default:
6170 TM.tmLastChar = 0xf0ff;
6172 TM.tmBreakChar = 0x20;
6173 TM.tmDefaultChar = 0x1f;
6175 else
6177 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6178 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6180 if(pOS2->usFirstCharIndex <= 1)
6181 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6182 else if (pOS2->usFirstCharIndex > 0xff)
6183 TM.tmBreakChar = 0x20;
6184 else
6185 TM.tmBreakChar = pOS2->usFirstCharIndex;
6186 TM.tmDefaultChar = TM.tmBreakChar - 1;
6188 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6189 TM.tmUnderlined = font->underline;
6190 TM.tmStruckOut = font->strikeout;
6192 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6193 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6194 (pOS2->version == 0xFFFFU ||
6195 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6196 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6197 else
6198 TM.tmPitchAndFamily = 0;
6200 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6202 case PAN_FAMILY_SCRIPT:
6203 TM.tmPitchAndFamily |= FF_SCRIPT;
6204 break;
6206 case PAN_FAMILY_DECORATIVE:
6207 TM.tmPitchAndFamily |= FF_DECORATIVE;
6208 break;
6210 case PAN_ANY:
6211 case PAN_NO_FIT:
6212 case PAN_FAMILY_TEXT_DISPLAY:
6213 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6214 /* which is clearly not what the panose spec says. */
6215 default:
6216 if(TM.tmPitchAndFamily == 0 || /* fixed */
6217 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6218 TM.tmPitchAndFamily = FF_MODERN;
6219 else
6221 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6223 case PAN_ANY:
6224 case PAN_NO_FIT:
6225 default:
6226 TM.tmPitchAndFamily |= FF_DONTCARE;
6227 break;
6229 case PAN_SERIF_COVE:
6230 case PAN_SERIF_OBTUSE_COVE:
6231 case PAN_SERIF_SQUARE_COVE:
6232 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6233 case PAN_SERIF_SQUARE:
6234 case PAN_SERIF_THIN:
6235 case PAN_SERIF_BONE:
6236 case PAN_SERIF_EXAGGERATED:
6237 case PAN_SERIF_TRIANGLE:
6238 TM.tmPitchAndFamily |= FF_ROMAN;
6239 break;
6241 case PAN_SERIF_NORMAL_SANS:
6242 case PAN_SERIF_OBTUSE_SANS:
6243 case PAN_SERIF_PERP_SANS:
6244 case PAN_SERIF_FLARED:
6245 case PAN_SERIF_ROUNDED:
6246 TM.tmPitchAndFamily |= FF_SWISS;
6247 break;
6250 break;
6253 if(FT_IS_SCALABLE(ft_face))
6254 TM.tmPitchAndFamily |= TMPF_VECTOR;
6256 if(FT_IS_SFNT(ft_face))
6258 if (font->ntmFlags & NTM_PS_OPENTYPE)
6259 TM.tmPitchAndFamily |= TMPF_DEVICE;
6260 else
6261 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6264 TM.tmCharSet = font->charset;
6266 font->potm->otmFiller = 0;
6267 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6268 font->potm->otmfsSelection = pOS2->fsSelection;
6269 font->potm->otmfsType = pOS2->fsType;
6270 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6271 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6272 font->potm->otmItalicAngle = 0; /* POST table */
6273 font->potm->otmEMSquare = ft_face->units_per_EM;
6274 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6275 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6276 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6277 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6278 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6279 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6280 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6281 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6282 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6283 font->potm->otmMacAscent = TM.tmAscent;
6284 font->potm->otmMacDescent = -TM.tmDescent;
6285 font->potm->otmMacLineGap = font->potm->otmLineGap;
6286 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6287 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6288 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6289 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6290 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6291 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6292 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6293 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6294 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6295 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6296 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6297 if(!pPost) {
6298 font->potm->otmsUnderscoreSize = 0;
6299 font->potm->otmsUnderscorePosition = 0;
6300 } else {
6301 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6302 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6304 #undef TM
6306 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6307 cp = (char*)font->potm + sizeof(*font->potm);
6308 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6309 strcpyW((WCHAR*)cp, family_nameW);
6310 cp += lenfam;
6311 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6312 strcpyW((WCHAR*)cp, style_nameW);
6313 cp += lensty;
6314 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6315 strcpyW((WCHAR*)cp, family_nameW);
6316 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6317 strcatW((WCHAR*)cp, spaceW);
6318 strcatW((WCHAR*)cp, style_nameW);
6319 cp += lenfam + lensty;
6320 } else
6321 cp += lenfam;
6322 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6323 strcpyW((WCHAR*)cp, family_nameW);
6324 strcatW((WCHAR*)cp, spaceW);
6325 strcatW((WCHAR*)cp, style_nameW);
6326 ret = TRUE;
6328 end:
6329 HeapFree(GetProcessHeap(), 0, style_nameW);
6330 HeapFree(GetProcessHeap(), 0, family_nameW);
6331 return ret;
6334 /*************************************************************
6335 * freetype_GetGlyphOutline
6337 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6338 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6340 struct freetype_physdev *physdev = get_freetype_dev( dev );
6341 DWORD ret;
6343 if (!physdev->font)
6345 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6346 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6349 GDI_CheckNotLock();
6350 EnterCriticalSection( &freetype_cs );
6351 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6352 LeaveCriticalSection( &freetype_cs );
6353 return ret;
6356 /*************************************************************
6357 * freetype_GetTextMetrics
6359 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6361 struct freetype_physdev *physdev = get_freetype_dev( dev );
6362 BOOL ret;
6364 if (!physdev->font)
6366 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6367 return dev->funcs->pGetTextMetrics( dev, metrics );
6370 GDI_CheckNotLock();
6371 EnterCriticalSection( &freetype_cs );
6372 ret = get_text_metrics( physdev->font, metrics );
6373 LeaveCriticalSection( &freetype_cs );
6374 return ret;
6377 /*************************************************************
6378 * freetype_GetOutlineTextMetrics
6380 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6382 struct freetype_physdev *physdev = get_freetype_dev( dev );
6383 UINT ret = 0;
6385 if (!physdev->font)
6387 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6388 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6391 TRACE("font=%p\n", physdev->font);
6393 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6395 GDI_CheckNotLock();
6396 EnterCriticalSection( &freetype_cs );
6398 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6400 if(cbSize >= physdev->font->potm->otmSize)
6402 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6403 scale_outline_font_metrics(physdev->font, potm);
6405 ret = physdev->font->potm->otmSize;
6407 LeaveCriticalSection( &freetype_cs );
6408 return ret;
6411 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6413 HFONTLIST *hfontlist;
6414 child->font = alloc_font();
6415 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6416 if(!child->font->ft_face)
6418 free_font(child->font);
6419 child->font = NULL;
6420 return FALSE;
6423 child->font->font_desc = font->font_desc;
6424 child->font->ntmFlags = child->face->ntmFlags;
6425 child->font->orientation = font->orientation;
6426 child->font->scale_y = font->scale_y;
6427 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6428 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6429 child->font->name = strdupW(child->face->family->FamilyName);
6430 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6431 child->font->base_font = font;
6432 list_add_head(&child_font_list, &child->font->entry);
6433 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6434 return TRUE;
6437 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6439 FT_UInt g;
6440 CHILD_FONT *child_font;
6442 if(font->base_font)
6443 font = font->base_font;
6445 *linked_font = font;
6447 if((*glyph = get_glyph_index(font, c)))
6449 *glyph = get_GSUB_vert_glyph(font, *glyph);
6450 return TRUE;
6453 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6455 if(!child_font->font)
6456 if(!load_child_font(font, child_font))
6457 continue;
6459 if(!child_font->font->ft_face)
6460 continue;
6461 g = get_glyph_index(child_font->font, c);
6462 g = get_GSUB_vert_glyph(child_font->font, g);
6463 if(g)
6465 *glyph = g;
6466 *linked_font = child_font->font;
6467 return TRUE;
6470 return FALSE;
6473 /*************************************************************
6474 * freetype_GetCharWidth
6476 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6478 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6479 UINT c;
6480 GLYPHMETRICS gm;
6481 FT_UInt glyph_index;
6482 GdiFont *linked_font;
6483 struct freetype_physdev *physdev = get_freetype_dev( dev );
6485 if (!physdev->font)
6487 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6488 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6491 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6493 GDI_CheckNotLock();
6494 EnterCriticalSection( &freetype_cs );
6495 for(c = firstChar; c <= lastChar; c++) {
6496 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6497 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6498 &gm, 0, NULL, &identity);
6499 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6501 LeaveCriticalSection( &freetype_cs );
6502 return TRUE;
6505 /*************************************************************
6506 * freetype_GetCharABCWidths
6508 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6510 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6511 UINT c;
6512 GLYPHMETRICS gm;
6513 FT_UInt glyph_index;
6514 GdiFont *linked_font;
6515 struct freetype_physdev *physdev = get_freetype_dev( dev );
6517 if (!physdev->font)
6519 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6520 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6523 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6525 GDI_CheckNotLock();
6526 EnterCriticalSection( &freetype_cs );
6528 for(c = firstChar; c <= lastChar; c++) {
6529 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6530 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6531 &gm, 0, NULL, &identity);
6532 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6533 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6534 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6535 FONT_GM(linked_font,glyph_index)->bbx;
6537 LeaveCriticalSection( &freetype_cs );
6538 return TRUE;
6541 /*************************************************************
6542 * freetype_GetCharABCWidthsI
6544 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6546 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6547 UINT c;
6548 GLYPHMETRICS gm;
6549 FT_UInt glyph_index;
6550 GdiFont *linked_font;
6551 struct freetype_physdev *physdev = get_freetype_dev( dev );
6553 if (!physdev->font)
6555 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6556 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6559 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6560 return FALSE;
6562 GDI_CheckNotLock();
6563 EnterCriticalSection( &freetype_cs );
6565 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6566 if (!pgi)
6567 for(c = firstChar; c < firstChar+count; c++) {
6568 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6569 &gm, 0, NULL, &identity);
6570 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6571 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6572 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6573 - FONT_GM(linked_font,c)->bbx;
6575 else
6576 for(c = 0; c < count; c++) {
6577 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6578 &gm, 0, NULL, &identity);
6579 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6580 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6581 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6582 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6585 LeaveCriticalSection( &freetype_cs );
6586 return TRUE;
6589 /*************************************************************
6590 * freetype_GetTextExtentExPoint
6592 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6593 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6595 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6596 INT idx;
6597 INT nfit = 0, ext;
6598 GLYPHMETRICS gm;
6599 TEXTMETRICW tm;
6600 FT_UInt glyph_index;
6601 GdiFont *linked_font;
6602 struct freetype_physdev *physdev = get_freetype_dev( dev );
6604 if (!physdev->font)
6606 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6607 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6610 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6612 GDI_CheckNotLock();
6613 EnterCriticalSection( &freetype_cs );
6615 size->cx = 0;
6616 get_text_metrics( physdev->font, &tm );
6617 size->cy = tm.tmHeight;
6619 for(idx = 0; idx < count; idx++) {
6620 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6621 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6622 &gm, 0, NULL, &identity);
6623 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6624 ext = size->cx;
6625 if (! pnfit || ext <= max_ext) {
6626 ++nfit;
6627 if (dxs)
6628 dxs[idx] = ext;
6632 if (pnfit)
6633 *pnfit = nfit;
6635 LeaveCriticalSection( &freetype_cs );
6636 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6637 return TRUE;
6640 /*************************************************************
6641 * freetype_GetTextExtentExPointI
6643 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6644 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6646 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6647 INT idx;
6648 INT nfit = 0, ext;
6649 GLYPHMETRICS gm;
6650 TEXTMETRICW tm;
6651 struct freetype_physdev *physdev = get_freetype_dev( dev );
6653 if (!physdev->font)
6655 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6656 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6659 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6661 GDI_CheckNotLock();
6662 EnterCriticalSection( &freetype_cs );
6664 size->cx = 0;
6665 get_text_metrics(physdev->font, &tm);
6666 size->cy = tm.tmHeight;
6668 for(idx = 0; idx < count; idx++) {
6669 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6670 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6671 ext = size->cx;
6672 if (! pnfit || ext <= max_ext) {
6673 ++nfit;
6674 if (dxs)
6675 dxs[idx] = ext;
6679 if (pnfit)
6680 *pnfit = nfit;
6682 LeaveCriticalSection( &freetype_cs );
6683 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6684 return TRUE;
6687 /*************************************************************
6688 * freetype_GetFontData
6690 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6692 struct freetype_physdev *physdev = get_freetype_dev( dev );
6694 if (!physdev->font)
6696 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6697 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6700 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6701 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6702 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6704 return get_font_data( physdev->font, table, offset, buf, cbData );
6707 /*************************************************************
6708 * freetype_GetTextFace
6710 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6712 INT n;
6713 struct freetype_physdev *physdev = get_freetype_dev( dev );
6715 if (!physdev->font)
6717 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6718 return dev->funcs->pGetTextFace( dev, count, str );
6721 n = strlenW(physdev->font->name) + 1;
6722 if (str)
6724 lstrcpynW(str, physdev->font->name, count);
6725 n = min(count, n);
6727 return n;
6730 /*************************************************************
6731 * freetype_GetTextCharsetInfo
6733 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6735 struct freetype_physdev *physdev = get_freetype_dev( dev );
6737 if (!physdev->font)
6739 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6740 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6742 if (fs) *fs = physdev->font->fs;
6743 return physdev->font->charset;
6746 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6748 GdiFont *font = dc->gdiFont, *linked_font;
6749 struct list *first_hfont;
6750 BOOL ret;
6752 GDI_CheckNotLock();
6753 EnterCriticalSection( &freetype_cs );
6754 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6755 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6756 if(font == linked_font)
6757 *new_hfont = dc->hFont;
6758 else
6760 first_hfont = list_head(&linked_font->hfontlist);
6761 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6763 LeaveCriticalSection( &freetype_cs );
6764 return ret;
6767 /* Retrieve a list of supported Unicode ranges for a given font.
6768 * Can be called with NULL gs to calculate the buffer size. Returns
6769 * the number of ranges found.
6771 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6773 DWORD num_ranges = 0;
6775 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6777 FT_UInt glyph_code;
6778 FT_ULong char_code, char_code_prev;
6780 glyph_code = 0;
6781 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6783 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6784 face->num_glyphs, glyph_code, char_code);
6786 if (!glyph_code) return 0;
6788 if (gs)
6790 gs->ranges[0].wcLow = (USHORT)char_code;
6791 gs->ranges[0].cGlyphs = 0;
6792 gs->cGlyphsSupported = 0;
6795 num_ranges = 1;
6796 while (glyph_code)
6798 if (char_code < char_code_prev)
6800 ERR("expected increasing char code from FT_Get_Next_Char\n");
6801 return 0;
6803 if (char_code - char_code_prev > 1)
6805 num_ranges++;
6806 if (gs)
6808 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6809 gs->ranges[num_ranges - 1].cGlyphs = 1;
6810 gs->cGlyphsSupported++;
6813 else if (gs)
6815 gs->ranges[num_ranges - 1].cGlyphs++;
6816 gs->cGlyphsSupported++;
6818 char_code_prev = char_code;
6819 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6822 else
6823 FIXME("encoding %u not supported\n", face->charmap->encoding);
6825 return num_ranges;
6828 /*************************************************************
6829 * freetype_GetFontUnicodeRanges
6831 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6833 struct freetype_physdev *physdev = get_freetype_dev( dev );
6834 DWORD size, num_ranges;
6836 if (!physdev->font)
6838 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6839 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6842 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6843 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6844 if (glyphset)
6846 glyphset->cbThis = size;
6847 glyphset->cRanges = num_ranges;
6848 glyphset->flAccel = 0;
6850 return size;
6853 /*************************************************************
6854 * freetype_FontIsLinked
6856 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6858 struct freetype_physdev *physdev = get_freetype_dev( dev );
6859 BOOL ret;
6861 if (!physdev->font)
6863 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6864 return dev->funcs->pFontIsLinked( dev );
6867 GDI_CheckNotLock();
6868 EnterCriticalSection( &freetype_cs );
6869 ret = !list_empty(&physdev->font->child_fonts);
6870 LeaveCriticalSection( &freetype_cs );
6871 return ret;
6874 static BOOL is_hinting_enabled(void)
6876 /* Use the >= 2.2.0 function if available */
6877 if(pFT_Get_TrueType_Engine_Type)
6879 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6880 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6882 #ifdef FT_DRIVER_HAS_HINTER
6883 else
6885 FT_Module mod;
6887 /* otherwise if we've been compiled with < 2.2.0 headers
6888 use the internal macro */
6889 mod = pFT_Get_Module(library, "truetype");
6890 if(mod && FT_DRIVER_HAS_HINTER(mod))
6891 return TRUE;
6893 #endif
6895 return FALSE;
6898 static BOOL is_subpixel_rendering_enabled( void )
6900 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6901 return pFT_Library_SetLcdFilter &&
6902 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6903 #else
6904 return FALSE;
6905 #endif
6908 /*************************************************************************
6909 * GetRasterizerCaps (GDI32.@)
6911 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6913 static int hinting = -1;
6914 static int subpixel = -1;
6916 if(hinting == -1)
6918 hinting = is_hinting_enabled();
6919 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6922 if ( subpixel == -1 )
6924 subpixel = is_subpixel_rendering_enabled();
6925 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6928 lprs->nSize = sizeof(RASTERIZER_STATUS);
6929 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6930 if ( subpixel )
6931 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6932 lprs->nLanguageID = 0;
6933 return TRUE;
6936 /*************************************************************
6937 * freetype_GdiRealizationInfo
6939 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6941 struct freetype_physdev *physdev = get_freetype_dev( dev );
6942 realization_info_t *info = ptr;
6944 if (!physdev->font)
6946 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6947 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6950 FIXME("(%p, %p): stub!\n", physdev->font, info);
6952 info->flags = 1;
6953 if(FT_IS_SCALABLE(physdev->font->ft_face))
6954 info->flags |= 2;
6956 info->cache_num = physdev->font->cache_num;
6957 info->unknown2 = -1;
6958 return TRUE;
6961 /*************************************************************************
6962 * Kerning support for TrueType fonts
6964 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6966 struct TT_kern_table
6968 USHORT version;
6969 USHORT nTables;
6972 struct TT_kern_subtable
6974 USHORT version;
6975 USHORT length;
6976 union
6978 USHORT word;
6979 struct
6981 USHORT horizontal : 1;
6982 USHORT minimum : 1;
6983 USHORT cross_stream: 1;
6984 USHORT override : 1;
6985 USHORT reserved1 : 4;
6986 USHORT format : 8;
6987 } bits;
6988 } coverage;
6991 struct TT_format0_kern_subtable
6993 USHORT nPairs;
6994 USHORT searchRange;
6995 USHORT entrySelector;
6996 USHORT rangeShift;
6999 struct TT_kern_pair
7001 USHORT left;
7002 USHORT right;
7003 short value;
7006 static DWORD parse_format0_kern_subtable(GdiFont *font,
7007 const struct TT_format0_kern_subtable *tt_f0_ks,
7008 const USHORT *glyph_to_char,
7009 KERNINGPAIR *kern_pair, DWORD cPairs)
7011 USHORT i, nPairs;
7012 const struct TT_kern_pair *tt_kern_pair;
7014 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7016 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7018 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7019 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7020 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7022 if (!kern_pair || !cPairs)
7023 return nPairs;
7025 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7027 nPairs = min(nPairs, cPairs);
7029 for (i = 0; i < nPairs; i++)
7031 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7032 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7033 /* this algorithm appears to better match what Windows does */
7034 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7035 if (kern_pair->iKernAmount < 0)
7037 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7038 kern_pair->iKernAmount -= font->ppem;
7040 else if (kern_pair->iKernAmount > 0)
7042 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7043 kern_pair->iKernAmount += font->ppem;
7045 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7047 TRACE("left %u right %u value %d\n",
7048 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7050 kern_pair++;
7052 TRACE("copied %u entries\n", nPairs);
7053 return nPairs;
7056 /*************************************************************
7057 * freetype_GetKerningPairs
7059 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7061 DWORD length;
7062 void *buf;
7063 const struct TT_kern_table *tt_kern_table;
7064 const struct TT_kern_subtable *tt_kern_subtable;
7065 USHORT i, nTables;
7066 USHORT *glyph_to_char;
7067 GdiFont *font;
7068 struct freetype_physdev *physdev = get_freetype_dev( dev );
7070 if (!(font = physdev->font))
7072 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7073 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7076 GDI_CheckNotLock();
7077 EnterCriticalSection( &freetype_cs );
7078 if (font->total_kern_pairs != (DWORD)-1)
7080 if (cPairs && kern_pair)
7082 cPairs = min(cPairs, font->total_kern_pairs);
7083 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7085 else cPairs = font->total_kern_pairs;
7087 LeaveCriticalSection( &freetype_cs );
7088 return cPairs;
7091 font->total_kern_pairs = 0;
7093 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7095 if (length == GDI_ERROR)
7097 TRACE("no kerning data in the font\n");
7098 LeaveCriticalSection( &freetype_cs );
7099 return 0;
7102 buf = HeapAlloc(GetProcessHeap(), 0, length);
7103 if (!buf)
7105 WARN("Out of memory\n");
7106 LeaveCriticalSection( &freetype_cs );
7107 return 0;
7110 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7112 /* build a glyph index to char code map */
7113 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7114 if (!glyph_to_char)
7116 WARN("Out of memory allocating a glyph index to char code map\n");
7117 HeapFree(GetProcessHeap(), 0, buf);
7118 LeaveCriticalSection( &freetype_cs );
7119 return 0;
7122 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7124 FT_UInt glyph_code;
7125 FT_ULong char_code;
7127 glyph_code = 0;
7128 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7130 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7131 font->ft_face->num_glyphs, glyph_code, char_code);
7133 while (glyph_code)
7135 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7137 /* FIXME: This doesn't match what Windows does: it does some fancy
7138 * things with duplicate glyph index to char code mappings, while
7139 * we just avoid overriding existing entries.
7141 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7142 glyph_to_char[glyph_code] = (USHORT)char_code;
7144 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7147 else
7149 ULONG n;
7151 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7152 for (n = 0; n <= 65535; n++)
7153 glyph_to_char[n] = (USHORT)n;
7156 tt_kern_table = buf;
7157 nTables = GET_BE_WORD(tt_kern_table->nTables);
7158 TRACE("version %u, nTables %u\n",
7159 GET_BE_WORD(tt_kern_table->version), nTables);
7161 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7163 for (i = 0; i < nTables; i++)
7165 struct TT_kern_subtable tt_kern_subtable_copy;
7167 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7168 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7169 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7171 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7172 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7173 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7175 /* According to the TrueType specification this is the only format
7176 * that will be properly interpreted by Windows and OS/2
7178 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7180 DWORD new_chunk, old_total = font->total_kern_pairs;
7182 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7183 glyph_to_char, NULL, 0);
7184 font->total_kern_pairs += new_chunk;
7186 if (!font->kern_pairs)
7187 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7188 font->total_kern_pairs * sizeof(*font->kern_pairs));
7189 else
7190 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7191 font->total_kern_pairs * sizeof(*font->kern_pairs));
7193 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7194 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7196 else
7197 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7199 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7202 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7203 HeapFree(GetProcessHeap(), 0, buf);
7205 if (cPairs && kern_pair)
7207 cPairs = min(cPairs, font->total_kern_pairs);
7208 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7210 else cPairs = font->total_kern_pairs;
7212 LeaveCriticalSection( &freetype_cs );
7213 return cPairs;
7216 static const struct gdi_dc_funcs freetype_funcs =
7218 NULL, /* pAbortDoc */
7219 NULL, /* pAbortPath */
7220 NULL, /* pAlphaBlend */
7221 NULL, /* pAngleArc */
7222 NULL, /* pArc */
7223 NULL, /* pArcTo */
7224 NULL, /* pBeginPath */
7225 NULL, /* pBlendImage */
7226 NULL, /* pChoosePixelFormat */
7227 NULL, /* pChord */
7228 NULL, /* pCloseFigure */
7229 NULL, /* pCopyBitmap */
7230 NULL, /* pCreateBitmap */
7231 NULL, /* pCreateCompatibleDC */
7232 freetype_CreateDC, /* pCreateDC */
7233 NULL, /* pDeleteBitmap */
7234 freetype_DeleteDC, /* pDeleteDC */
7235 NULL, /* pDeleteObject */
7236 NULL, /* pDescribePixelFormat */
7237 NULL, /* pDeviceCapabilities */
7238 NULL, /* pEllipse */
7239 NULL, /* pEndDoc */
7240 NULL, /* pEndPage */
7241 NULL, /* pEndPath */
7242 freetype_EnumFonts, /* pEnumFonts */
7243 NULL, /* pEnumICMProfiles */
7244 NULL, /* pExcludeClipRect */
7245 NULL, /* pExtDeviceMode */
7246 NULL, /* pExtEscape */
7247 NULL, /* pExtFloodFill */
7248 NULL, /* pExtSelectClipRgn */
7249 NULL, /* pExtTextOut */
7250 NULL, /* pFillPath */
7251 NULL, /* pFillRgn */
7252 NULL, /* pFlattenPath */
7253 freetype_FontIsLinked, /* pFontIsLinked */
7254 NULL, /* pFrameRgn */
7255 NULL, /* pGdiComment */
7256 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7257 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7258 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7259 freetype_GetCharWidth, /* pGetCharWidth */
7260 NULL, /* pGetDeviceCaps */
7261 NULL, /* pGetDeviceGammaRamp */
7262 freetype_GetFontData, /* pGetFontData */
7263 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7264 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7265 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7266 NULL, /* pGetICMProfile */
7267 NULL, /* pGetImage */
7268 freetype_GetKerningPairs, /* pGetKerningPairs */
7269 NULL, /* pGetNearestColor */
7270 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7271 NULL, /* pGetPixel */
7272 NULL, /* pGetPixelFormat */
7273 NULL, /* pGetSystemPaletteEntries */
7274 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7275 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7276 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7277 freetype_GetTextFace, /* pGetTextFace */
7278 freetype_GetTextMetrics, /* pGetTextMetrics */
7279 NULL, /* pGradientFill */
7280 NULL, /* pIntersectClipRect */
7281 NULL, /* pInvertRgn */
7282 NULL, /* pLineTo */
7283 NULL, /* pModifyWorldTransform */
7284 NULL, /* pMoveTo */
7285 NULL, /* pOffsetClipRgn */
7286 NULL, /* pOffsetViewportOrg */
7287 NULL, /* pOffsetWindowOrg */
7288 NULL, /* pPaintRgn */
7289 NULL, /* pPatBlt */
7290 NULL, /* pPie */
7291 NULL, /* pPolyBezier */
7292 NULL, /* pPolyBezierTo */
7293 NULL, /* pPolyDraw */
7294 NULL, /* pPolyPolygon */
7295 NULL, /* pPolyPolyline */
7296 NULL, /* pPolygon */
7297 NULL, /* pPolyline */
7298 NULL, /* pPolylineTo */
7299 NULL, /* pPutImage */
7300 NULL, /* pRealizeDefaultPalette */
7301 NULL, /* pRealizePalette */
7302 NULL, /* pRectangle */
7303 NULL, /* pResetDC */
7304 NULL, /* pRestoreDC */
7305 NULL, /* pRoundRect */
7306 NULL, /* pSaveDC */
7307 NULL, /* pScaleViewportExt */
7308 NULL, /* pScaleWindowExt */
7309 NULL, /* pSelectBitmap */
7310 NULL, /* pSelectBrush */
7311 NULL, /* pSelectClipPath */
7312 freetype_SelectFont, /* pSelectFont */
7313 NULL, /* pSelectPalette */
7314 NULL, /* pSelectPen */
7315 NULL, /* pSetArcDirection */
7316 NULL, /* pSetBkColor */
7317 NULL, /* pSetBkMode */
7318 NULL, /* pSetDCBrushColor */
7319 NULL, /* pSetDCPenColor */
7320 NULL, /* pSetDIBColorTable */
7321 NULL, /* pSetDIBitsToDevice */
7322 NULL, /* pSetDeviceClipping */
7323 NULL, /* pSetDeviceGammaRamp */
7324 NULL, /* pSetLayout */
7325 NULL, /* pSetMapMode */
7326 NULL, /* pSetMapperFlags */
7327 NULL, /* pSetPixel */
7328 NULL, /* pSetPixelFormat */
7329 NULL, /* pSetPolyFillMode */
7330 NULL, /* pSetROP2 */
7331 NULL, /* pSetRelAbs */
7332 NULL, /* pSetStretchBltMode */
7333 NULL, /* pSetTextAlign */
7334 NULL, /* pSetTextCharacterExtra */
7335 NULL, /* pSetTextColor */
7336 NULL, /* pSetTextJustification */
7337 NULL, /* pSetViewportExt */
7338 NULL, /* pSetViewportOrg */
7339 NULL, /* pSetWindowExt */
7340 NULL, /* pSetWindowOrg */
7341 NULL, /* pSetWorldTransform */
7342 NULL, /* pStartDoc */
7343 NULL, /* pStartPage */
7344 NULL, /* pStretchBlt */
7345 NULL, /* pStretchDIBits */
7346 NULL, /* pStrokeAndFillPath */
7347 NULL, /* pStrokePath */
7348 NULL, /* pSwapBuffers */
7349 NULL, /* pUnrealizePalette */
7350 NULL, /* pWidenPath */
7351 /* OpenGL not supported */
7354 #else /* HAVE_FREETYPE */
7356 /*************************************************************************/
7358 BOOL WineEngInit(void)
7360 return FALSE;
7362 BOOL WineEngDestroyFontInstance(HFONT hfont)
7364 return FALSE;
7367 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7369 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7370 return 1;
7373 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7375 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7376 return TRUE;
7379 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7381 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7382 return NULL;
7385 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7387 return FALSE;
7390 /*************************************************************************
7391 * GetRasterizerCaps (GDI32.@)
7393 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7395 lprs->nSize = sizeof(RASTERIZER_STATUS);
7396 lprs->wFlags = 0;
7397 lprs->nLanguageID = 0;
7398 return TRUE;
7401 #endif /* HAVE_FREETYPE */