gdi32: Add a helper function to find font link.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob3056462d85fde67e4416581e8fd47e2e1dc9e8b4
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 SYSTEM_LINKS *find_font_link(const WCHAR *name)
1983 SYSTEM_LINKS *font_link;
1985 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1987 if(!strcmpiW(font_link->font_name, name))
1988 return font_link;
1991 return NULL;
1994 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
1996 const WCHAR *value;
1997 int i;
1998 FontSubst *psub;
1999 Family *family;
2000 Face *face;
2001 const char *file;
2002 WCHAR *fileW;
2003 FONTSIGNATURE fs;
2005 if (values)
2007 SYSTEM_LINKS *font_link;
2009 memset(&fs, 0, sizeof(fs));
2010 psub = get_font_subst(&font_subst_list, name, -1);
2011 /* Don't store fonts that are only substitutes for other fonts */
2012 if(psub)
2014 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2015 return;
2018 font_link = find_font_link(name);
2019 if (font_link == NULL)
2021 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2022 font_link->font_name = strdupW(name);
2023 list_init(&font_link->links);
2024 list_add_tail(&system_links, &font_link->entry);
2027 for (i = 0; values[i] != NULL; i++)
2029 CHILD_FONT *child_font;
2031 value = values[i];
2032 if (!strcmpiW(name,value))
2033 continue;
2034 psub = get_font_subst(&font_subst_list, value, -1);
2035 if(psub)
2036 value = psub->to.name;
2037 family = find_family_from_name(value);
2038 if (!family)
2039 continue;
2040 file = NULL;
2041 /* Use first extant filename for this Family */
2042 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2044 if (!face->file)
2045 continue;
2046 file = strrchr(face->file, '/');
2047 if (!file)
2048 file = face->file;
2049 else
2050 file++;
2051 break;
2053 if (!file)
2054 continue;
2055 fileW = towstr(CP_UNIXCP, file);
2057 face = find_face_from_filename(fileW, value);
2058 if(!face)
2060 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2061 continue;
2064 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2065 child_font->face = face;
2066 child_font->font = NULL;
2067 fs.fsCsb[0] |= face->fs.fsCsb[0];
2068 fs.fsCsb[1] |= face->fs.fsCsb[1];
2069 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2070 list_add_tail(&font_link->links, &child_font->entry);
2072 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2073 HeapFree(GetProcessHeap(), 0, fileW);
2076 family = find_family_from_name(font_link->font_name);
2077 if(family)
2079 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2081 face->fs_links = fs;
2088 /*************************************************************
2089 * init_system_links
2091 static BOOL init_system_links(void)
2093 HKEY hkey;
2094 BOOL ret = FALSE;
2095 DWORD type, max_val, max_data, val_len, data_len, index;
2096 WCHAR *value, *data;
2097 WCHAR *entry, *next;
2098 SYSTEM_LINKS *font_link, *system_font_link;
2099 CHILD_FONT *child_font;
2100 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2101 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2102 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2103 FONTSIGNATURE fs;
2104 Family *family;
2105 Face *face;
2106 FontSubst *psub;
2107 UINT i, j;
2109 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2111 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2112 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2113 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2114 val_len = max_val + 1;
2115 data_len = max_data;
2116 index = 0;
2117 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2119 memset(&fs, 0, sizeof(fs));
2120 psub = get_font_subst(&font_subst_list, value, -1);
2121 /* Don't store fonts that are only substitutes for other fonts */
2122 if(psub)
2124 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2125 goto next;
2127 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2128 font_link->font_name = strdupW(value);
2129 list_init(&font_link->links);
2130 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2132 WCHAR *face_name;
2133 CHILD_FONT *child_font;
2135 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2137 next = entry + strlenW(entry) + 1;
2139 face_name = strchrW(entry, ',');
2140 if(face_name)
2142 *face_name++ = 0;
2143 while(isspaceW(*face_name))
2144 face_name++;
2146 psub = get_font_subst(&font_subst_list, face_name, -1);
2147 if(psub)
2148 face_name = psub->to.name;
2150 face = find_face_from_filename(entry, face_name);
2151 if(!face)
2153 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2154 continue;
2157 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2158 child_font->face = face;
2159 child_font->font = NULL;
2160 fs.fsCsb[0] |= face->fs.fsCsb[0];
2161 fs.fsCsb[1] |= face->fs.fsCsb[1];
2162 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2163 list_add_tail(&font_link->links, &child_font->entry);
2165 family = find_family_from_name(font_link->font_name);
2166 if(family)
2168 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2170 face->fs_links = fs;
2173 list_add_tail(&system_links, &font_link->entry);
2174 next:
2175 val_len = max_val + 1;
2176 data_len = max_data;
2179 HeapFree(GetProcessHeap(), 0, value);
2180 HeapFree(GetProcessHeap(), 0, data);
2181 RegCloseKey(hkey);
2185 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2186 if (!psub) {
2187 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2188 goto skip_internal;
2191 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2193 const FontSubst *psub2;
2194 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2196 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2198 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2199 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2201 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2202 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2204 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2206 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2210 skip_internal:
2212 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2213 that Tahoma has */
2215 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2216 system_font_link->font_name = strdupW(System);
2217 list_init(&system_font_link->links);
2218 memset(&fs, 0, sizeof(fs));
2220 face = find_face_from_filename(tahoma_ttf, Tahoma);
2221 if(face)
2223 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2224 child_font->face = face;
2225 child_font->font = NULL;
2226 fs.fsCsb[0] |= face->fs.fsCsb[0];
2227 fs.fsCsb[1] |= face->fs.fsCsb[1];
2228 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2229 list_add_tail(&system_font_link->links, &child_font->entry);
2231 font_link = find_font_link(Tahoma);
2232 if (font_link != NULL)
2234 CHILD_FONT *font_link_entry;
2235 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2237 CHILD_FONT *new_child;
2238 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2239 new_child->face = font_link_entry->face;
2240 new_child->font = NULL;
2241 fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2242 fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2243 list_add_tail(&system_font_link->links, &new_child->entry);
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 font_link = find_font_link(font_name);
3797 if (font_link != NULL)
3799 TRACE("found entry in system list\n");
3800 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3802 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3803 new_child->face = font_link_entry->face;
3804 new_child->font = NULL;
3805 list_add_tail(&font->child_fonts, &new_child->entry);
3806 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3808 ret = TRUE;
3811 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3812 * Sans Serif. This is how asian windows get default fallbacks for fonts
3814 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3815 font->charset != OEM_CHARSET &&
3816 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3818 font_link = find_font_link(szDefaultFallbackLink);
3819 if (font_link != NULL)
3821 TRACE("found entry in default fallback list\n");
3822 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3824 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3825 new_child->face = font_link_entry->face;
3826 new_child->font = NULL;
3827 list_add_tail(&font->child_fonts, &new_child->entry);
3828 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3830 ret = TRUE;
3834 return ret;
3837 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3839 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3841 if (pFT_Set_Charmap)
3843 FT_Int i;
3844 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3846 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3848 for (i = 0; i < ft_face->num_charmaps; i++)
3850 if (ft_face->charmaps[i]->encoding == encoding)
3852 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3853 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3855 switch (ft_face->charmaps[i]->platform_id)
3857 default:
3858 cmap_def = ft_face->charmaps[i];
3859 break;
3860 case 0: /* Apple Unicode */
3861 cmap0 = ft_face->charmaps[i];
3862 break;
3863 case 1: /* Macintosh */
3864 cmap1 = ft_face->charmaps[i];
3865 break;
3866 case 2: /* ISO */
3867 cmap2 = ft_face->charmaps[i];
3868 break;
3869 case 3: /* Microsoft */
3870 cmap3 = ft_face->charmaps[i];
3871 break;
3875 if (cmap3) /* prefer Microsoft cmap table */
3876 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3877 else if (cmap1)
3878 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3879 else if (cmap2)
3880 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3881 else if (cmap0)
3882 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3883 else if (cmap_def)
3884 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3886 return ft_err == FT_Err_Ok;
3889 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3893 /*************************************************************
3894 * freetype_CreateDC
3896 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3897 LPCWSTR output, const DEVMODEW *devmode )
3899 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3901 if (!physdev) return FALSE;
3902 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3903 return TRUE;
3907 /*************************************************************
3908 * freetype_DeleteDC
3910 static BOOL freetype_DeleteDC( PHYSDEV dev )
3912 struct freetype_physdev *physdev = get_freetype_dev( dev );
3913 HeapFree( GetProcessHeap(), 0, physdev );
3914 return TRUE;
3918 /*************************************************************
3919 * freetype_SelectFont
3921 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3923 struct freetype_physdev *physdev = get_freetype_dev( dev );
3924 GdiFont *ret;
3925 Face *face, *best, *best_bitmap;
3926 Family *family, *last_resort_family;
3927 struct list *family_elem_ptr, *face_elem_ptr;
3928 INT height, width = 0;
3929 unsigned int score = 0, new_score;
3930 signed int diff = 0, newdiff;
3931 BOOL bd, it, can_use_bitmap, want_vertical;
3932 LOGFONTW lf;
3933 CHARSETINFO csi;
3934 HFONTLIST *hflist;
3935 FMAT2 dcmat;
3936 FontSubst *psub = NULL;
3937 DC *dc = get_dc_ptr( dev->hdc );
3939 if (!hfont) /* notification that the font has been changed by another driver */
3941 dc->gdiFont = NULL;
3942 physdev->font = NULL;
3943 release_dc_ptr( dc );
3944 return 0;
3947 GetObjectW( hfont, sizeof(lf), &lf );
3948 lf.lfWidth = abs(lf.lfWidth);
3950 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3952 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3953 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3954 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3955 lf.lfEscapement);
3957 if(dc->GraphicsMode == GM_ADVANCED)
3959 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3960 /* Try to avoid not necessary glyph transformations */
3961 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3963 lf.lfHeight *= fabs(dcmat.eM11);
3964 lf.lfWidth *= fabs(dcmat.eM11);
3965 dcmat.eM11 = dcmat.eM22 = 1.0;
3968 else
3970 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3971 font scaling abilities. */
3972 dcmat.eM11 = dcmat.eM22 = 1.0;
3973 dcmat.eM21 = dcmat.eM12 = 0;
3974 if (dc->vport2WorldValid)
3976 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
3977 lf.lfOrientation = -lf.lfOrientation;
3978 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
3979 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
3983 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3984 dcmat.eM21, dcmat.eM22);
3986 GDI_CheckNotLock();
3987 EnterCriticalSection( &freetype_cs );
3989 /* check the cache first */
3990 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3991 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3992 goto done;
3995 if(list_empty(&font_list)) /* No fonts installed */
3997 TRACE("No fonts installed\n");
3998 goto done;
4001 TRACE("not in cache\n");
4002 ret = alloc_font();
4004 ret->font_desc.matrix = dcmat;
4005 ret->font_desc.lf = lf;
4006 ret->font_desc.can_use_bitmap = can_use_bitmap;
4007 calc_hash(&ret->font_desc);
4008 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4009 hflist->hfont = hfont;
4010 list_add_head(&ret->hfontlist, &hflist->entry);
4012 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4013 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4014 original value lfCharSet. Note this is a special case for
4015 Symbol and doesn't happen at least for "Wingdings*" */
4017 if(!strcmpiW(lf.lfFaceName, SymbolW))
4018 lf.lfCharSet = SYMBOL_CHARSET;
4020 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4021 switch(lf.lfCharSet) {
4022 case DEFAULT_CHARSET:
4023 csi.fs.fsCsb[0] = 0;
4024 break;
4025 default:
4026 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4027 csi.fs.fsCsb[0] = 0;
4028 break;
4032 family = NULL;
4033 if(lf.lfFaceName[0] != '\0') {
4034 SYSTEM_LINKS *font_link;
4035 CHILD_FONT *font_link_entry;
4036 LPWSTR FaceName = lf.lfFaceName;
4038 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4040 if(psub) {
4041 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4042 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4043 if (psub->to.charset != -1)
4044 lf.lfCharSet = psub->to.charset;
4047 /* We want a match on name and charset or just name if
4048 charset was DEFAULT_CHARSET. If the latter then
4049 we fixup the returned charset later in get_nearest_charset
4050 where we'll either use the charset of the current ansi codepage
4051 or if that's unavailable the first charset that the font supports.
4053 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4054 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4055 if (!strcmpiW(family->FamilyName, FaceName) ||
4056 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4058 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4059 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4060 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4061 if(face->scalable || can_use_bitmap)
4062 goto found;
4067 /* Search by full face name. */
4068 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4069 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4070 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4071 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4072 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4073 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
4075 if(face->scalable || can_use_bitmap)
4076 goto found_face;
4082 * Try check the SystemLink list first for a replacement font.
4083 * We may find good replacements there.
4085 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4087 if(!strcmpiW(font_link->font_name, FaceName) ||
4088 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4090 TRACE("found entry in system list\n");
4091 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4093 face = font_link_entry->face;
4094 family = face->family;
4095 if(csi.fs.fsCsb[0] &
4096 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4098 if(face->scalable || can_use_bitmap)
4099 goto found;
4106 psub = NULL; /* substitution is no more relevant */
4108 /* If requested charset was DEFAULT_CHARSET then try using charset
4109 corresponding to the current ansi codepage */
4110 if (!csi.fs.fsCsb[0])
4112 INT acp = GetACP();
4113 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4114 FIXME("TCI failed on codepage %d\n", acp);
4115 csi.fs.fsCsb[0] = 0;
4116 } else
4117 lf.lfCharSet = csi.ciCharset;
4120 want_vertical = (lf.lfFaceName[0] == '@');
4122 /* Face families are in the top 4 bits of lfPitchAndFamily,
4123 so mask with 0xF0 before testing */
4125 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4126 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4127 strcpyW(lf.lfFaceName, defFixed);
4128 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4129 strcpyW(lf.lfFaceName, defSerif);
4130 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4131 strcpyW(lf.lfFaceName, defSans);
4132 else
4133 strcpyW(lf.lfFaceName, defSans);
4134 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4135 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4136 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4137 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4138 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4139 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4140 if(face->scalable || can_use_bitmap)
4141 goto found;
4146 last_resort_family = NULL;
4147 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4148 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4149 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4150 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4151 if(face->vertical == want_vertical &&
4152 (csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))) {
4153 if(face->scalable)
4154 goto found;
4155 if(can_use_bitmap && !last_resort_family)
4156 last_resort_family = family;
4161 if(last_resort_family) {
4162 family = last_resort_family;
4163 csi.fs.fsCsb[0] = 0;
4164 goto found;
4167 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4168 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4169 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4170 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4171 if(face->scalable && face->vertical == want_vertical) {
4172 csi.fs.fsCsb[0] = 0;
4173 WARN("just using first face for now\n");
4174 goto found;
4176 if(can_use_bitmap && !last_resort_family)
4177 last_resort_family = family;
4180 if(!last_resort_family) {
4181 FIXME("can't find a single appropriate font - bailing\n");
4182 free_font(ret);
4183 ret = NULL;
4184 goto done;
4187 WARN("could only find a bitmap font - this will probably look awful!\n");
4188 family = last_resort_family;
4189 csi.fs.fsCsb[0] = 0;
4191 found:
4192 it = lf.lfItalic ? 1 : 0;
4193 bd = lf.lfWeight > 550 ? 1 : 0;
4195 height = lf.lfHeight;
4197 face = best = best_bitmap = NULL;
4198 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4200 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4202 BOOL italic, bold;
4204 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4205 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4206 new_score = (italic ^ it) + (bold ^ bd);
4207 if(!best || new_score <= score)
4209 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4210 italic, bold, it, bd);
4211 score = new_score;
4212 best = face;
4213 if(best->scalable && score == 0) break;
4214 if(!best->scalable)
4216 if(height > 0)
4217 newdiff = height - (signed int)(best->size.height);
4218 else
4219 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4220 if(!best_bitmap || new_score < score ||
4221 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4223 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4224 diff = newdiff;
4225 best_bitmap = best;
4226 if(score == 0 && diff == 0) break;
4232 if(best)
4233 face = best->scalable ? best : best_bitmap;
4234 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4235 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4237 found_face:
4238 height = lf.lfHeight;
4240 ret->fs = face->fs;
4242 if(csi.fs.fsCsb[0]) {
4243 ret->charset = lf.lfCharSet;
4244 ret->codepage = csi.ciACP;
4246 else
4247 ret->charset = get_nearest_charset(face, &ret->codepage);
4249 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4250 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4252 ret->aveWidth = height ? lf.lfWidth : 0;
4254 if(!face->scalable) {
4255 /* Windows uses integer scaling factors for bitmap fonts */
4256 INT scale, scaled_height;
4257 GdiFont *cachedfont;
4259 /* FIXME: rotation of bitmap fonts is ignored */
4260 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4261 if (ret->aveWidth)
4262 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4263 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4264 dcmat.eM11 = dcmat.eM22 = 1.0;
4265 /* As we changed the matrix, we need to search the cache for the font again,
4266 * otherwise we might explode the cache. */
4267 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4268 TRACE("Found cached font after non-scalable matrix rescale!\n");
4269 free_font( ret );
4270 ret = cachedfont;
4271 goto done;
4273 calc_hash(&ret->font_desc);
4275 if (height != 0) height = diff;
4276 height += face->size.height;
4278 scale = (height + face->size.height - 1) / face->size.height;
4279 scaled_height = scale * face->size.height;
4280 /* Only jump to the next height if the difference <= 25% original height */
4281 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4282 /* The jump between unscaled and doubled is delayed by 1 */
4283 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4284 ret->scale_y = scale;
4286 width = face->size.x_ppem >> 6;
4287 height = face->size.y_ppem >> 6;
4289 else
4290 ret->scale_y = 1.0;
4291 TRACE("font scale y: %f\n", ret->scale_y);
4293 ret->ft_face = OpenFontFace(ret, face, width, height);
4295 if (!ret->ft_face)
4297 free_font( ret );
4298 ret = NULL;
4299 goto done;
4302 ret->ntmFlags = face->ntmFlags;
4304 if (ret->charset == SYMBOL_CHARSET &&
4305 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4306 /* No ops */
4308 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4309 /* No ops */
4311 else {
4312 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4315 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4316 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4317 ret->underline = lf.lfUnderline ? 0xff : 0;
4318 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4319 create_child_font_list(ret);
4321 if (face->vertical) /* We need to try to load the GSUB table */
4323 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4324 if (length != GDI_ERROR)
4326 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4327 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4328 TRACE("Loaded GSUB table of %i bytes\n",length);
4332 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4334 add_to_cache(ret);
4335 done:
4336 if (ret)
4338 dc->gdiFont = ret;
4339 physdev->font = ret;
4341 LeaveCriticalSection( &freetype_cs );
4342 release_dc_ptr( dc );
4343 return ret ? hfont : 0;
4346 static void dump_gdi_font_list(void)
4348 GdiFont *gdiFont;
4349 struct list *elem_ptr;
4351 TRACE("---------- gdiFont Cache ----------\n");
4352 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4353 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4354 TRACE("gdiFont=%p %s %d\n",
4355 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4358 TRACE("---------- Unused gdiFont Cache ----------\n");
4359 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4360 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4361 TRACE("gdiFont=%p %s %d\n",
4362 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4365 TRACE("---------- Child gdiFont Cache ----------\n");
4366 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4367 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4368 TRACE("gdiFont=%p %s %d\n",
4369 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4373 /*************************************************************
4374 * WineEngDestroyFontInstance
4376 * free the gdiFont associated with this handle
4379 BOOL WineEngDestroyFontInstance(HFONT handle)
4381 GdiFont *gdiFont;
4382 HFONTLIST *hflist;
4383 BOOL ret = FALSE;
4384 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4385 int i = 0;
4387 GDI_CheckNotLock();
4388 EnterCriticalSection( &freetype_cs );
4390 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4392 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4393 while(hfontlist_elem_ptr) {
4394 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4395 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4396 if(hflist->hfont == handle) {
4397 TRACE("removing child font %p from child list\n", gdiFont);
4398 list_remove(&gdiFont->entry);
4399 LeaveCriticalSection( &freetype_cs );
4400 return TRUE;
4405 TRACE("destroying hfont=%p\n", handle);
4406 if(TRACE_ON(font))
4407 dump_gdi_font_list();
4409 font_elem_ptr = list_head(&gdi_font_list);
4410 while(font_elem_ptr) {
4411 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4412 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4414 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4415 while(hfontlist_elem_ptr) {
4416 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4417 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4418 if(hflist->hfont == handle) {
4419 list_remove(&hflist->entry);
4420 HeapFree(GetProcessHeap(), 0, hflist);
4421 ret = TRUE;
4424 if(list_empty(&gdiFont->hfontlist)) {
4425 TRACE("Moving to Unused list\n");
4426 list_remove(&gdiFont->entry);
4427 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4432 font_elem_ptr = list_head(&unused_gdi_font_list);
4433 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4434 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4435 while(font_elem_ptr) {
4436 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4437 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4438 TRACE("freeing %p\n", gdiFont);
4439 list_remove(&gdiFont->entry);
4440 free_font(gdiFont);
4442 LeaveCriticalSection( &freetype_cs );
4443 return ret;
4446 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4448 HRSRC rsrc;
4449 HGLOBAL hMem;
4450 WCHAR *p;
4451 int i;
4453 id += IDS_FIRST_SCRIPT;
4454 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4455 if (!rsrc) return 0;
4456 hMem = LoadResource( gdi32_module, rsrc );
4457 if (!hMem) return 0;
4459 p = LockResource( hMem );
4460 id &= 0x000f;
4461 while (id--) p += *p + 1;
4463 i = min(LF_FACESIZE - 1, *p);
4464 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4465 buffer[i] = 0;
4466 return i;
4470 /***************************************************
4471 * create_enum_charset_list
4473 * This function creates charset enumeration list because in DEFAULT_CHARSET
4474 * case, the ANSI codepage's charset takes precedence over other charsets.
4475 * This function works as a filter other than DEFAULT_CHARSET case.
4477 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4479 CHARSETINFO csi;
4480 DWORD n = 0;
4482 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4483 csi.fs.fsCsb[0] != 0) {
4484 list->element[n].mask = csi.fs.fsCsb[0];
4485 list->element[n].charset = csi.ciCharset;
4486 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4487 n++;
4489 else { /* charset is DEFAULT_CHARSET or invalid. */
4490 INT acp, i;
4492 /* Set the current codepage's charset as the first element. */
4493 acp = GetACP();
4494 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4495 csi.fs.fsCsb[0] != 0) {
4496 list->element[n].mask = csi.fs.fsCsb[0];
4497 list->element[n].charset = csi.ciCharset;
4498 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4499 n++;
4502 /* Fill out left elements. */
4503 for (i = 0; i < 32; i++) {
4504 FONTSIGNATURE fs;
4505 fs.fsCsb[0] = 1L << i;
4506 fs.fsCsb[1] = 0;
4507 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4508 continue; /* skip, already added. */
4509 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4510 continue; /* skip, this is an invalid fsCsb bit. */
4512 list->element[n].mask = fs.fsCsb[0];
4513 list->element[n].charset = csi.ciCharset;
4514 load_script_name( i, list->element[n].name );
4515 n++;
4518 list->total = n;
4520 return n;
4523 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4524 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4526 GdiFont *font;
4527 LONG width, height;
4529 if (face->cached_enum_data)
4531 TRACE("Cached\n");
4532 *pelf = face->cached_enum_data->elf;
4533 *pntm = face->cached_enum_data->ntm;
4534 *ptype = face->cached_enum_data->type;
4535 return;
4538 font = alloc_font();
4540 if(face->scalable) {
4541 height = -2048; /* 2048 is the most common em size */
4542 width = 0;
4543 } else {
4544 height = face->size.y_ppem >> 6;
4545 width = face->size.x_ppem >> 6;
4547 font->scale_y = 1.0;
4549 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4551 free_font(font);
4552 return;
4555 font->name = strdupW(face->family->FamilyName);
4556 font->ntmFlags = face->ntmFlags;
4558 if (get_outline_text_metrics(font))
4560 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4562 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4564 lstrcpynW(pelf->elfLogFont.lfFaceName,
4565 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4566 LF_FACESIZE);
4567 lstrcpynW(pelf->elfFullName,
4568 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4569 LF_FULLFACESIZE);
4570 lstrcpynW(pelf->elfStyle,
4571 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4572 LF_FACESIZE);
4574 else
4576 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4578 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4580 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4581 if (face->FullName)
4582 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4583 else
4584 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4585 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4588 pntm->ntmTm.ntmFlags = face->ntmFlags;
4589 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4590 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4591 pntm->ntmFontSig = face->fs;
4593 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4595 pelf->elfLogFont.lfEscapement = 0;
4596 pelf->elfLogFont.lfOrientation = 0;
4597 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4598 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4599 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4600 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4601 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4602 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4603 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4604 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4605 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4606 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4607 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4609 *ptype = 0;
4610 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4611 *ptype |= TRUETYPE_FONTTYPE;
4612 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4613 *ptype |= DEVICE_FONTTYPE;
4614 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4615 *ptype |= RASTER_FONTTYPE;
4617 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4618 if (face->cached_enum_data)
4620 face->cached_enum_data->elf = *pelf;
4621 face->cached_enum_data->ntm = *pntm;
4622 face->cached_enum_data->type = *ptype;
4625 free_font(font);
4628 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4630 struct list *face_elem_ptr;
4632 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4634 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4636 static const WCHAR spaceW[] = { ' ',0 };
4637 WCHAR full_family_name[LF_FULLFACESIZE];
4638 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4640 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4642 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4643 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4644 continue;
4647 strcpyW(full_family_name, family->FamilyName);
4648 strcatW(full_family_name, spaceW);
4649 strcatW(full_family_name, face->StyleName);
4650 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4653 return FALSE;
4656 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4658 static const WCHAR spaceW[] = { ' ',0 };
4659 WCHAR full_family_name[LF_FULLFACESIZE];
4661 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4663 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4665 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4666 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4667 return FALSE;
4670 strcpyW(full_family_name, face->family->FamilyName);
4671 strcatW(full_family_name, spaceW);
4672 strcatW(full_family_name, face->StyleName);
4673 return !strcmpiW(lf->lfFaceName, full_family_name);
4676 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4677 FONTENUMPROCW proc, LPARAM lparam)
4679 ENUMLOGFONTEXW elf;
4680 NEWTEXTMETRICEXW ntm;
4681 DWORD type = 0;
4682 int i;
4684 GetEnumStructs(face, &elf, &ntm, &type);
4685 for(i = 0; i < list->total; i++) {
4686 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4687 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4688 load_script_name( IDS_OEM_DOS, elf.elfScript );
4689 i = list->total; /* break out of loop after enumeration */
4690 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4691 continue;
4692 else {
4693 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4694 strcpyW(elf.elfScript, list->element[i].name);
4695 if (!elf.elfScript[0])
4696 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4698 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4699 debugstr_w(elf.elfLogFont.lfFaceName),
4700 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4701 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4702 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4703 ntm.ntmTm.ntmFlags);
4704 /* release section before callback (FIXME) */
4705 LeaveCriticalSection( &freetype_cs );
4706 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4707 EnterCriticalSection( &freetype_cs );
4709 return TRUE;
4712 /*************************************************************
4713 * freetype_EnumFonts
4715 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4717 Family *family;
4718 Face *face;
4719 struct list *family_elem_ptr, *face_elem_ptr;
4720 LOGFONTW lf;
4721 struct enum_charset_list enum_charsets;
4723 if (!plf)
4725 lf.lfCharSet = DEFAULT_CHARSET;
4726 lf.lfPitchAndFamily = 0;
4727 lf.lfFaceName[0] = 0;
4728 plf = &lf;
4731 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4733 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4735 GDI_CheckNotLock();
4736 EnterCriticalSection( &freetype_cs );
4737 if(plf->lfFaceName[0]) {
4738 FontSubst *psub;
4739 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4741 if(psub) {
4742 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4743 debugstr_w(psub->to.name));
4744 lf = *plf;
4745 strcpyW(lf.lfFaceName, psub->to.name);
4746 plf = &lf;
4749 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4750 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4751 if(family_matches(family, plf)) {
4752 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4753 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4754 if (!face_matches(face, plf)) continue;
4755 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4759 } else {
4760 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4761 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4762 face_elem_ptr = list_head(&family->faces);
4763 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4764 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4767 LeaveCriticalSection( &freetype_cs );
4768 return TRUE;
4771 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4773 pt->x.value = vec->x >> 6;
4774 pt->x.fract = (vec->x & 0x3f) << 10;
4775 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4776 pt->y.value = vec->y >> 6;
4777 pt->y.fract = (vec->y & 0x3f) << 10;
4778 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4779 return;
4782 /***************************************************
4783 * According to the MSDN documentation on WideCharToMultiByte,
4784 * certain codepages cannot set the default_used parameter.
4785 * This returns TRUE if the codepage can set that parameter, false else
4786 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4788 static BOOL codepage_sets_default_used(UINT codepage)
4790 switch (codepage)
4792 case CP_UTF7:
4793 case CP_UTF8:
4794 case CP_SYMBOL:
4795 return FALSE;
4796 default:
4797 return TRUE;
4802 * GSUB Table handling functions
4805 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4807 const GSUB_CoverageFormat1* cf1;
4809 cf1 = table;
4811 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4813 int count = GET_BE_WORD(cf1->GlyphCount);
4814 int i;
4815 TRACE("Coverage Format 1, %i glyphs\n",count);
4816 for (i = 0; i < count; i++)
4817 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4818 return i;
4819 return -1;
4821 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4823 const GSUB_CoverageFormat2* cf2;
4824 int i;
4825 int count;
4826 cf2 = (const GSUB_CoverageFormat2*)cf1;
4828 count = GET_BE_WORD(cf2->RangeCount);
4829 TRACE("Coverage Format 2, %i ranges\n",count);
4830 for (i = 0; i < count; i++)
4832 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4833 return -1;
4834 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4835 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4837 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4838 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4841 return -1;
4843 else
4844 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4846 return -1;
4849 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4851 const GSUB_ScriptList *script;
4852 const GSUB_Script *deflt = NULL;
4853 int i;
4854 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4856 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4857 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4859 const GSUB_Script *scr;
4860 int offset;
4862 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4863 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4865 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4866 return scr;
4867 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4868 deflt = scr;
4870 return deflt;
4873 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4875 int i;
4876 int offset;
4877 const GSUB_LangSys *Lang;
4879 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4881 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4883 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4884 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4886 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4887 return Lang;
4889 offset = GET_BE_WORD(script->DefaultLangSys);
4890 if (offset)
4892 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4893 return Lang;
4895 return NULL;
4898 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4900 int i;
4901 const GSUB_FeatureList *feature;
4902 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4904 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4905 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4907 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4908 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4910 const GSUB_Feature *feat;
4911 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4912 return feat;
4915 return NULL;
4918 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4920 int i;
4921 int offset;
4922 const GSUB_LookupList *lookup;
4923 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4925 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4926 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4928 const GSUB_LookupTable *look;
4929 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4930 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4931 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4932 if (GET_BE_WORD(look->LookupType) != 1)
4933 FIXME("We only handle SubType 1\n");
4934 else
4936 int j;
4938 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4940 const GSUB_SingleSubstFormat1 *ssf1;
4941 offset = GET_BE_WORD(look->SubTable[j]);
4942 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4943 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4945 int offset = GET_BE_WORD(ssf1->Coverage);
4946 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4947 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4949 TRACE(" Glyph 0x%x ->",glyph);
4950 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4951 TRACE(" 0x%x\n",glyph);
4954 else
4956 const GSUB_SingleSubstFormat2 *ssf2;
4957 INT index;
4958 INT offset;
4960 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4961 offset = GET_BE_WORD(ssf1->Coverage);
4962 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4963 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4964 TRACE(" Coverage index %i\n",index);
4965 if (index != -1)
4967 TRACE(" Glyph is 0x%x ->",glyph);
4968 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4969 TRACE("0x%x\n",glyph);
4975 return glyph;
4978 static const char* get_opentype_script(const GdiFont *font)
4981 * I am not sure if this is the correct way to generate our script tag
4984 switch (font->charset)
4986 case ANSI_CHARSET: return "latn";
4987 case BALTIC_CHARSET: return "latn"; /* ?? */
4988 case CHINESEBIG5_CHARSET: return "hani";
4989 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4990 case GB2312_CHARSET: return "hani";
4991 case GREEK_CHARSET: return "grek";
4992 case HANGUL_CHARSET: return "hang";
4993 case RUSSIAN_CHARSET: return "cyrl";
4994 case SHIFTJIS_CHARSET: return "kana";
4995 case TURKISH_CHARSET: return "latn"; /* ?? */
4996 case VIETNAMESE_CHARSET: return "latn";
4997 case JOHAB_CHARSET: return "latn"; /* ?? */
4998 case ARABIC_CHARSET: return "arab";
4999 case HEBREW_CHARSET: return "hebr";
5000 case THAI_CHARSET: return "thai";
5001 default: return "latn";
5005 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5007 const GSUB_Header *header;
5008 const GSUB_Script *script;
5009 const GSUB_LangSys *language;
5010 const GSUB_Feature *feature;
5012 if (!font->GSUB_Table)
5013 return glyph;
5015 header = font->GSUB_Table;
5017 script = GSUB_get_script_table(header, get_opentype_script(font));
5018 if (!script)
5020 TRACE("Script not found\n");
5021 return glyph;
5023 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5024 if (!language)
5026 TRACE("Language not found\n");
5027 return glyph;
5029 feature = GSUB_get_feature(header, language, "vrt2");
5030 if (!feature)
5031 feature = GSUB_get_feature(header, language, "vert");
5032 if (!feature)
5034 TRACE("vrt2/vert feature not found\n");
5035 return glyph;
5037 return GSUB_apply_feature(header, feature, glyph);
5040 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5042 FT_UInt glyphId;
5044 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5045 WCHAR wc = (WCHAR)glyph;
5046 BOOL default_used;
5047 BOOL *default_used_pointer;
5048 FT_UInt ret;
5049 char buf;
5050 default_used_pointer = NULL;
5051 default_used = FALSE;
5052 if (codepage_sets_default_used(font->codepage))
5053 default_used_pointer = &default_used;
5054 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5055 ret = 0;
5056 else
5057 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5058 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5059 return ret;
5062 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5064 if (glyph < 0x100) glyph += 0xf000;
5065 /* there is a number of old pre-Unicode "broken" TTFs, which
5066 do have symbols at U+00XX instead of U+f0XX */
5067 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5068 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5070 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5072 return glyphId;
5075 /*************************************************************
5076 * freetype_GetGlyphIndices
5078 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5080 struct freetype_physdev *physdev = get_freetype_dev( dev );
5081 int i;
5082 WORD default_char;
5083 BOOL got_default = FALSE;
5085 if (!physdev->font)
5087 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5088 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5091 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5093 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5094 got_default = TRUE;
5097 GDI_CheckNotLock();
5098 EnterCriticalSection( &freetype_cs );
5100 for(i = 0; i < count; i++)
5102 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5103 if (pgi[i] == 0)
5105 if (!got_default)
5107 if (FT_IS_SFNT(physdev->font->ft_face))
5109 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5110 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5112 else
5114 TEXTMETRICW textm;
5115 get_text_metrics(physdev->font, &textm);
5116 default_char = textm.tmDefaultChar;
5118 got_default = TRUE;
5120 pgi[i] = default_char;
5123 LeaveCriticalSection( &freetype_cs );
5124 return count;
5127 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5129 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5130 return !memcmp(matrix, &identity, sizeof(FMAT2));
5133 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5135 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5136 return !memcmp(matrix, &identity, sizeof(MAT2));
5139 static inline BYTE get_max_level( UINT format )
5141 switch( format )
5143 case GGO_GRAY2_BITMAP: return 4;
5144 case GGO_GRAY4_BITMAP: return 16;
5145 case GGO_GRAY8_BITMAP: return 64;
5147 return 255;
5150 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5152 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5153 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5154 const MAT2* lpmat)
5156 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5157 FT_Face ft_face = incoming_font->ft_face;
5158 GdiFont *font = incoming_font;
5159 FT_UInt glyph_index;
5160 DWORD width, height, pitch, needed = 0;
5161 FT_Bitmap ft_bitmap;
5162 FT_Error err;
5163 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5164 FT_Angle angle = 0;
5165 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5166 double widthRatio = 1.0;
5167 FT_Matrix transMat = identityMat;
5168 FT_Matrix transMatUnrotated;
5169 BOOL needsTransform = FALSE;
5170 BOOL tategaki = (font->GSUB_Table != NULL);
5171 UINT original_index;
5173 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5174 buflen, buf, lpmat);
5176 TRACE("font transform %f %f %f %f\n",
5177 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5178 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5180 if(format & GGO_GLYPH_INDEX) {
5181 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5182 original_index = glyph;
5183 format &= ~GGO_GLYPH_INDEX;
5184 } else {
5185 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5186 ft_face = font->ft_face;
5187 original_index = glyph_index;
5190 if(format & GGO_UNHINTED) {
5191 load_flags |= FT_LOAD_NO_HINTING;
5192 format &= ~GGO_UNHINTED;
5195 /* tategaki never appears to happen to lower glyph index */
5196 if (glyph_index < TATEGAKI_LOWER_BOUND )
5197 tategaki = FALSE;
5199 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5200 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5201 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5202 font->gmsize * sizeof(GM*));
5203 } else {
5204 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5205 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5207 *lpgm = FONT_GM(font,original_index)->gm;
5208 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5209 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5210 lpgm->gmCellIncX, lpgm->gmCellIncY);
5211 return 1; /* FIXME */
5215 if (!font->gm[original_index / GM_BLOCK_SIZE])
5216 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5218 /* Scaling factor */
5219 if (font->aveWidth)
5221 TEXTMETRICW tm;
5223 get_text_metrics(font, &tm);
5225 widthRatio = (double)font->aveWidth;
5226 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5228 else
5229 widthRatio = font->scale_y;
5231 /* Scaling transform */
5232 if (widthRatio != 1.0 || font->scale_y != 1.0)
5234 FT_Matrix scaleMat;
5235 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5236 scaleMat.xy = 0;
5237 scaleMat.yx = 0;
5238 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5240 pFT_Matrix_Multiply(&scaleMat, &transMat);
5241 needsTransform = TRUE;
5244 /* Slant transform */
5245 if (font->fake_italic) {
5246 FT_Matrix slantMat;
5248 slantMat.xx = (1 << 16);
5249 slantMat.xy = ((1 << 16) >> 2);
5250 slantMat.yx = 0;
5251 slantMat.yy = (1 << 16);
5252 pFT_Matrix_Multiply(&slantMat, &transMat);
5253 needsTransform = TRUE;
5256 /* Rotation transform */
5257 transMatUnrotated = transMat;
5258 if(font->orientation && !tategaki) {
5259 FT_Matrix rotationMat;
5260 FT_Vector vecAngle;
5261 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5262 pFT_Vector_Unit(&vecAngle, angle);
5263 rotationMat.xx = vecAngle.x;
5264 rotationMat.xy = -vecAngle.y;
5265 rotationMat.yx = -rotationMat.xy;
5266 rotationMat.yy = rotationMat.xx;
5268 pFT_Matrix_Multiply(&rotationMat, &transMat);
5269 needsTransform = TRUE;
5272 /* World transform */
5273 if (!is_identity_FMAT2(&font->font_desc.matrix))
5275 FT_Matrix worldMat;
5276 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5277 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5278 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5279 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5280 pFT_Matrix_Multiply(&worldMat, &transMat);
5281 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5282 needsTransform = TRUE;
5285 /* Extra transformation specified by caller */
5286 if (!is_identity_MAT2(lpmat))
5288 FT_Matrix extraMat;
5289 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5290 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5291 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5292 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5293 pFT_Matrix_Multiply(&extraMat, &transMat);
5294 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5295 needsTransform = TRUE;
5298 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5299 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5300 format == GGO_GRAY8_BITMAP))
5302 load_flags |= FT_LOAD_NO_BITMAP;
5305 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5307 if(err) {
5308 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5309 return GDI_ERROR;
5312 if(!needsTransform) {
5313 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5314 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5315 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5317 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5318 bottom = (ft_face->glyph->metrics.horiBearingY -
5319 ft_face->glyph->metrics.height) & -64;
5320 lpgm->gmCellIncX = adv;
5321 lpgm->gmCellIncY = 0;
5322 } else {
5323 INT xc, yc;
5324 FT_Vector vec;
5326 left = right = 0;
5328 for(xc = 0; xc < 2; xc++) {
5329 for(yc = 0; yc < 2; yc++) {
5330 vec.x = (ft_face->glyph->metrics.horiBearingX +
5331 xc * ft_face->glyph->metrics.width);
5332 vec.y = ft_face->glyph->metrics.horiBearingY -
5333 yc * ft_face->glyph->metrics.height;
5334 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5335 pFT_Vector_Transform(&vec, &transMat);
5336 if(xc == 0 && yc == 0) {
5337 left = right = vec.x;
5338 top = bottom = vec.y;
5339 } else {
5340 if(vec.x < left) left = vec.x;
5341 else if(vec.x > right) right = vec.x;
5342 if(vec.y < bottom) bottom = vec.y;
5343 else if(vec.y > top) top = vec.y;
5347 left = left & -64;
5348 right = (right + 63) & -64;
5349 bottom = bottom & -64;
5350 top = (top + 63) & -64;
5352 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5353 vec.x = ft_face->glyph->metrics.horiAdvance;
5354 vec.y = 0;
5355 pFT_Vector_Transform(&vec, &transMat);
5356 lpgm->gmCellIncX = (vec.x+63) >> 6;
5357 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5359 vec.x = ft_face->glyph->metrics.horiAdvance;
5360 vec.y = 0;
5361 pFT_Vector_Transform(&vec, &transMatUnrotated);
5362 adv = (vec.x+63) >> 6;
5365 lsb = left >> 6;
5366 bbx = (right - left) >> 6;
5367 lpgm->gmBlackBoxX = (right - left) >> 6;
5368 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5369 lpgm->gmptGlyphOrigin.x = left >> 6;
5370 lpgm->gmptGlyphOrigin.y = top >> 6;
5372 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5373 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5374 lpgm->gmCellIncX, lpgm->gmCellIncY);
5376 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5377 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5379 FONT_GM(font,original_index)->gm = *lpgm;
5380 FONT_GM(font,original_index)->adv = adv;
5381 FONT_GM(font,original_index)->lsb = lsb;
5382 FONT_GM(font,original_index)->bbx = bbx;
5383 FONT_GM(font,original_index)->init = TRUE;
5386 if(format == GGO_METRICS)
5388 return 1; /* FIXME */
5391 if(ft_face->glyph->format != ft_glyph_format_outline &&
5392 (format == GGO_NATIVE || format == GGO_BEZIER))
5394 TRACE("loaded a bitmap\n");
5395 return GDI_ERROR;
5398 switch(format) {
5399 case GGO_BITMAP:
5400 width = lpgm->gmBlackBoxX;
5401 height = lpgm->gmBlackBoxY;
5402 pitch = ((width + 31) >> 5) << 2;
5403 needed = pitch * height;
5405 if(!buf || !buflen) break;
5407 switch(ft_face->glyph->format) {
5408 case ft_glyph_format_bitmap:
5410 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5411 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5412 INT h = ft_face->glyph->bitmap.rows;
5413 while(h--) {
5414 memcpy(dst, src, w);
5415 src += ft_face->glyph->bitmap.pitch;
5416 dst += pitch;
5418 break;
5421 case ft_glyph_format_outline:
5422 ft_bitmap.width = width;
5423 ft_bitmap.rows = height;
5424 ft_bitmap.pitch = pitch;
5425 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5426 ft_bitmap.buffer = buf;
5428 if(needsTransform)
5429 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5431 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5433 /* Note: FreeType will only set 'black' bits for us. */
5434 memset(buf, 0, needed);
5435 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5436 break;
5438 default:
5439 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5440 return GDI_ERROR;
5442 break;
5444 case GGO_GRAY2_BITMAP:
5445 case GGO_GRAY4_BITMAP:
5446 case GGO_GRAY8_BITMAP:
5447 case WINE_GGO_GRAY16_BITMAP:
5449 unsigned int max_level, row, col;
5450 BYTE *start, *ptr;
5452 width = lpgm->gmBlackBoxX;
5453 height = lpgm->gmBlackBoxY;
5454 pitch = (width + 3) / 4 * 4;
5455 needed = pitch * height;
5457 if(!buf || !buflen) break;
5459 max_level = get_max_level( format );
5461 switch(ft_face->glyph->format) {
5462 case ft_glyph_format_bitmap:
5464 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5465 INT h = ft_face->glyph->bitmap.rows;
5466 INT x;
5467 memset( buf, 0, needed );
5468 while(h--) {
5469 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5470 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5471 src += ft_face->glyph->bitmap.pitch;
5472 dst += pitch;
5474 return needed;
5476 case ft_glyph_format_outline:
5478 ft_bitmap.width = width;
5479 ft_bitmap.rows = height;
5480 ft_bitmap.pitch = pitch;
5481 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5482 ft_bitmap.buffer = buf;
5484 if(needsTransform)
5485 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5487 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5489 memset(ft_bitmap.buffer, 0, buflen);
5491 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5493 if (max_level != 255)
5495 for (row = 0, start = buf; row < height; row++)
5497 for (col = 0, ptr = start; col < width; col++, ptr++)
5498 *ptr = (((int)*ptr) * max_level + 128) / 256;
5499 start += pitch;
5502 return needed;
5505 default:
5506 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5507 return GDI_ERROR;
5509 break;
5512 case WINE_GGO_HRGB_BITMAP:
5513 case WINE_GGO_HBGR_BITMAP:
5514 case WINE_GGO_VRGB_BITMAP:
5515 case WINE_GGO_VBGR_BITMAP:
5516 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5518 switch (ft_face->glyph->format)
5520 case FT_GLYPH_FORMAT_BITMAP:
5522 BYTE *src, *dst;
5523 INT src_pitch, x;
5525 width = lpgm->gmBlackBoxX;
5526 height = lpgm->gmBlackBoxY;
5527 pitch = width * 4;
5528 needed = pitch * height;
5530 if (!buf || !buflen) break;
5532 memset(buf, 0, buflen);
5533 dst = buf;
5534 src = ft_face->glyph->bitmap.buffer;
5535 src_pitch = ft_face->glyph->bitmap.pitch;
5537 height = min( height, ft_face->glyph->bitmap.rows );
5538 while ( height-- )
5540 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5542 if ( src[x / 8] & masks[x % 8] )
5543 ((unsigned int *)dst)[x] = ~0u;
5545 src += src_pitch;
5546 dst += pitch;
5549 break;
5552 case FT_GLYPH_FORMAT_OUTLINE:
5554 unsigned int *dst;
5555 BYTE *src;
5556 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5557 INT x_shift, y_shift;
5558 BOOL rgb;
5559 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5560 FT_Render_Mode render_mode =
5561 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5562 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5564 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5566 if ( render_mode == FT_RENDER_MODE_LCD)
5568 lpgm->gmBlackBoxX += 2;
5569 lpgm->gmptGlyphOrigin.x -= 1;
5571 else
5573 lpgm->gmBlackBoxY += 2;
5574 lpgm->gmptGlyphOrigin.y += 1;
5578 width = lpgm->gmBlackBoxX;
5579 height = lpgm->gmBlackBoxY;
5580 pitch = width * 4;
5581 needed = pitch * height;
5583 if (!buf || !buflen) break;
5585 memset(buf, 0, buflen);
5586 dst = buf;
5587 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5589 if ( needsTransform )
5590 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5592 if ( pFT_Library_SetLcdFilter )
5593 pFT_Library_SetLcdFilter( library, lcdfilter );
5594 pFT_Render_Glyph (ft_face->glyph, render_mode);
5596 src = ft_face->glyph->bitmap.buffer;
5597 src_pitch = ft_face->glyph->bitmap.pitch;
5598 src_width = ft_face->glyph->bitmap.width;
5599 src_height = ft_face->glyph->bitmap.rows;
5601 if ( render_mode == FT_RENDER_MODE_LCD)
5603 rgb_interval = 1;
5604 hmul = 3;
5605 vmul = 1;
5607 else
5609 rgb_interval = src_pitch;
5610 hmul = 1;
5611 vmul = 3;
5614 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5615 if ( x_shift < 0 ) x_shift = 0;
5616 if ( x_shift + (src_width / hmul) > width )
5617 x_shift = width - (src_width / hmul);
5619 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5620 if ( y_shift < 0 ) y_shift = 0;
5621 if ( y_shift + (src_height / vmul) > height )
5622 y_shift = height - (src_height / vmul);
5624 dst += x_shift + y_shift * ( pitch / 4 );
5625 while ( src_height )
5627 for ( x = 0; x < src_width / hmul; x++ )
5629 if ( rgb )
5631 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5632 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5633 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5634 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5636 else
5638 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5639 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5640 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5641 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5644 src += src_pitch * vmul;
5645 dst += pitch / 4;
5646 src_height -= vmul;
5649 break;
5652 default:
5653 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5654 return GDI_ERROR;
5657 break;
5659 #else
5660 return GDI_ERROR;
5661 #endif
5663 case GGO_NATIVE:
5665 int contour, point = 0, first_pt;
5666 FT_Outline *outline = &ft_face->glyph->outline;
5667 TTPOLYGONHEADER *pph;
5668 TTPOLYCURVE *ppc;
5669 DWORD pph_start, cpfx, type;
5671 if(buflen == 0) buf = NULL;
5673 if (needsTransform && buf) {
5674 pFT_Outline_Transform(outline, &transMat);
5677 for(contour = 0; contour < outline->n_contours; contour++) {
5678 pph_start = needed;
5679 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5680 first_pt = point;
5681 if(buf) {
5682 pph->dwType = TT_POLYGON_TYPE;
5683 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5685 needed += sizeof(*pph);
5686 point++;
5687 while(point <= outline->contours[contour]) {
5688 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5689 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5690 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5691 cpfx = 0;
5692 do {
5693 if(buf)
5694 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5695 cpfx++;
5696 point++;
5697 } while(point <= outline->contours[contour] &&
5698 (outline->tags[point] & FT_Curve_Tag_On) ==
5699 (outline->tags[point-1] & FT_Curve_Tag_On));
5700 /* At the end of a contour Windows adds the start point, but
5701 only for Beziers */
5702 if(point > outline->contours[contour] &&
5703 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5704 if(buf)
5705 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5706 cpfx++;
5707 } else if(point <= outline->contours[contour] &&
5708 outline->tags[point] & FT_Curve_Tag_On) {
5709 /* add closing pt for bezier */
5710 if(buf)
5711 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5712 cpfx++;
5713 point++;
5715 if(buf) {
5716 ppc->wType = type;
5717 ppc->cpfx = cpfx;
5719 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5721 if(buf)
5722 pph->cb = needed - pph_start;
5724 break;
5726 case GGO_BEZIER:
5728 /* Convert the quadratic Beziers to cubic Beziers.
5729 The parametric eqn for a cubic Bezier is, from PLRM:
5730 r(t) = at^3 + bt^2 + ct + r0
5731 with the control points:
5732 r1 = r0 + c/3
5733 r2 = r1 + (c + b)/3
5734 r3 = r0 + c + b + a
5736 A quadratic Bezier has the form:
5737 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5739 So equating powers of t leads to:
5740 r1 = 2/3 p1 + 1/3 p0
5741 r2 = 2/3 p1 + 1/3 p2
5742 and of course r0 = p0, r3 = p2
5745 int contour, point = 0, first_pt;
5746 FT_Outline *outline = &ft_face->glyph->outline;
5747 TTPOLYGONHEADER *pph;
5748 TTPOLYCURVE *ppc;
5749 DWORD pph_start, cpfx, type;
5750 FT_Vector cubic_control[4];
5751 if(buflen == 0) buf = NULL;
5753 if (needsTransform && buf) {
5754 pFT_Outline_Transform(outline, &transMat);
5757 for(contour = 0; contour < outline->n_contours; contour++) {
5758 pph_start = needed;
5759 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5760 first_pt = point;
5761 if(buf) {
5762 pph->dwType = TT_POLYGON_TYPE;
5763 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5765 needed += sizeof(*pph);
5766 point++;
5767 while(point <= outline->contours[contour]) {
5768 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5769 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5770 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5771 cpfx = 0;
5772 do {
5773 if(type == TT_PRIM_LINE) {
5774 if(buf)
5775 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5776 cpfx++;
5777 point++;
5778 } else {
5779 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5780 so cpfx = 3n */
5782 /* FIXME: Possible optimization in endpoint calculation
5783 if there are two consecutive curves */
5784 cubic_control[0] = outline->points[point-1];
5785 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5786 cubic_control[0].x += outline->points[point].x + 1;
5787 cubic_control[0].y += outline->points[point].y + 1;
5788 cubic_control[0].x >>= 1;
5789 cubic_control[0].y >>= 1;
5791 if(point+1 > outline->contours[contour])
5792 cubic_control[3] = outline->points[first_pt];
5793 else {
5794 cubic_control[3] = outline->points[point+1];
5795 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5796 cubic_control[3].x += outline->points[point].x + 1;
5797 cubic_control[3].y += outline->points[point].y + 1;
5798 cubic_control[3].x >>= 1;
5799 cubic_control[3].y >>= 1;
5802 /* r1 = 1/3 p0 + 2/3 p1
5803 r2 = 1/3 p2 + 2/3 p1 */
5804 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5805 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5806 cubic_control[2] = cubic_control[1];
5807 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5808 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5809 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5810 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5811 if(buf) {
5812 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5813 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5814 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5816 cpfx += 3;
5817 point++;
5819 } while(point <= outline->contours[contour] &&
5820 (outline->tags[point] & FT_Curve_Tag_On) ==
5821 (outline->tags[point-1] & FT_Curve_Tag_On));
5822 /* At the end of a contour Windows adds the start point,
5823 but only for Beziers and we've already done that.
5825 if(point <= outline->contours[contour] &&
5826 outline->tags[point] & FT_Curve_Tag_On) {
5827 /* This is the closing pt of a bezier, but we've already
5828 added it, so just inc point and carry on */
5829 point++;
5831 if(buf) {
5832 ppc->wType = type;
5833 ppc->cpfx = cpfx;
5835 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5837 if(buf)
5838 pph->cb = needed - pph_start;
5840 break;
5843 default:
5844 FIXME("Unsupported format %d\n", format);
5845 return GDI_ERROR;
5847 return needed;
5850 static BOOL get_bitmap_text_metrics(GdiFont *font)
5852 FT_Face ft_face = font->ft_face;
5853 FT_WinFNT_HeaderRec winfnt_header;
5854 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5855 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5856 font->potm->otmSize = size;
5858 #define TM font->potm->otmTextMetrics
5859 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5861 TM.tmHeight = winfnt_header.pixel_height;
5862 TM.tmAscent = winfnt_header.ascent;
5863 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5864 TM.tmInternalLeading = winfnt_header.internal_leading;
5865 TM.tmExternalLeading = winfnt_header.external_leading;
5866 TM.tmAveCharWidth = winfnt_header.avg_width;
5867 TM.tmMaxCharWidth = winfnt_header.max_width;
5868 TM.tmWeight = winfnt_header.weight;
5869 TM.tmOverhang = 0;
5870 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5871 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5872 TM.tmFirstChar = winfnt_header.first_char;
5873 TM.tmLastChar = winfnt_header.last_char;
5874 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5875 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5876 TM.tmItalic = winfnt_header.italic;
5877 TM.tmUnderlined = font->underline;
5878 TM.tmStruckOut = font->strikeout;
5879 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5880 TM.tmCharSet = winfnt_header.charset;
5882 else
5884 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5885 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5886 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5887 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5888 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5889 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5890 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5891 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5892 TM.tmOverhang = 0;
5893 TM.tmDigitizedAspectX = 96; /* FIXME */
5894 TM.tmDigitizedAspectY = 96; /* FIXME */
5895 TM.tmFirstChar = 1;
5896 TM.tmLastChar = 255;
5897 TM.tmDefaultChar = 32;
5898 TM.tmBreakChar = 32;
5899 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5900 TM.tmUnderlined = font->underline;
5901 TM.tmStruckOut = font->strikeout;
5902 /* NB inverted meaning of TMPF_FIXED_PITCH */
5903 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5904 TM.tmCharSet = font->charset;
5906 #undef TM
5908 return TRUE;
5912 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5914 double scale_x, scale_y;
5916 if (font->aveWidth)
5918 scale_x = (double)font->aveWidth;
5919 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5921 else
5922 scale_x = font->scale_y;
5924 scale_x *= fabs(font->font_desc.matrix.eM11);
5925 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5927 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5928 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5930 SCALE_Y(ptm->tmHeight);
5931 SCALE_Y(ptm->tmAscent);
5932 SCALE_Y(ptm->tmDescent);
5933 SCALE_Y(ptm->tmInternalLeading);
5934 SCALE_Y(ptm->tmExternalLeading);
5935 SCALE_Y(ptm->tmOverhang);
5937 SCALE_X(ptm->tmAveCharWidth);
5938 SCALE_X(ptm->tmMaxCharWidth);
5940 #undef SCALE_X
5941 #undef SCALE_Y
5944 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5946 double scale_x, scale_y;
5948 if (font->aveWidth)
5950 scale_x = (double)font->aveWidth;
5951 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5953 else
5954 scale_x = font->scale_y;
5956 scale_x *= fabs(font->font_desc.matrix.eM11);
5957 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5959 scale_font_metrics(font, &potm->otmTextMetrics);
5961 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5962 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5964 SCALE_Y(potm->otmAscent);
5965 SCALE_Y(potm->otmDescent);
5966 SCALE_Y(potm->otmLineGap);
5967 SCALE_Y(potm->otmsCapEmHeight);
5968 SCALE_Y(potm->otmsXHeight);
5969 SCALE_Y(potm->otmrcFontBox.top);
5970 SCALE_Y(potm->otmrcFontBox.bottom);
5971 SCALE_X(potm->otmrcFontBox.left);
5972 SCALE_X(potm->otmrcFontBox.right);
5973 SCALE_Y(potm->otmMacAscent);
5974 SCALE_Y(potm->otmMacDescent);
5975 SCALE_Y(potm->otmMacLineGap);
5976 SCALE_X(potm->otmptSubscriptSize.x);
5977 SCALE_Y(potm->otmptSubscriptSize.y);
5978 SCALE_X(potm->otmptSubscriptOffset.x);
5979 SCALE_Y(potm->otmptSubscriptOffset.y);
5980 SCALE_X(potm->otmptSuperscriptSize.x);
5981 SCALE_Y(potm->otmptSuperscriptSize.y);
5982 SCALE_X(potm->otmptSuperscriptOffset.x);
5983 SCALE_Y(potm->otmptSuperscriptOffset.y);
5984 SCALE_Y(potm->otmsStrikeoutSize);
5985 SCALE_Y(potm->otmsStrikeoutPosition);
5986 SCALE_Y(potm->otmsUnderscoreSize);
5987 SCALE_Y(potm->otmsUnderscorePosition);
5989 #undef SCALE_X
5990 #undef SCALE_Y
5993 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5995 if(!font->potm)
5997 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
5999 /* Make sure that the font has sane width/height ratio */
6000 if (font->aveWidth)
6002 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6004 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6005 font->aveWidth = 0;
6009 *ptm = font->potm->otmTextMetrics;
6010 scale_font_metrics(font, ptm);
6011 return TRUE;
6014 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6016 int i;
6018 for(i = 0; i < ft_face->num_charmaps; i++)
6020 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6021 return TRUE;
6023 return FALSE;
6026 static BOOL get_outline_text_metrics(GdiFont *font)
6028 BOOL ret = FALSE;
6029 FT_Face ft_face = font->ft_face;
6030 UINT needed, lenfam, lensty;
6031 TT_OS2 *pOS2;
6032 TT_HoriHeader *pHori;
6033 TT_Postscript *pPost;
6034 FT_Fixed x_scale, y_scale;
6035 WCHAR *family_nameW, *style_nameW;
6036 static const WCHAR spaceW[] = {' ', '\0'};
6037 char *cp;
6038 INT ascent, descent;
6040 TRACE("font=%p\n", font);
6042 if(!FT_IS_SCALABLE(ft_face))
6043 return FALSE;
6045 needed = sizeof(*font->potm);
6047 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6048 family_nameW = strdupW(font->name);
6050 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6051 * sizeof(WCHAR);
6052 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6053 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6054 style_nameW, lensty/sizeof(WCHAR));
6056 /* These names should be read from the TT name table */
6058 /* length of otmpFamilyName */
6059 needed += lenfam;
6061 /* length of otmpFaceName */
6062 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6063 needed += lenfam; /* just the family name */
6064 } else {
6065 needed += lenfam + lensty; /* family + " " + style */
6068 /* length of otmpStyleName */
6069 needed += lensty;
6071 /* length of otmpFullName */
6072 needed += lenfam + lensty;
6075 x_scale = ft_face->size->metrics.x_scale;
6076 y_scale = ft_face->size->metrics.y_scale;
6078 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6079 if(!pOS2) {
6080 FIXME("Can't find OS/2 table - not TT font?\n");
6081 goto end;
6084 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6085 if(!pHori) {
6086 FIXME("Can't find HHEA table - not TT font?\n");
6087 goto end;
6090 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6092 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",
6093 pOS2->usWinAscent, pOS2->usWinDescent,
6094 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6095 ft_face->ascender, ft_face->descender, ft_face->height,
6096 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6097 ft_face->bbox.yMax, ft_face->bbox.yMin);
6099 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6100 font->potm->otmSize = needed;
6102 #define TM font->potm->otmTextMetrics
6104 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6105 ascent = pHori->Ascender;
6106 descent = -pHori->Descender;
6107 } else {
6108 ascent = pOS2->usWinAscent;
6109 descent = pOS2->usWinDescent;
6112 if(font->yMax) {
6113 TM.tmAscent = font->yMax;
6114 TM.tmDescent = -font->yMin;
6115 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6116 } else {
6117 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6118 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6119 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6120 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6123 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6125 /* MSDN says:
6126 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6128 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6129 ((ascent + descent) -
6130 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6132 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6133 if (TM.tmAveCharWidth == 0) {
6134 TM.tmAveCharWidth = 1;
6136 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6137 TM.tmWeight = FW_REGULAR;
6138 if (font->fake_bold)
6139 TM.tmWeight = FW_BOLD;
6140 else
6142 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6144 if (pOS2->usWeightClass > FW_MEDIUM)
6145 TM.tmWeight = pOS2->usWeightClass;
6147 else if (pOS2->usWeightClass <= FW_MEDIUM)
6148 TM.tmWeight = pOS2->usWeightClass;
6150 TM.tmOverhang = 0;
6151 TM.tmDigitizedAspectX = 300;
6152 TM.tmDigitizedAspectY = 300;
6153 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6154 * symbol range to 0 - f0ff
6157 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6159 TM.tmFirstChar = 0;
6160 switch(GetACP())
6162 case 1257: /* Baltic */
6163 TM.tmLastChar = 0xf8fd;
6164 break;
6165 default:
6166 TM.tmLastChar = 0xf0ff;
6168 TM.tmBreakChar = 0x20;
6169 TM.tmDefaultChar = 0x1f;
6171 else
6173 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6174 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6176 if(pOS2->usFirstCharIndex <= 1)
6177 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6178 else if (pOS2->usFirstCharIndex > 0xff)
6179 TM.tmBreakChar = 0x20;
6180 else
6181 TM.tmBreakChar = pOS2->usFirstCharIndex;
6182 TM.tmDefaultChar = TM.tmBreakChar - 1;
6184 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6185 TM.tmUnderlined = font->underline;
6186 TM.tmStruckOut = font->strikeout;
6188 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6189 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6190 (pOS2->version == 0xFFFFU ||
6191 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6192 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6193 else
6194 TM.tmPitchAndFamily = 0;
6196 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6198 case PAN_FAMILY_SCRIPT:
6199 TM.tmPitchAndFamily |= FF_SCRIPT;
6200 break;
6202 case PAN_FAMILY_DECORATIVE:
6203 TM.tmPitchAndFamily |= FF_DECORATIVE;
6204 break;
6206 case PAN_ANY:
6207 case PAN_NO_FIT:
6208 case PAN_FAMILY_TEXT_DISPLAY:
6209 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6210 /* which is clearly not what the panose spec says. */
6211 default:
6212 if(TM.tmPitchAndFamily == 0 || /* fixed */
6213 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6214 TM.tmPitchAndFamily = FF_MODERN;
6215 else
6217 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6219 case PAN_ANY:
6220 case PAN_NO_FIT:
6221 default:
6222 TM.tmPitchAndFamily |= FF_DONTCARE;
6223 break;
6225 case PAN_SERIF_COVE:
6226 case PAN_SERIF_OBTUSE_COVE:
6227 case PAN_SERIF_SQUARE_COVE:
6228 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6229 case PAN_SERIF_SQUARE:
6230 case PAN_SERIF_THIN:
6231 case PAN_SERIF_BONE:
6232 case PAN_SERIF_EXAGGERATED:
6233 case PAN_SERIF_TRIANGLE:
6234 TM.tmPitchAndFamily |= FF_ROMAN;
6235 break;
6237 case PAN_SERIF_NORMAL_SANS:
6238 case PAN_SERIF_OBTUSE_SANS:
6239 case PAN_SERIF_PERP_SANS:
6240 case PAN_SERIF_FLARED:
6241 case PAN_SERIF_ROUNDED:
6242 TM.tmPitchAndFamily |= FF_SWISS;
6243 break;
6246 break;
6249 if(FT_IS_SCALABLE(ft_face))
6250 TM.tmPitchAndFamily |= TMPF_VECTOR;
6252 if(FT_IS_SFNT(ft_face))
6254 if (font->ntmFlags & NTM_PS_OPENTYPE)
6255 TM.tmPitchAndFamily |= TMPF_DEVICE;
6256 else
6257 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6260 TM.tmCharSet = font->charset;
6262 font->potm->otmFiller = 0;
6263 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6264 font->potm->otmfsSelection = pOS2->fsSelection;
6265 font->potm->otmfsType = pOS2->fsType;
6266 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6267 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6268 font->potm->otmItalicAngle = 0; /* POST table */
6269 font->potm->otmEMSquare = ft_face->units_per_EM;
6270 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6271 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6272 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6273 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6274 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6275 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6276 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6277 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6278 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6279 font->potm->otmMacAscent = TM.tmAscent;
6280 font->potm->otmMacDescent = -TM.tmDescent;
6281 font->potm->otmMacLineGap = font->potm->otmLineGap;
6282 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6283 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6284 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6285 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6286 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6287 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6288 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6289 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6290 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6291 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6292 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6293 if(!pPost) {
6294 font->potm->otmsUnderscoreSize = 0;
6295 font->potm->otmsUnderscorePosition = 0;
6296 } else {
6297 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6298 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6300 #undef TM
6302 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6303 cp = (char*)font->potm + sizeof(*font->potm);
6304 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6305 strcpyW((WCHAR*)cp, family_nameW);
6306 cp += lenfam;
6307 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6308 strcpyW((WCHAR*)cp, style_nameW);
6309 cp += lensty;
6310 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6311 strcpyW((WCHAR*)cp, family_nameW);
6312 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6313 strcatW((WCHAR*)cp, spaceW);
6314 strcatW((WCHAR*)cp, style_nameW);
6315 cp += lenfam + lensty;
6316 } else
6317 cp += lenfam;
6318 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6319 strcpyW((WCHAR*)cp, family_nameW);
6320 strcatW((WCHAR*)cp, spaceW);
6321 strcatW((WCHAR*)cp, style_nameW);
6322 ret = TRUE;
6324 end:
6325 HeapFree(GetProcessHeap(), 0, style_nameW);
6326 HeapFree(GetProcessHeap(), 0, family_nameW);
6327 return ret;
6330 /*************************************************************
6331 * freetype_GetGlyphOutline
6333 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6334 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6336 struct freetype_physdev *physdev = get_freetype_dev( dev );
6337 DWORD ret;
6339 if (!physdev->font)
6341 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6342 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6345 GDI_CheckNotLock();
6346 EnterCriticalSection( &freetype_cs );
6347 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6348 LeaveCriticalSection( &freetype_cs );
6349 return ret;
6352 /*************************************************************
6353 * freetype_GetTextMetrics
6355 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6357 struct freetype_physdev *physdev = get_freetype_dev( dev );
6358 BOOL ret;
6360 if (!physdev->font)
6362 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6363 return dev->funcs->pGetTextMetrics( dev, metrics );
6366 GDI_CheckNotLock();
6367 EnterCriticalSection( &freetype_cs );
6368 ret = get_text_metrics( physdev->font, metrics );
6369 LeaveCriticalSection( &freetype_cs );
6370 return ret;
6373 /*************************************************************
6374 * freetype_GetOutlineTextMetrics
6376 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6378 struct freetype_physdev *physdev = get_freetype_dev( dev );
6379 UINT ret = 0;
6381 if (!physdev->font)
6383 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6384 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6387 TRACE("font=%p\n", physdev->font);
6389 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6391 GDI_CheckNotLock();
6392 EnterCriticalSection( &freetype_cs );
6394 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6396 if(cbSize >= physdev->font->potm->otmSize)
6398 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6399 scale_outline_font_metrics(physdev->font, potm);
6401 ret = physdev->font->potm->otmSize;
6403 LeaveCriticalSection( &freetype_cs );
6404 return ret;
6407 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6409 HFONTLIST *hfontlist;
6410 child->font = alloc_font();
6411 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6412 if(!child->font->ft_face)
6414 free_font(child->font);
6415 child->font = NULL;
6416 return FALSE;
6419 child->font->font_desc = font->font_desc;
6420 child->font->ntmFlags = child->face->ntmFlags;
6421 child->font->orientation = font->orientation;
6422 child->font->scale_y = font->scale_y;
6423 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6424 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6425 child->font->name = strdupW(child->face->family->FamilyName);
6426 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6427 child->font->base_font = font;
6428 list_add_head(&child_font_list, &child->font->entry);
6429 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6430 return TRUE;
6433 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6435 FT_UInt g;
6436 CHILD_FONT *child_font;
6438 if(font->base_font)
6439 font = font->base_font;
6441 *linked_font = font;
6443 if((*glyph = get_glyph_index(font, c)))
6445 *glyph = get_GSUB_vert_glyph(font, *glyph);
6446 return TRUE;
6449 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6451 if(!child_font->font)
6452 if(!load_child_font(font, child_font))
6453 continue;
6455 if(!child_font->font->ft_face)
6456 continue;
6457 g = get_glyph_index(child_font->font, c);
6458 g = get_GSUB_vert_glyph(child_font->font, g);
6459 if(g)
6461 *glyph = g;
6462 *linked_font = child_font->font;
6463 return TRUE;
6466 return FALSE;
6469 /*************************************************************
6470 * freetype_GetCharWidth
6472 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6474 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6475 UINT c;
6476 GLYPHMETRICS gm;
6477 FT_UInt glyph_index;
6478 GdiFont *linked_font;
6479 struct freetype_physdev *physdev = get_freetype_dev( dev );
6481 if (!physdev->font)
6483 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6484 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6487 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6489 GDI_CheckNotLock();
6490 EnterCriticalSection( &freetype_cs );
6491 for(c = firstChar; c <= lastChar; c++) {
6492 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6493 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6494 &gm, 0, NULL, &identity);
6495 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6497 LeaveCriticalSection( &freetype_cs );
6498 return TRUE;
6501 /*************************************************************
6502 * freetype_GetCharABCWidths
6504 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6506 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6507 UINT c;
6508 GLYPHMETRICS gm;
6509 FT_UInt glyph_index;
6510 GdiFont *linked_font;
6511 struct freetype_physdev *physdev = get_freetype_dev( dev );
6513 if (!physdev->font)
6515 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6516 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6519 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6521 GDI_CheckNotLock();
6522 EnterCriticalSection( &freetype_cs );
6524 for(c = firstChar; c <= lastChar; c++) {
6525 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6526 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6527 &gm, 0, NULL, &identity);
6528 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6529 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6530 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6531 FONT_GM(linked_font,glyph_index)->bbx;
6533 LeaveCriticalSection( &freetype_cs );
6534 return TRUE;
6537 /*************************************************************
6538 * freetype_GetCharABCWidthsI
6540 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6542 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6543 UINT c;
6544 GLYPHMETRICS gm;
6545 FT_UInt glyph_index;
6546 GdiFont *linked_font;
6547 struct freetype_physdev *physdev = get_freetype_dev( dev );
6549 if (!physdev->font)
6551 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6552 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6555 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6556 return FALSE;
6558 GDI_CheckNotLock();
6559 EnterCriticalSection( &freetype_cs );
6561 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6562 if (!pgi)
6563 for(c = firstChar; c < firstChar+count; c++) {
6564 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6565 &gm, 0, NULL, &identity);
6566 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6567 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6568 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6569 - FONT_GM(linked_font,c)->bbx;
6571 else
6572 for(c = 0; c < count; c++) {
6573 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6574 &gm, 0, NULL, &identity);
6575 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6576 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6577 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6578 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6581 LeaveCriticalSection( &freetype_cs );
6582 return TRUE;
6585 /*************************************************************
6586 * freetype_GetTextExtentExPoint
6588 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6589 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6591 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6592 INT idx;
6593 INT nfit = 0, ext;
6594 GLYPHMETRICS gm;
6595 TEXTMETRICW tm;
6596 FT_UInt glyph_index;
6597 GdiFont *linked_font;
6598 struct freetype_physdev *physdev = get_freetype_dev( dev );
6600 if (!physdev->font)
6602 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6603 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6606 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6608 GDI_CheckNotLock();
6609 EnterCriticalSection( &freetype_cs );
6611 size->cx = 0;
6612 get_text_metrics( physdev->font, &tm );
6613 size->cy = tm.tmHeight;
6615 for(idx = 0; idx < count; idx++) {
6616 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6617 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6618 &gm, 0, NULL, &identity);
6619 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6620 ext = size->cx;
6621 if (! pnfit || ext <= max_ext) {
6622 ++nfit;
6623 if (dxs)
6624 dxs[idx] = ext;
6628 if (pnfit)
6629 *pnfit = nfit;
6631 LeaveCriticalSection( &freetype_cs );
6632 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6633 return TRUE;
6636 /*************************************************************
6637 * freetype_GetTextExtentExPointI
6639 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6640 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6642 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6643 INT idx;
6644 INT nfit = 0, ext;
6645 GLYPHMETRICS gm;
6646 TEXTMETRICW tm;
6647 struct freetype_physdev *physdev = get_freetype_dev( dev );
6649 if (!physdev->font)
6651 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6652 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6655 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6657 GDI_CheckNotLock();
6658 EnterCriticalSection( &freetype_cs );
6660 size->cx = 0;
6661 get_text_metrics(physdev->font, &tm);
6662 size->cy = tm.tmHeight;
6664 for(idx = 0; idx < count; idx++) {
6665 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6666 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6667 ext = size->cx;
6668 if (! pnfit || ext <= max_ext) {
6669 ++nfit;
6670 if (dxs)
6671 dxs[idx] = ext;
6675 if (pnfit)
6676 *pnfit = nfit;
6678 LeaveCriticalSection( &freetype_cs );
6679 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6680 return TRUE;
6683 /*************************************************************
6684 * freetype_GetFontData
6686 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6688 struct freetype_physdev *physdev = get_freetype_dev( dev );
6690 if (!physdev->font)
6692 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6693 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6696 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6697 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6698 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6700 return get_font_data( physdev->font, table, offset, buf, cbData );
6703 /*************************************************************
6704 * freetype_GetTextFace
6706 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6708 INT n;
6709 struct freetype_physdev *physdev = get_freetype_dev( dev );
6711 if (!physdev->font)
6713 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6714 return dev->funcs->pGetTextFace( dev, count, str );
6717 n = strlenW(physdev->font->name) + 1;
6718 if (str)
6720 lstrcpynW(str, physdev->font->name, count);
6721 n = min(count, n);
6723 return n;
6726 /*************************************************************
6727 * freetype_GetTextCharsetInfo
6729 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6731 struct freetype_physdev *physdev = get_freetype_dev( dev );
6733 if (!physdev->font)
6735 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6736 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6738 if (fs) *fs = physdev->font->fs;
6739 return physdev->font->charset;
6742 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6744 GdiFont *font = dc->gdiFont, *linked_font;
6745 struct list *first_hfont;
6746 BOOL ret;
6748 GDI_CheckNotLock();
6749 EnterCriticalSection( &freetype_cs );
6750 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6751 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6752 if(font == linked_font)
6753 *new_hfont = dc->hFont;
6754 else
6756 first_hfont = list_head(&linked_font->hfontlist);
6757 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6759 LeaveCriticalSection( &freetype_cs );
6760 return ret;
6763 /* Retrieve a list of supported Unicode ranges for a given font.
6764 * Can be called with NULL gs to calculate the buffer size. Returns
6765 * the number of ranges found.
6767 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6769 DWORD num_ranges = 0;
6771 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6773 FT_UInt glyph_code;
6774 FT_ULong char_code, char_code_prev;
6776 glyph_code = 0;
6777 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6779 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6780 face->num_glyphs, glyph_code, char_code);
6782 if (!glyph_code) return 0;
6784 if (gs)
6786 gs->ranges[0].wcLow = (USHORT)char_code;
6787 gs->ranges[0].cGlyphs = 0;
6788 gs->cGlyphsSupported = 0;
6791 num_ranges = 1;
6792 while (glyph_code)
6794 if (char_code < char_code_prev)
6796 ERR("expected increasing char code from FT_Get_Next_Char\n");
6797 return 0;
6799 if (char_code - char_code_prev > 1)
6801 num_ranges++;
6802 if (gs)
6804 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6805 gs->ranges[num_ranges - 1].cGlyphs = 1;
6806 gs->cGlyphsSupported++;
6809 else if (gs)
6811 gs->ranges[num_ranges - 1].cGlyphs++;
6812 gs->cGlyphsSupported++;
6814 char_code_prev = char_code;
6815 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6818 else
6819 FIXME("encoding %u not supported\n", face->charmap->encoding);
6821 return num_ranges;
6824 /*************************************************************
6825 * freetype_GetFontUnicodeRanges
6827 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6829 struct freetype_physdev *physdev = get_freetype_dev( dev );
6830 DWORD size, num_ranges;
6832 if (!physdev->font)
6834 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6835 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6838 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6839 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6840 if (glyphset)
6842 glyphset->cbThis = size;
6843 glyphset->cRanges = num_ranges;
6844 glyphset->flAccel = 0;
6846 return size;
6849 /*************************************************************
6850 * freetype_FontIsLinked
6852 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6854 struct freetype_physdev *physdev = get_freetype_dev( dev );
6855 BOOL ret;
6857 if (!physdev->font)
6859 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6860 return dev->funcs->pFontIsLinked( dev );
6863 GDI_CheckNotLock();
6864 EnterCriticalSection( &freetype_cs );
6865 ret = !list_empty(&physdev->font->child_fonts);
6866 LeaveCriticalSection( &freetype_cs );
6867 return ret;
6870 static BOOL is_hinting_enabled(void)
6872 /* Use the >= 2.2.0 function if available */
6873 if(pFT_Get_TrueType_Engine_Type)
6875 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6876 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6878 #ifdef FT_DRIVER_HAS_HINTER
6879 else
6881 FT_Module mod;
6883 /* otherwise if we've been compiled with < 2.2.0 headers
6884 use the internal macro */
6885 mod = pFT_Get_Module(library, "truetype");
6886 if(mod && FT_DRIVER_HAS_HINTER(mod))
6887 return TRUE;
6889 #endif
6891 return FALSE;
6894 static BOOL is_subpixel_rendering_enabled( void )
6896 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6897 return pFT_Library_SetLcdFilter &&
6898 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6899 #else
6900 return FALSE;
6901 #endif
6904 /*************************************************************************
6905 * GetRasterizerCaps (GDI32.@)
6907 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6909 static int hinting = -1;
6910 static int subpixel = -1;
6912 if(hinting == -1)
6914 hinting = is_hinting_enabled();
6915 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6918 if ( subpixel == -1 )
6920 subpixel = is_subpixel_rendering_enabled();
6921 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6924 lprs->nSize = sizeof(RASTERIZER_STATUS);
6925 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6926 if ( subpixel )
6927 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6928 lprs->nLanguageID = 0;
6929 return TRUE;
6932 /*************************************************************
6933 * freetype_GdiRealizationInfo
6935 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6937 struct freetype_physdev *physdev = get_freetype_dev( dev );
6938 realization_info_t *info = ptr;
6940 if (!physdev->font)
6942 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6943 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6946 FIXME("(%p, %p): stub!\n", physdev->font, info);
6948 info->flags = 1;
6949 if(FT_IS_SCALABLE(physdev->font->ft_face))
6950 info->flags |= 2;
6952 info->cache_num = physdev->font->cache_num;
6953 info->unknown2 = -1;
6954 return TRUE;
6957 /*************************************************************************
6958 * Kerning support for TrueType fonts
6960 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6962 struct TT_kern_table
6964 USHORT version;
6965 USHORT nTables;
6968 struct TT_kern_subtable
6970 USHORT version;
6971 USHORT length;
6972 union
6974 USHORT word;
6975 struct
6977 USHORT horizontal : 1;
6978 USHORT minimum : 1;
6979 USHORT cross_stream: 1;
6980 USHORT override : 1;
6981 USHORT reserved1 : 4;
6982 USHORT format : 8;
6983 } bits;
6984 } coverage;
6987 struct TT_format0_kern_subtable
6989 USHORT nPairs;
6990 USHORT searchRange;
6991 USHORT entrySelector;
6992 USHORT rangeShift;
6995 struct TT_kern_pair
6997 USHORT left;
6998 USHORT right;
6999 short value;
7002 static DWORD parse_format0_kern_subtable(GdiFont *font,
7003 const struct TT_format0_kern_subtable *tt_f0_ks,
7004 const USHORT *glyph_to_char,
7005 KERNINGPAIR *kern_pair, DWORD cPairs)
7007 USHORT i, nPairs;
7008 const struct TT_kern_pair *tt_kern_pair;
7010 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7012 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7014 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7015 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7016 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7018 if (!kern_pair || !cPairs)
7019 return nPairs;
7021 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7023 nPairs = min(nPairs, cPairs);
7025 for (i = 0; i < nPairs; i++)
7027 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7028 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7029 /* this algorithm appears to better match what Windows does */
7030 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7031 if (kern_pair->iKernAmount < 0)
7033 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7034 kern_pair->iKernAmount -= font->ppem;
7036 else if (kern_pair->iKernAmount > 0)
7038 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7039 kern_pair->iKernAmount += font->ppem;
7041 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7043 TRACE("left %u right %u value %d\n",
7044 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7046 kern_pair++;
7048 TRACE("copied %u entries\n", nPairs);
7049 return nPairs;
7052 /*************************************************************
7053 * freetype_GetKerningPairs
7055 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7057 DWORD length;
7058 void *buf;
7059 const struct TT_kern_table *tt_kern_table;
7060 const struct TT_kern_subtable *tt_kern_subtable;
7061 USHORT i, nTables;
7062 USHORT *glyph_to_char;
7063 GdiFont *font;
7064 struct freetype_physdev *physdev = get_freetype_dev( dev );
7066 if (!(font = physdev->font))
7068 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7069 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7072 GDI_CheckNotLock();
7073 EnterCriticalSection( &freetype_cs );
7074 if (font->total_kern_pairs != (DWORD)-1)
7076 if (cPairs && kern_pair)
7078 cPairs = min(cPairs, font->total_kern_pairs);
7079 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7081 else cPairs = font->total_kern_pairs;
7083 LeaveCriticalSection( &freetype_cs );
7084 return cPairs;
7087 font->total_kern_pairs = 0;
7089 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7091 if (length == GDI_ERROR)
7093 TRACE("no kerning data in the font\n");
7094 LeaveCriticalSection( &freetype_cs );
7095 return 0;
7098 buf = HeapAlloc(GetProcessHeap(), 0, length);
7099 if (!buf)
7101 WARN("Out of memory\n");
7102 LeaveCriticalSection( &freetype_cs );
7103 return 0;
7106 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7108 /* build a glyph index to char code map */
7109 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7110 if (!glyph_to_char)
7112 WARN("Out of memory allocating a glyph index to char code map\n");
7113 HeapFree(GetProcessHeap(), 0, buf);
7114 LeaveCriticalSection( &freetype_cs );
7115 return 0;
7118 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7120 FT_UInt glyph_code;
7121 FT_ULong char_code;
7123 glyph_code = 0;
7124 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7126 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7127 font->ft_face->num_glyphs, glyph_code, char_code);
7129 while (glyph_code)
7131 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7133 /* FIXME: This doesn't match what Windows does: it does some fancy
7134 * things with duplicate glyph index to char code mappings, while
7135 * we just avoid overriding existing entries.
7137 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7138 glyph_to_char[glyph_code] = (USHORT)char_code;
7140 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7143 else
7145 ULONG n;
7147 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7148 for (n = 0; n <= 65535; n++)
7149 glyph_to_char[n] = (USHORT)n;
7152 tt_kern_table = buf;
7153 nTables = GET_BE_WORD(tt_kern_table->nTables);
7154 TRACE("version %u, nTables %u\n",
7155 GET_BE_WORD(tt_kern_table->version), nTables);
7157 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7159 for (i = 0; i < nTables; i++)
7161 struct TT_kern_subtable tt_kern_subtable_copy;
7163 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7164 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7165 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7167 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7168 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7169 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7171 /* According to the TrueType specification this is the only format
7172 * that will be properly interpreted by Windows and OS/2
7174 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7176 DWORD new_chunk, old_total = font->total_kern_pairs;
7178 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7179 glyph_to_char, NULL, 0);
7180 font->total_kern_pairs += new_chunk;
7182 if (!font->kern_pairs)
7183 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7184 font->total_kern_pairs * sizeof(*font->kern_pairs));
7185 else
7186 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7187 font->total_kern_pairs * sizeof(*font->kern_pairs));
7189 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7190 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7192 else
7193 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7195 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7198 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7199 HeapFree(GetProcessHeap(), 0, buf);
7201 if (cPairs && kern_pair)
7203 cPairs = min(cPairs, font->total_kern_pairs);
7204 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7206 else cPairs = font->total_kern_pairs;
7208 LeaveCriticalSection( &freetype_cs );
7209 return cPairs;
7212 static const struct gdi_dc_funcs freetype_funcs =
7214 NULL, /* pAbortDoc */
7215 NULL, /* pAbortPath */
7216 NULL, /* pAlphaBlend */
7217 NULL, /* pAngleArc */
7218 NULL, /* pArc */
7219 NULL, /* pArcTo */
7220 NULL, /* pBeginPath */
7221 NULL, /* pBlendImage */
7222 NULL, /* pChoosePixelFormat */
7223 NULL, /* pChord */
7224 NULL, /* pCloseFigure */
7225 NULL, /* pCopyBitmap */
7226 NULL, /* pCreateBitmap */
7227 NULL, /* pCreateCompatibleDC */
7228 freetype_CreateDC, /* pCreateDC */
7229 NULL, /* pDeleteBitmap */
7230 freetype_DeleteDC, /* pDeleteDC */
7231 NULL, /* pDeleteObject */
7232 NULL, /* pDescribePixelFormat */
7233 NULL, /* pDeviceCapabilities */
7234 NULL, /* pEllipse */
7235 NULL, /* pEndDoc */
7236 NULL, /* pEndPage */
7237 NULL, /* pEndPath */
7238 freetype_EnumFonts, /* pEnumFonts */
7239 NULL, /* pEnumICMProfiles */
7240 NULL, /* pExcludeClipRect */
7241 NULL, /* pExtDeviceMode */
7242 NULL, /* pExtEscape */
7243 NULL, /* pExtFloodFill */
7244 NULL, /* pExtSelectClipRgn */
7245 NULL, /* pExtTextOut */
7246 NULL, /* pFillPath */
7247 NULL, /* pFillRgn */
7248 NULL, /* pFlattenPath */
7249 freetype_FontIsLinked, /* pFontIsLinked */
7250 NULL, /* pFrameRgn */
7251 NULL, /* pGdiComment */
7252 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7253 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7254 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7255 freetype_GetCharWidth, /* pGetCharWidth */
7256 NULL, /* pGetDeviceCaps */
7257 NULL, /* pGetDeviceGammaRamp */
7258 freetype_GetFontData, /* pGetFontData */
7259 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7260 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7261 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7262 NULL, /* pGetICMProfile */
7263 NULL, /* pGetImage */
7264 freetype_GetKerningPairs, /* pGetKerningPairs */
7265 NULL, /* pGetNearestColor */
7266 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7267 NULL, /* pGetPixel */
7268 NULL, /* pGetPixelFormat */
7269 NULL, /* pGetSystemPaletteEntries */
7270 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7271 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7272 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7273 freetype_GetTextFace, /* pGetTextFace */
7274 freetype_GetTextMetrics, /* pGetTextMetrics */
7275 NULL, /* pGradientFill */
7276 NULL, /* pIntersectClipRect */
7277 NULL, /* pInvertRgn */
7278 NULL, /* pLineTo */
7279 NULL, /* pModifyWorldTransform */
7280 NULL, /* pMoveTo */
7281 NULL, /* pOffsetClipRgn */
7282 NULL, /* pOffsetViewportOrg */
7283 NULL, /* pOffsetWindowOrg */
7284 NULL, /* pPaintRgn */
7285 NULL, /* pPatBlt */
7286 NULL, /* pPie */
7287 NULL, /* pPolyBezier */
7288 NULL, /* pPolyBezierTo */
7289 NULL, /* pPolyDraw */
7290 NULL, /* pPolyPolygon */
7291 NULL, /* pPolyPolyline */
7292 NULL, /* pPolygon */
7293 NULL, /* pPolyline */
7294 NULL, /* pPolylineTo */
7295 NULL, /* pPutImage */
7296 NULL, /* pRealizeDefaultPalette */
7297 NULL, /* pRealizePalette */
7298 NULL, /* pRectangle */
7299 NULL, /* pResetDC */
7300 NULL, /* pRestoreDC */
7301 NULL, /* pRoundRect */
7302 NULL, /* pSaveDC */
7303 NULL, /* pScaleViewportExt */
7304 NULL, /* pScaleWindowExt */
7305 NULL, /* pSelectBitmap */
7306 NULL, /* pSelectBrush */
7307 NULL, /* pSelectClipPath */
7308 freetype_SelectFont, /* pSelectFont */
7309 NULL, /* pSelectPalette */
7310 NULL, /* pSelectPen */
7311 NULL, /* pSetArcDirection */
7312 NULL, /* pSetBkColor */
7313 NULL, /* pSetBkMode */
7314 NULL, /* pSetDCBrushColor */
7315 NULL, /* pSetDCPenColor */
7316 NULL, /* pSetDIBColorTable */
7317 NULL, /* pSetDIBitsToDevice */
7318 NULL, /* pSetDeviceClipping */
7319 NULL, /* pSetDeviceGammaRamp */
7320 NULL, /* pSetLayout */
7321 NULL, /* pSetMapMode */
7322 NULL, /* pSetMapperFlags */
7323 NULL, /* pSetPixel */
7324 NULL, /* pSetPixelFormat */
7325 NULL, /* pSetPolyFillMode */
7326 NULL, /* pSetROP2 */
7327 NULL, /* pSetRelAbs */
7328 NULL, /* pSetStretchBltMode */
7329 NULL, /* pSetTextAlign */
7330 NULL, /* pSetTextCharacterExtra */
7331 NULL, /* pSetTextColor */
7332 NULL, /* pSetTextJustification */
7333 NULL, /* pSetViewportExt */
7334 NULL, /* pSetViewportOrg */
7335 NULL, /* pSetWindowExt */
7336 NULL, /* pSetWindowOrg */
7337 NULL, /* pSetWorldTransform */
7338 NULL, /* pStartDoc */
7339 NULL, /* pStartPage */
7340 NULL, /* pStretchBlt */
7341 NULL, /* pStretchDIBits */
7342 NULL, /* pStrokeAndFillPath */
7343 NULL, /* pStrokePath */
7344 NULL, /* pSwapBuffers */
7345 NULL, /* pUnrealizePalette */
7346 NULL, /* pWidenPath */
7347 /* OpenGL not supported */
7350 #else /* HAVE_FREETYPE */
7352 /*************************************************************************/
7354 BOOL WineEngInit(void)
7356 return FALSE;
7358 BOOL WineEngDestroyFontInstance(HFONT hfont)
7360 return FALSE;
7363 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7365 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7366 return 1;
7369 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7371 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7372 return TRUE;
7375 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7377 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7378 return NULL;
7381 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7383 return FALSE;
7386 /*************************************************************************
7387 * GetRasterizerCaps (GDI32.@)
7389 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7391 lprs->nSize = sizeof(RASTERIZER_STATUS);
7392 lprs->wFlags = 0;
7393 lprs->nLanguageID = 0;
7394 return TRUE;
7397 #endif /* HAVE_FREETYPE */