cmd: Respect constant wide strings naming convention.
[wine/wine-gecko.git] / dlls / gdi32 / freetype.c
blob8bf397b255ba1446f0bb694e210436493519fbcb
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 Family *family;
1884 Face *face;
1885 struct list *family_elem_ptr, *face_elem_ptr;
1886 CHAR familyA[400];
1888 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1889 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1891 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1892 &valuelen, &datalen, NULL, NULL);
1894 valuelen++; /* returned value doesn't include room for '\0' */
1895 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1896 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1898 dlen = datalen;
1899 vlen = valuelen;
1900 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1901 &dlen) == ERROR_SUCCESS) {
1902 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1903 /* "NewName"="Oldname" */
1904 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1906 if(!find_family_from_any_name(value))
1908 /* Find the old family and hence all of the font files
1909 in that family */
1910 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1911 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1912 if(!strcmpiW(family->FamilyName, data) || (family->EnglishName && !strcmpiW(family->EnglishName, data))) {
1913 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1914 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1915 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1916 debugstr_w(face->StyleName), familyA);
1917 /* Now add a new entry with the new family name */
1918 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1919 familyA, family->FamilyName,
1920 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1922 break;
1926 /* reset dlen and vlen */
1927 dlen = datalen;
1928 vlen = valuelen;
1930 HeapFree(GetProcessHeap(), 0, data);
1931 HeapFree(GetProcessHeap(), 0, value);
1932 RegCloseKey(hkey);
1936 /*************************************************************
1937 * init_system_links
1939 static BOOL init_system_links(void)
1941 HKEY hkey;
1942 BOOL ret = FALSE;
1943 DWORD type, max_val, max_data, val_len, data_len, index;
1944 WCHAR *value, *data;
1945 WCHAR *entry, *next;
1946 SYSTEM_LINKS *font_link, *system_font_link;
1947 CHILD_FONT *child_font;
1948 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1949 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1950 FONTSIGNATURE fs;
1951 Family *family;
1952 Face *face;
1953 FontSubst *psub;
1955 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1957 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1958 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1959 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1960 val_len = max_val + 1;
1961 data_len = max_data;
1962 index = 0;
1963 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1965 memset(&fs, 0, sizeof(fs));
1966 psub = get_font_subst(&font_subst_list, value, -1);
1967 /* Don't store fonts that are only substitutes for other fonts */
1968 if(psub)
1970 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1971 goto next;
1973 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1974 font_link->font_name = strdupW(value);
1975 list_init(&font_link->links);
1976 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1978 WCHAR *face_name;
1979 CHILD_FONT *child_font;
1981 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1983 next = entry + strlenW(entry) + 1;
1985 face_name = strchrW(entry, ',');
1986 if(face_name)
1988 *face_name++ = 0;
1989 while(isspaceW(*face_name))
1990 face_name++;
1992 psub = get_font_subst(&font_subst_list, face_name, -1);
1993 if(psub)
1994 face_name = psub->to.name;
1996 face = find_face_from_filename(entry, face_name);
1997 if(!face)
1999 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2000 continue;
2003 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2004 child_font->face = face;
2005 child_font->font = NULL;
2006 fs.fsCsb[0] |= face->fs.fsCsb[0];
2007 fs.fsCsb[1] |= face->fs.fsCsb[1];
2008 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2009 list_add_tail(&font_link->links, &child_font->entry);
2011 family = find_family_from_name(font_link->font_name);
2012 if(family)
2014 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2016 face->fs_links = fs;
2019 list_add_tail(&system_links, &font_link->entry);
2020 next:
2021 val_len = max_val + 1;
2022 data_len = max_data;
2025 HeapFree(GetProcessHeap(), 0, value);
2026 HeapFree(GetProcessHeap(), 0, data);
2027 RegCloseKey(hkey);
2030 if(RegOpenKeyW(HKEY_CURRENT_USER, internal_system_link, &hkey) == ERROR_SUCCESS)
2032 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2033 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2034 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2035 val_len = max_val + 1;
2036 data_len = max_data;
2037 index = 0;
2038 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2040 BOOL existing = FALSE;
2041 memset(&fs, 0, sizeof(fs));
2042 psub = get_font_subst(&font_subst_list, value, -1);
2043 /* Don't store fonts that are only substitutes for other fonts */
2044 if(psub)
2046 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2047 goto next_internal;
2050 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2052 if(!strcmpiW(font_link->font_name, value))
2054 existing = TRUE;
2055 break;
2059 if (!existing)
2061 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2062 font_link->font_name = strdupW(value);
2063 list_init(&font_link->links);
2066 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2068 WCHAR *face_name;
2069 CHILD_FONT *child_font;
2071 TRACE("Internal entry %s: %s\n", debugstr_w(value), debugstr_w(entry));
2073 next = entry + strlenW(entry) + 1;
2075 face_name = strchrW(entry, ',');
2076 if(face_name)
2078 *face_name++ = 0;
2079 while(isspaceW(*face_name))
2080 face_name++;
2082 psub = get_font_subst(&font_subst_list, face_name, -1);
2083 if(psub)
2084 face_name = psub->to.name;
2086 face = find_face_from_filename(entry, face_name);
2087 if(!face)
2089 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2090 continue;
2093 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2094 child_font->face = face;
2095 child_font->font = NULL;
2096 fs.fsCsb[0] |= face->fs.fsCsb[0];
2097 fs.fsCsb[1] |= face->fs.fsCsb[1];
2098 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2099 list_add_tail(&font_link->links, &child_font->entry);
2101 family = find_family_from_name(font_link->font_name);
2102 if(family)
2104 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2106 face->fs_links = fs;
2109 if (!existing)
2110 list_add_tail(&system_links, &font_link->entry);
2111 next_internal:
2112 val_len = max_val + 1;
2113 data_len = max_data;
2116 HeapFree(GetProcessHeap(), 0, value);
2117 HeapFree(GetProcessHeap(), 0, data);
2118 RegCloseKey(hkey);
2121 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2122 that Tahoma has */
2124 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2125 system_font_link->font_name = strdupW(System);
2126 list_init(&system_font_link->links);
2128 face = find_face_from_filename(tahoma_ttf, Tahoma);
2129 if(face)
2131 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2132 child_font->face = face;
2133 child_font->font = NULL;
2134 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2135 list_add_tail(&system_font_link->links, &child_font->entry);
2137 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2139 if(!strcmpiW(font_link->font_name, Tahoma))
2141 CHILD_FONT *font_link_entry;
2142 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2144 CHILD_FONT *new_child;
2145 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2146 new_child->face = font_link_entry->face;
2147 new_child->font = NULL;
2148 list_add_tail(&system_font_link->links, &new_child->entry);
2150 break;
2153 list_add_tail(&system_links, &system_font_link->entry);
2154 return ret;
2157 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2159 DIR *dir;
2160 struct dirent *dent;
2161 char path[MAX_PATH];
2163 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2165 dir = opendir(dirname);
2166 if(!dir) {
2167 WARN("Can't open directory %s\n", debugstr_a(dirname));
2168 return FALSE;
2170 while((dent = readdir(dir)) != NULL) {
2171 struct stat statbuf;
2173 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2174 continue;
2176 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2178 sprintf(path, "%s/%s", dirname, dent->d_name);
2180 if(stat(path, &statbuf) == -1)
2182 WARN("Can't stat %s\n", debugstr_a(path));
2183 continue;
2185 if(S_ISDIR(statbuf.st_mode))
2186 ReadFontDir(path, external_fonts);
2187 else
2189 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2190 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2191 AddFontFileToList(path, NULL, NULL, addfont_flags);
2194 closedir(dir);
2195 return TRUE;
2198 static void load_fontconfig_fonts(void)
2200 #ifdef SONAME_LIBFONTCONFIG
2201 void *fc_handle = NULL;
2202 FcConfig *config;
2203 FcPattern *pat;
2204 FcObjectSet *os;
2205 FcFontSet *fontset;
2206 int i, len;
2207 char *file;
2208 const char *ext;
2210 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2211 if(!fc_handle) {
2212 TRACE("Wine cannot find the fontconfig library (%s).\n",
2213 SONAME_LIBFONTCONFIG);
2214 return;
2216 #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;}
2217 LOAD_FUNCPTR(FcConfigGetCurrent);
2218 LOAD_FUNCPTR(FcFontList);
2219 LOAD_FUNCPTR(FcFontSetDestroy);
2220 LOAD_FUNCPTR(FcInit);
2221 LOAD_FUNCPTR(FcObjectSetAdd);
2222 LOAD_FUNCPTR(FcObjectSetCreate);
2223 LOAD_FUNCPTR(FcObjectSetDestroy);
2224 LOAD_FUNCPTR(FcPatternCreate);
2225 LOAD_FUNCPTR(FcPatternDestroy);
2226 LOAD_FUNCPTR(FcPatternGetBool);
2227 LOAD_FUNCPTR(FcPatternGetString);
2228 #undef LOAD_FUNCPTR
2230 if(!pFcInit()) return;
2232 config = pFcConfigGetCurrent();
2233 pat = pFcPatternCreate();
2234 os = pFcObjectSetCreate();
2235 pFcObjectSetAdd(os, FC_FILE);
2236 pFcObjectSetAdd(os, FC_SCALABLE);
2237 fontset = pFcFontList(config, pat, os);
2238 if(!fontset) return;
2239 for(i = 0; i < fontset->nfont; i++) {
2240 FcBool scalable;
2242 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2243 continue;
2244 TRACE("fontconfig: %s\n", file);
2246 /* We're just interested in OT/TT fonts for now, so this hack just
2247 picks up the scalable fonts without extensions .pf[ab] to save time
2248 loading every other font */
2250 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2252 TRACE("not scalable\n");
2253 continue;
2256 len = strlen( file );
2257 if(len < 4) continue;
2258 ext = &file[ len - 3 ];
2259 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2260 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2262 pFcFontSetDestroy(fontset);
2263 pFcObjectSetDestroy(os);
2264 pFcPatternDestroy(pat);
2265 sym_not_found:
2266 #endif
2267 return;
2270 static BOOL load_font_from_data_dir(LPCWSTR file)
2272 BOOL ret = FALSE;
2273 const char *data_dir = wine_get_data_dir();
2275 if (!data_dir) data_dir = wine_get_build_dir();
2277 if (data_dir)
2279 INT len;
2280 char *unix_name;
2282 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2284 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2286 strcpy(unix_name, data_dir);
2287 strcat(unix_name, "/fonts/");
2289 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2291 EnterCriticalSection( &freetype_cs );
2292 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2293 LeaveCriticalSection( &freetype_cs );
2294 HeapFree(GetProcessHeap(), 0, unix_name);
2296 return ret;
2299 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2301 static const WCHAR slashW[] = {'\\','\0'};
2302 BOOL ret = FALSE;
2303 WCHAR windowsdir[MAX_PATH];
2304 char *unixname;
2306 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2307 strcatW(windowsdir, fontsW);
2308 strcatW(windowsdir, slashW);
2309 strcatW(windowsdir, file);
2310 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2311 EnterCriticalSection( &freetype_cs );
2312 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2313 LeaveCriticalSection( &freetype_cs );
2314 HeapFree(GetProcessHeap(), 0, unixname);
2316 return ret;
2319 static void load_system_fonts(void)
2321 HKEY hkey;
2322 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2323 const WCHAR * const *value;
2324 DWORD dlen, type;
2325 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2326 char *unixname;
2328 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2329 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2330 strcatW(windowsdir, fontsW);
2331 for(value = SystemFontValues; *value; value++) {
2332 dlen = sizeof(data);
2333 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2334 type == REG_SZ) {
2335 BOOL added = FALSE;
2337 sprintfW(pathW, fmtW, windowsdir, data);
2338 if((unixname = wine_get_unix_file_name(pathW))) {
2339 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2340 HeapFree(GetProcessHeap(), 0, unixname);
2342 if (!added)
2343 load_font_from_data_dir(data);
2346 RegCloseKey(hkey);
2350 /*************************************************************
2352 * This adds registry entries for any externally loaded fonts
2353 * (fonts from fontconfig or FontDirs). It also deletes entries
2354 * of no longer existing fonts.
2357 static void update_reg_entries(void)
2359 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2360 LPWSTR valueW;
2361 DWORD len, len_fam;
2362 Family *family;
2363 Face *face;
2364 struct list *family_elem_ptr, *face_elem_ptr;
2365 WCHAR *file;
2366 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2367 static const WCHAR spaceW[] = {' ', '\0'};
2368 char *path;
2370 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2371 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2372 ERR("Can't create Windows font reg key\n");
2373 goto end;
2376 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2377 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2378 ERR("Can't create Windows font reg key\n");
2379 goto end;
2382 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2383 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2384 ERR("Can't create external font reg key\n");
2385 goto end;
2388 /* enumerate the fonts and add external ones to the two keys */
2390 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2391 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2392 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2393 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2394 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2395 if(!face->external) continue;
2396 len = len_fam;
2397 if (!(face->ntmFlags & NTM_REGULAR))
2398 len = len_fam + strlenW(face->StyleName) + 1;
2399 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2400 strcpyW(valueW, family->FamilyName);
2401 if(len != len_fam) {
2402 strcatW(valueW, spaceW);
2403 strcatW(valueW, face->StyleName);
2405 strcatW(valueW, TrueType);
2407 file = wine_get_dos_file_name(face->file);
2408 if(file)
2409 len = strlenW(file) + 1;
2410 else
2412 if((path = strrchr(face->file, '/')) == NULL)
2413 path = face->file;
2414 else
2415 path++;
2416 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2418 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2419 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2421 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2422 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2423 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2425 HeapFree(GetProcessHeap(), 0, file);
2426 HeapFree(GetProcessHeap(), 0, valueW);
2429 end:
2430 if(external_key) RegCloseKey(external_key);
2431 if(win9x_key) RegCloseKey(win9x_key);
2432 if(winnt_key) RegCloseKey(winnt_key);
2433 return;
2436 static void delete_external_font_keys(void)
2438 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2439 DWORD dlen, vlen, datalen, valuelen, i, type;
2440 LPWSTR valueW;
2441 LPVOID data;
2443 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2444 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2445 ERR("Can't create Windows font reg key\n");
2446 goto end;
2449 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2450 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2451 ERR("Can't create Windows font reg key\n");
2452 goto end;
2455 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2456 ERR("Can't create external font reg key\n");
2457 goto end;
2460 /* Delete all external fonts added last time */
2462 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2463 &valuelen, &datalen, NULL, NULL);
2464 valuelen++; /* returned value doesn't include room for '\0' */
2465 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2466 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2468 dlen = datalen * sizeof(WCHAR);
2469 vlen = valuelen;
2470 i = 0;
2471 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2472 &dlen) == ERROR_SUCCESS) {
2474 RegDeleteValueW(winnt_key, valueW);
2475 RegDeleteValueW(win9x_key, valueW);
2476 /* reset dlen and vlen */
2477 dlen = datalen;
2478 vlen = valuelen;
2480 HeapFree(GetProcessHeap(), 0, data);
2481 HeapFree(GetProcessHeap(), 0, valueW);
2483 /* Delete the old external fonts key */
2484 RegCloseKey(external_key);
2485 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2487 end:
2488 if(win9x_key) RegCloseKey(win9x_key);
2489 if(winnt_key) RegCloseKey(winnt_key);
2492 /*************************************************************
2493 * WineEngAddFontResourceEx
2496 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2498 INT ret = 0;
2500 GDI_CheckNotLock();
2502 if (ft_handle) /* do it only if we have freetype up and running */
2504 char *unixname;
2506 if(flags)
2507 FIXME("Ignoring flags %x\n", flags);
2509 if((unixname = wine_get_unix_file_name(file)))
2511 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2513 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2514 EnterCriticalSection( &freetype_cs );
2515 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2516 LeaveCriticalSection( &freetype_cs );
2517 HeapFree(GetProcessHeap(), 0, unixname);
2519 if (!ret && !strchrW(file, '\\')) {
2520 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2521 ret = load_font_from_winfonts_dir(file);
2522 if (!ret) {
2523 /* Try in datadir/fonts (or builddir/fonts),
2524 * needed for Magic the Gathering Online
2526 ret = load_font_from_data_dir(file);
2530 return ret;
2533 /*************************************************************
2534 * WineEngAddFontMemResourceEx
2537 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2539 GDI_CheckNotLock();
2541 if (ft_handle) /* do it only if we have freetype up and running */
2543 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2545 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2546 memcpy(pFontCopy, pbFont, cbFont);
2548 EnterCriticalSection( &freetype_cs );
2549 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2550 LeaveCriticalSection( &freetype_cs );
2552 if (*pcFonts == 0)
2554 TRACE("AddFontToList failed\n");
2555 HeapFree(GetProcessHeap(), 0, pFontCopy);
2556 return 0;
2558 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2559 * For now return something unique but quite random
2561 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2562 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2565 *pcFonts = 0;
2566 return 0;
2569 /*************************************************************
2570 * WineEngRemoveFontResourceEx
2573 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2575 GDI_CheckNotLock();
2576 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2577 return TRUE;
2580 static const struct nls_update_font_list
2582 UINT ansi_cp, oem_cp;
2583 const char *oem, *fixed, *system;
2584 const char *courier, *serif, *small, *sserif;
2585 /* these are for font substitutes */
2586 const char *shelldlg, *tmsrmn;
2587 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2588 *helv_0, *tmsrmn_0;
2589 const struct subst
2591 const char *from, *to;
2592 } arial_0, courier_new_0, times_new_roman_0;
2593 } nls_update_font_list[] =
2595 /* Latin 1 (United States) */
2596 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2597 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2598 "Tahoma","Times New Roman",
2599 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2600 { 0 }, { 0 }, { 0 }
2602 /* Latin 1 (Multilingual) */
2603 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2604 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2605 "Tahoma","Times New Roman", /* FIXME unverified */
2606 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2607 { 0 }, { 0 }, { 0 }
2609 /* Eastern Europe */
2610 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2611 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2612 "Tahoma","Times New Roman", /* FIXME unverified */
2613 "Fixedsys,238", "System,238",
2614 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2615 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2616 { "Arial CE,0", "Arial,238" },
2617 { "Courier New CE,0", "Courier New,238" },
2618 { "Times New Roman CE,0", "Times New Roman,238" }
2620 /* Cyrillic */
2621 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2622 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2623 "Tahoma","Times New Roman", /* FIXME unverified */
2624 "Fixedsys,204", "System,204",
2625 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2626 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2627 { "Arial Cyr,0", "Arial,204" },
2628 { "Courier New Cyr,0", "Courier New,204" },
2629 { "Times New Roman Cyr,0", "Times New Roman,204" }
2631 /* Greek */
2632 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2633 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2634 "Tahoma","Times New Roman", /* FIXME unverified */
2635 "Fixedsys,161", "System,161",
2636 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2637 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2638 { "Arial Greek,0", "Arial,161" },
2639 { "Courier New Greek,0", "Courier New,161" },
2640 { "Times New Roman Greek,0", "Times New Roman,161" }
2642 /* Turkish */
2643 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2644 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2645 "Tahoma","Times New Roman", /* FIXME unverified */
2646 "Fixedsys,162", "System,162",
2647 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2648 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2649 { "Arial Tur,0", "Arial,162" },
2650 { "Courier New Tur,0", "Courier New,162" },
2651 { "Times New Roman Tur,0", "Times New Roman,162" }
2653 /* Hebrew */
2654 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2655 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2656 "Tahoma","Times New Roman", /* FIXME unverified */
2657 "Fixedsys,177", "System,177",
2658 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2659 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2660 { 0 }, { 0 }, { 0 }
2662 /* Arabic */
2663 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2664 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2665 "Tahoma","Times New Roman", /* FIXME unverified */
2666 "Fixedsys,178", "System,178",
2667 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2668 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2669 { 0 }, { 0 }, { 0 }
2671 /* Baltic */
2672 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2673 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2674 "Tahoma","Times New Roman", /* FIXME unverified */
2675 "Fixedsys,186", "System,186",
2676 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2677 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2678 { "Arial Baltic,0", "Arial,186" },
2679 { "Courier New Baltic,0", "Courier New,186" },
2680 { "Times New Roman Baltic,0", "Times New Roman,186" }
2682 /* Vietnamese */
2683 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2684 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2685 "Tahoma","Times New Roman", /* FIXME unverified */
2686 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2687 { 0 }, { 0 }, { 0 }
2689 /* Thai */
2690 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2691 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2692 "Tahoma","Times New Roman", /* FIXME unverified */
2693 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2694 { 0 }, { 0 }, { 0 }
2696 /* Japanese */
2697 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2698 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2699 "MS UI Gothic","MS Serif",
2700 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2701 { 0 }, { 0 }, { 0 }
2703 /* Chinese Simplified */
2704 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2705 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2706 "SimSun", "NSimSun",
2707 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2708 { 0 }, { 0 }, { 0 }
2710 /* Korean */
2711 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2712 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2713 "Gulim", "Batang",
2714 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2715 { 0 }, { 0 }, { 0 }
2717 /* Chinese Traditional */
2718 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2719 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2720 "PMingLiU", "MingLiU",
2721 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2722 { 0 }, { 0 }, { 0 }
2726 static const WCHAR *font_links_list[] =
2728 Lucida_Sans_Unicode,
2729 Microsoft_Sans_Serif,
2730 Tahoma
2733 static const struct font_links_defaults_list
2735 /* Keyed off substitution for "MS Shell Dlg" */
2736 const WCHAR *shelldlg;
2737 /* Maximum of four substitutes, plus terminating NULL pointer */
2738 const WCHAR *substitutes[5];
2739 } font_links_defaults_list[] =
2741 /* Non East-Asian */
2742 { Tahoma, /* FIXME unverified ordering */
2743 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2745 /* Below lists are courtesy of
2746 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2748 /* Japanese */
2749 { MS_UI_Gothic,
2750 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2752 /* Chinese Simplified */
2753 { SimSun,
2754 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2756 /* Korean */
2757 { Gulim,
2758 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2760 /* Chinese Traditional */
2761 { PMingLiU,
2762 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2766 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2768 return ( ansi_cp == 932 /* CP932 for Japanese */
2769 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2770 || ansi_cp == 949 /* CP949 for Korean */
2771 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2774 static inline HKEY create_fonts_NT_registry_key(void)
2776 HKEY hkey = 0;
2778 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2779 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2780 return hkey;
2783 static inline HKEY create_fonts_9x_registry_key(void)
2785 HKEY hkey = 0;
2787 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2788 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2789 return hkey;
2792 static inline HKEY create_config_fonts_registry_key(void)
2794 HKEY hkey = 0;
2796 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2797 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2798 return hkey;
2801 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2803 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2804 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2805 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2806 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2809 static void set_value_key(HKEY hkey, const char *name, const char *value)
2811 if (value)
2812 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2813 else if (name)
2814 RegDeleteValueA(hkey, name);
2817 static void update_font_info(void)
2819 char buf[40], cpbuf[40];
2820 DWORD len, type;
2821 HKEY hkey = 0;
2822 UINT i, ansi_cp = 0, oem_cp = 0;
2823 BOOL done = FALSE;
2825 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2826 return;
2828 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2829 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2830 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2831 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2832 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2834 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2835 if (is_dbcs_ansi_cp(ansi_cp))
2836 use_default_fallback = TRUE;
2838 len = sizeof(buf);
2839 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2841 if (!strcmp( buf, cpbuf )) /* already set correctly */
2843 RegCloseKey(hkey);
2844 return;
2846 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2848 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2850 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2851 RegCloseKey(hkey);
2853 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2855 HKEY hkey;
2857 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2858 nls_update_font_list[i].oem_cp == oem_cp)
2860 hkey = create_config_fonts_registry_key();
2861 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2862 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2863 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2864 RegCloseKey(hkey);
2866 hkey = create_fonts_NT_registry_key();
2867 add_font_list(hkey, &nls_update_font_list[i]);
2868 RegCloseKey(hkey);
2870 hkey = create_fonts_9x_registry_key();
2871 add_font_list(hkey, &nls_update_font_list[i]);
2872 RegCloseKey(hkey);
2874 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2876 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2877 strlen(nls_update_font_list[i].shelldlg)+1);
2878 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2879 strlen(nls_update_font_list[i].tmsrmn)+1);
2881 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2882 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2883 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2884 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2885 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2886 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2887 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2888 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2890 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2891 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2892 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2894 RegCloseKey(hkey);
2896 done = TRUE;
2898 else
2900 /* Delete the FontSubstitutes from other locales */
2901 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2903 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2904 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2905 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2906 RegCloseKey(hkey);
2910 if (!done)
2911 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2914 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2916 const WCHAR *value;
2917 int i;
2918 FontSubst *psub;
2919 Family *family;
2920 Face *face;
2921 const char *file;
2922 WCHAR *fileW;
2923 WCHAR buff[MAX_PATH];
2924 WCHAR *data;
2925 int entryLen;
2927 static const WCHAR comma[] = {',',0};
2929 RegDeleteValueW(hkey, name);
2930 if (values)
2932 data = buff;
2933 data[0] = '\0';
2934 for (i = 0; values[i] != NULL; i++)
2936 value = values[i];
2937 if (!strcmpiW(name,value))
2938 continue;
2939 psub = get_font_subst(&font_subst_list, value, -1);
2940 if(psub)
2941 value = psub->to.name;
2942 family = find_family_from_name(value);
2943 if (!family)
2944 continue;
2945 file = NULL;
2946 /* Use first extant filename for this Family */
2947 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2949 if (!face->file)
2950 continue;
2951 file = strrchr(face->file, '/');
2952 if (!file)
2953 file = face->file;
2954 else
2955 file++;
2956 break;
2958 if (!file)
2959 continue;
2960 fileW = towstr(CP_UNIXCP, file);
2961 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2962 if (sizeof(buff)-(data-buff) < entryLen + 1)
2964 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2965 HeapFree(GetProcessHeap(), 0, fileW);
2966 break;
2968 strcpyW(data, fileW);
2969 strcatW(data, comma);
2970 strcatW(data, value);
2971 data += entryLen;
2972 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2973 HeapFree(GetProcessHeap(), 0, fileW);
2975 if (data != buff)
2977 *data='\0';
2978 data++;
2979 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2980 } else
2981 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2982 } else
2983 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2986 static void update_system_links(void)
2988 HKEY hkey = 0;
2989 UINT i, j;
2990 BOOL done = FALSE;
2991 DWORD disposition;
2992 FontSubst *psub;
2994 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2996 if (!RegCreateKeyExW(HKEY_CURRENT_USER, internal_system_link, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2998 if (disposition == REG_OPENED_EXISTING_KEY)
3000 TRACE("SystemLink key already exists, doing nothing\n");
3001 RegCloseKey(hkey);
3002 return;
3005 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
3006 if (!psub) {
3007 WARN("could not find FontSubstitute for MS Shell Dlg\n");
3008 RegCloseKey(hkey);
3009 return;
3012 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
3014 const FontSubst *psub2;
3015 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
3017 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
3019 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
3020 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
3022 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
3023 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
3024 done = TRUE;
3026 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
3028 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
3031 RegCloseKey(hkey);
3032 if (!done)
3033 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
3034 } else
3035 WARN("failed to create Internal SystemLink key\n");
3039 static BOOL init_freetype(void)
3041 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3042 if(!ft_handle) {
3043 WINE_MESSAGE(
3044 "Wine cannot find the FreeType font library. To enable Wine to\n"
3045 "use TrueType fonts please install a version of FreeType greater than\n"
3046 "or equal to 2.0.5.\n"
3047 "http://www.freetype.org\n");
3048 return FALSE;
3051 #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;}
3053 LOAD_FUNCPTR(FT_Done_Face)
3054 LOAD_FUNCPTR(FT_Get_Char_Index)
3055 LOAD_FUNCPTR(FT_Get_First_Char)
3056 LOAD_FUNCPTR(FT_Get_Module)
3057 LOAD_FUNCPTR(FT_Get_Next_Char)
3058 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3059 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3060 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3061 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3062 LOAD_FUNCPTR(FT_Init_FreeType)
3063 LOAD_FUNCPTR(FT_Library_Version)
3064 LOAD_FUNCPTR(FT_Load_Glyph)
3065 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3066 LOAD_FUNCPTR(FT_Matrix_Multiply)
3067 #ifndef FT_MULFIX_INLINED
3068 LOAD_FUNCPTR(FT_MulFix)
3069 #endif
3070 LOAD_FUNCPTR(FT_New_Face)
3071 LOAD_FUNCPTR(FT_New_Memory_Face)
3072 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3073 LOAD_FUNCPTR(FT_Outline_Transform)
3074 LOAD_FUNCPTR(FT_Outline_Translate)
3075 LOAD_FUNCPTR(FT_Render_Glyph)
3076 LOAD_FUNCPTR(FT_Select_Charmap)
3077 LOAD_FUNCPTR(FT_Set_Charmap)
3078 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3079 LOAD_FUNCPTR(FT_Vector_Transform)
3080 LOAD_FUNCPTR(FT_Vector_Unit)
3081 #undef LOAD_FUNCPTR
3082 /* Don't warn if these ones are missing */
3083 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3084 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3085 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3086 #endif
3088 if(pFT_Init_FreeType(&library) != 0) {
3089 ERR("Can't init FreeType library\n");
3090 wine_dlclose(ft_handle, NULL, 0);
3091 ft_handle = NULL;
3092 return FALSE;
3094 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3096 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3097 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3098 ((FT_Version.minor << 8) & 0x00ff00) |
3099 ((FT_Version.patch ) & 0x0000ff);
3101 font_driver = &freetype_funcs;
3102 return TRUE;
3104 sym_not_found:
3105 WINE_MESSAGE(
3106 "Wine cannot find certain functions that it needs inside the FreeType\n"
3107 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3108 "FreeType to at least version 2.1.4.\n"
3109 "http://www.freetype.org\n");
3110 wine_dlclose(ft_handle, NULL, 0);
3111 ft_handle = NULL;
3112 return FALSE;
3115 static void init_font_list(void)
3117 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3118 static const WCHAR pathW[] = {'P','a','t','h',0};
3119 HKEY hkey;
3120 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3121 WCHAR windowsdir[MAX_PATH];
3122 char *unixname;
3123 const char *home;
3124 const char *data_dir;
3126 delete_external_font_keys();
3128 /* load the system bitmap fonts */
3129 load_system_fonts();
3131 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3132 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3133 strcatW(windowsdir, fontsW);
3134 if((unixname = wine_get_unix_file_name(windowsdir)))
3136 ReadFontDir(unixname, FALSE);
3137 HeapFree(GetProcessHeap(), 0, unixname);
3140 /* load the system truetype fonts */
3141 data_dir = wine_get_data_dir();
3142 if (!data_dir) data_dir = wine_get_build_dir();
3143 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3145 strcpy(unixname, data_dir);
3146 strcat(unixname, "/fonts/");
3147 ReadFontDir(unixname, TRUE);
3148 HeapFree(GetProcessHeap(), 0, unixname);
3151 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3152 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3153 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3154 will skip these. */
3155 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3156 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3157 &hkey) == ERROR_SUCCESS)
3159 LPWSTR data, valueW;
3160 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3161 &valuelen, &datalen, NULL, NULL);
3163 valuelen++; /* returned value doesn't include room for '\0' */
3164 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3165 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3166 if (valueW && data)
3168 dlen = datalen * sizeof(WCHAR);
3169 vlen = valuelen;
3170 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3171 &dlen) == ERROR_SUCCESS)
3173 if(data[0] && (data[1] == ':'))
3175 if((unixname = wine_get_unix_file_name(data)))
3177 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3178 HeapFree(GetProcessHeap(), 0, unixname);
3181 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3183 WCHAR pathW[MAX_PATH];
3184 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3185 BOOL added = FALSE;
3187 sprintfW(pathW, fmtW, windowsdir, data);
3188 if((unixname = wine_get_unix_file_name(pathW)))
3190 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3191 HeapFree(GetProcessHeap(), 0, unixname);
3193 if (!added)
3194 load_font_from_data_dir(data);
3196 /* reset dlen and vlen */
3197 dlen = datalen;
3198 vlen = valuelen;
3201 HeapFree(GetProcessHeap(), 0, data);
3202 HeapFree(GetProcessHeap(), 0, valueW);
3203 RegCloseKey(hkey);
3206 load_fontconfig_fonts();
3208 /* then look in any directories that we've specified in the config file */
3209 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3210 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3212 DWORD len;
3213 LPWSTR valueW;
3214 LPSTR valueA, ptr;
3216 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3218 len += sizeof(WCHAR);
3219 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3220 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3222 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3223 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3224 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3225 TRACE( "got font path %s\n", debugstr_a(valueA) );
3226 ptr = valueA;
3227 while (ptr)
3229 LPSTR next = strchr( ptr, ':' );
3230 if (next) *next++ = 0;
3231 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3232 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3234 strcpy( unixname, home );
3235 strcat( unixname, ptr + 1 );
3236 ReadFontDir( unixname, TRUE );
3237 HeapFree( GetProcessHeap(), 0, unixname );
3239 else
3240 ReadFontDir( ptr, TRUE );
3241 ptr = next;
3243 HeapFree( GetProcessHeap(), 0, valueA );
3245 HeapFree( GetProcessHeap(), 0, valueW );
3247 RegCloseKey(hkey);
3250 #ifdef __APPLE__
3251 /* Mac default font locations. */
3252 ReadFontDir( "/Library/Fonts", TRUE );
3253 ReadFontDir( "/Network/Library/Fonts", TRUE );
3254 ReadFontDir( "/System/Library/Fonts", TRUE );
3255 if ((home = getenv( "HOME" )))
3257 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3258 strcpy( unixname, home );
3259 strcat( unixname, "/Library/Fonts" );
3260 ReadFontDir( unixname, TRUE);
3261 HeapFree( GetProcessHeap(), 0, unixname );
3263 #endif
3266 static BOOL move_to_front(const WCHAR *name)
3268 Family *family, *cursor2;
3269 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3271 if(!strcmpiW(family->FamilyName, name))
3273 list_remove(&family->entry);
3274 list_add_head(&font_list, &family->entry);
3275 return TRUE;
3278 return FALSE;
3281 static BOOL set_default(const WCHAR **name_list)
3283 while (*name_list)
3285 if (move_to_front(*name_list)) return TRUE;
3286 name_list++;
3289 return FALSE;
3292 static void reorder_font_list(void)
3294 set_default( default_serif_list );
3295 set_default( default_fixed_list );
3296 set_default( default_sans_list );
3299 /*************************************************************
3300 * WineEngInit
3302 * Initialize FreeType library and create a list of available faces
3304 BOOL WineEngInit(void)
3306 HKEY hkey_font_cache;
3307 DWORD disposition;
3308 HANDLE font_mutex;
3310 /* update locale dependent font info in registry */
3311 update_font_info();
3313 if(!init_freetype()) return FALSE;
3315 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3317 ERR("Failed to create font mutex\n");
3318 return FALSE;
3320 WaitForSingleObject(font_mutex, INFINITE);
3322 create_font_cache_key(&hkey_font_cache, &disposition);
3324 if(disposition == REG_CREATED_NEW_KEY)
3325 init_font_list();
3326 else
3327 load_font_list_from_cache(hkey_font_cache);
3329 RegCloseKey(hkey_font_cache);
3331 reorder_font_list();
3333 DumpFontList();
3334 LoadSubstList();
3335 DumpSubstList();
3336 LoadReplaceList();
3338 if(disposition == REG_CREATED_NEW_KEY)
3339 update_reg_entries();
3341 update_system_links();
3342 init_system_links();
3344 ReleaseMutex(font_mutex);
3345 return TRUE;
3349 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3351 TT_OS2 *pOS2;
3352 TT_HoriHeader *pHori;
3354 LONG ppem;
3356 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3357 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3359 if(height == 0) height = 16;
3361 /* Calc. height of EM square:
3363 * For +ve lfHeight we have
3364 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3365 * Re-arranging gives:
3366 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3368 * For -ve lfHeight we have
3369 * |lfHeight| = ppem
3370 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3371 * with il = winAscent + winDescent - units_per_em]
3375 if(height > 0) {
3376 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3377 ppem = MulDiv(ft_face->units_per_EM, height,
3378 pHori->Ascender - pHori->Descender);
3379 else
3380 ppem = MulDiv(ft_face->units_per_EM, height,
3381 pOS2->usWinAscent + pOS2->usWinDescent);
3383 else
3384 ppem = -height;
3386 return ppem;
3389 static struct font_mapping *map_font_file( const char *name )
3391 struct font_mapping *mapping;
3392 struct stat st;
3393 int fd;
3395 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3396 if (fstat( fd, &st ) == -1) goto error;
3398 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3400 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3402 mapping->refcount++;
3403 close( fd );
3404 return mapping;
3407 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3408 goto error;
3410 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3411 close( fd );
3413 if (mapping->data == MAP_FAILED)
3415 HeapFree( GetProcessHeap(), 0, mapping );
3416 return NULL;
3418 mapping->refcount = 1;
3419 mapping->dev = st.st_dev;
3420 mapping->ino = st.st_ino;
3421 mapping->size = st.st_size;
3422 list_add_tail( &mappings_list, &mapping->entry );
3423 return mapping;
3425 error:
3426 close( fd );
3427 return NULL;
3430 static void unmap_font_file( struct font_mapping *mapping )
3432 if (!--mapping->refcount)
3434 list_remove( &mapping->entry );
3435 munmap( mapping->data, mapping->size );
3436 HeapFree( GetProcessHeap(), 0, mapping );
3440 static LONG load_VDMX(GdiFont*, LONG);
3442 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3444 FT_Error err;
3445 FT_Face ft_face;
3446 void *data_ptr;
3447 DWORD data_size;
3449 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3451 if (face->file)
3453 if (!(font->mapping = map_font_file( face->file )))
3455 WARN("failed to map %s\n", debugstr_a(face->file));
3456 return 0;
3458 data_ptr = font->mapping->data;
3459 data_size = font->mapping->size;
3461 else
3463 data_ptr = face->font_data_ptr;
3464 data_size = face->font_data_size;
3467 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3468 if(err) {
3469 ERR("FT_New_Face rets %d\n", err);
3470 return 0;
3473 /* set it here, as load_VDMX needs it */
3474 font->ft_face = ft_face;
3476 if(FT_IS_SCALABLE(ft_face)) {
3477 /* load the VDMX table if we have one */
3478 font->ppem = load_VDMX(font, height);
3479 if(font->ppem == 0)
3480 font->ppem = calc_ppem_for_height(ft_face, height);
3481 TRACE("height %d => ppem %d\n", height, font->ppem);
3483 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3484 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3485 } else {
3486 font->ppem = height;
3487 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3488 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3490 return ft_face;
3494 static int get_nearest_charset(Face *face, int *cp)
3496 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3497 a single face with the requested charset. The idea is to check if
3498 the selected font supports the current ANSI codepage, if it does
3499 return the corresponding charset, else return the first charset */
3501 CHARSETINFO csi;
3502 int acp = GetACP(), i;
3503 DWORD fs0;
3505 *cp = acp;
3506 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3507 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3508 return csi.ciCharset;
3510 for(i = 0; i < 32; i++) {
3511 fs0 = 1L << i;
3512 if(face->fs.fsCsb[0] & fs0) {
3513 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3514 *cp = csi.ciACP;
3515 return csi.ciCharset;
3517 else
3518 FIXME("TCI failing on %x\n", fs0);
3522 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3523 face->fs.fsCsb[0], face->file);
3524 *cp = acp;
3525 return DEFAULT_CHARSET;
3528 static GdiFont *alloc_font(void)
3530 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3531 ret->gmsize = 1;
3532 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3533 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3534 ret->potm = NULL;
3535 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3536 ret->total_kern_pairs = (DWORD)-1;
3537 ret->kern_pairs = NULL;
3538 list_init(&ret->hfontlist);
3539 list_init(&ret->child_fonts);
3540 return ret;
3543 static void free_font(GdiFont *font)
3545 struct list *cursor, *cursor2;
3546 DWORD i;
3548 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3550 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3551 list_remove(cursor);
3552 if(child->font)
3553 free_font(child->font);
3554 HeapFree(GetProcessHeap(), 0, child);
3557 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3559 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3560 DeleteObject(hfontlist->hfont);
3561 list_remove(&hfontlist->entry);
3562 HeapFree(GetProcessHeap(), 0, hfontlist);
3565 if (font->ft_face) pFT_Done_Face(font->ft_face);
3566 if (font->mapping) unmap_font_file( font->mapping );
3567 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3568 HeapFree(GetProcessHeap(), 0, font->potm);
3569 HeapFree(GetProcessHeap(), 0, font->name);
3570 for (i = 0; i < font->gmsize; i++)
3571 HeapFree(GetProcessHeap(),0,font->gm[i]);
3572 HeapFree(GetProcessHeap(), 0, font->gm);
3573 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3574 HeapFree(GetProcessHeap(), 0, font);
3578 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3580 FT_Face ft_face = font->ft_face;
3581 FT_ULong len;
3582 FT_Error err;
3584 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3586 if(!buf)
3587 len = 0;
3588 else
3589 len = cbData;
3591 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3593 /* make sure value of len is the value freetype says it needs */
3594 if (buf && len)
3596 FT_ULong needed = 0;
3597 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3598 if( !err && needed < len) len = needed;
3600 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3601 if (err)
3603 TRACE("Can't find table %c%c%c%c\n",
3604 /* bytes were reversed */
3605 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3606 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3607 return GDI_ERROR;
3609 return len;
3612 /*************************************************************
3613 * load_VDMX
3615 * load the vdmx entry for the specified height
3618 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3619 ( ( (FT_ULong)_x4 << 24 ) | \
3620 ( (FT_ULong)_x3 << 16 ) | \
3621 ( (FT_ULong)_x2 << 8 ) | \
3622 (FT_ULong)_x1 )
3624 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3626 typedef struct {
3627 BYTE bCharSet;
3628 BYTE xRatio;
3629 BYTE yStartRatio;
3630 BYTE yEndRatio;
3631 } Ratios;
3633 typedef struct {
3634 WORD recs;
3635 BYTE startsz;
3636 BYTE endsz;
3637 } VDMX_group;
3639 static LONG load_VDMX(GdiFont *font, LONG height)
3641 WORD hdr[3], tmp;
3642 VDMX_group group;
3643 BYTE devXRatio, devYRatio;
3644 USHORT numRecs, numRatios;
3645 DWORD result, offset = -1;
3646 LONG ppem = 0;
3647 int i;
3649 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3651 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3652 return ppem;
3654 /* FIXME: need the real device aspect ratio */
3655 devXRatio = 1;
3656 devYRatio = 1;
3658 numRecs = GET_BE_WORD(hdr[1]);
3659 numRatios = GET_BE_WORD(hdr[2]);
3661 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3662 for(i = 0; i < numRatios; i++) {
3663 Ratios ratio;
3665 offset = (3 * 2) + (i * sizeof(Ratios));
3666 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3667 offset = -1;
3669 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3671 if((ratio.xRatio == 0 &&
3672 ratio.yStartRatio == 0 &&
3673 ratio.yEndRatio == 0) ||
3674 (devXRatio == ratio.xRatio &&
3675 devYRatio >= ratio.yStartRatio &&
3676 devYRatio <= ratio.yEndRatio))
3678 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3679 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3680 offset = GET_BE_WORD(tmp);
3681 break;
3685 if(offset == -1) {
3686 FIXME("No suitable ratio found\n");
3687 return ppem;
3690 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3691 USHORT recs;
3692 BYTE startsz, endsz;
3693 WORD *vTable;
3695 recs = GET_BE_WORD(group.recs);
3696 startsz = group.startsz;
3697 endsz = group.endsz;
3699 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3701 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3702 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3703 if(result == GDI_ERROR) {
3704 FIXME("Failed to retrieve vTable\n");
3705 goto end;
3708 if(height > 0) {
3709 for(i = 0; i < recs; i++) {
3710 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3711 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3712 ppem = GET_BE_WORD(vTable[i * 3]);
3714 if(yMax + -yMin == height) {
3715 font->yMax = yMax;
3716 font->yMin = yMin;
3717 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3718 break;
3720 if(yMax + -yMin > height) {
3721 if(--i < 0) {
3722 ppem = 0;
3723 goto end; /* failed */
3725 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3726 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3727 ppem = GET_BE_WORD(vTable[i * 3]);
3728 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3729 break;
3732 if(!font->yMax) {
3733 ppem = 0;
3734 TRACE("ppem not found for height %d\n", height);
3737 end:
3738 HeapFree(GetProcessHeap(), 0, vTable);
3741 return ppem;
3744 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3746 if(font->font_desc.hash != fd->hash) return TRUE;
3747 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3748 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3749 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3750 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3753 static void calc_hash(FONT_DESC *pfd)
3755 DWORD hash = 0, *ptr, two_chars;
3756 WORD *pwc;
3757 unsigned int i;
3759 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3760 hash ^= *ptr;
3761 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3762 hash ^= *ptr;
3763 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3764 two_chars = *ptr;
3765 pwc = (WCHAR *)&two_chars;
3766 if(!*pwc) break;
3767 *pwc = toupperW(*pwc);
3768 pwc++;
3769 *pwc = toupperW(*pwc);
3770 hash ^= two_chars;
3771 if(!*pwc) break;
3773 hash ^= !pfd->can_use_bitmap;
3774 pfd->hash = hash;
3775 return;
3778 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3780 GdiFont *ret;
3781 FONT_DESC fd;
3782 HFONTLIST *hflist;
3783 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3785 fd.lf = *plf;
3786 fd.matrix = *pmat;
3787 fd.can_use_bitmap = can_use_bitmap;
3788 calc_hash(&fd);
3790 /* try the child list */
3791 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3792 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3793 if(!fontcmp(ret, &fd)) {
3794 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3795 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3796 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3797 if(hflist->hfont == hfont)
3798 return ret;
3803 /* try the in-use list */
3804 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3805 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3806 if(!fontcmp(ret, &fd)) {
3807 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3808 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3809 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3810 if(hflist->hfont == hfont)
3811 return ret;
3813 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3814 hflist->hfont = hfont;
3815 list_add_head(&ret->hfontlist, &hflist->entry);
3816 return ret;
3820 /* then the unused list */
3821 font_elem_ptr = list_head(&unused_gdi_font_list);
3822 while(font_elem_ptr) {
3823 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3824 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3825 if(!fontcmp(ret, &fd)) {
3826 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3827 assert(list_empty(&ret->hfontlist));
3828 TRACE("Found %p in unused list\n", ret);
3829 list_remove(&ret->entry);
3830 list_add_head(&gdi_font_list, &ret->entry);
3831 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3832 hflist->hfont = hfont;
3833 list_add_head(&ret->hfontlist, &hflist->entry);
3834 return ret;
3837 return NULL;
3840 static void add_to_cache(GdiFont *font)
3842 static DWORD cache_num = 1;
3844 font->cache_num = cache_num++;
3845 list_add_head(&gdi_font_list, &font->entry);
3848 /*************************************************************
3849 * create_child_font_list
3851 static BOOL create_child_font_list(GdiFont *font)
3853 BOOL ret = FALSE;
3854 SYSTEM_LINKS *font_link;
3855 CHILD_FONT *font_link_entry, *new_child;
3856 FontSubst *psub;
3857 WCHAR* font_name;
3859 psub = get_font_subst(&font_subst_list, font->name, -1);
3860 font_name = psub ? psub->to.name : font->name;
3861 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3863 if(!strcmpiW(font_link->font_name, font_name))
3865 TRACE("found entry in system list\n");
3866 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3868 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3869 new_child->face = font_link_entry->face;
3870 new_child->font = NULL;
3871 list_add_tail(&font->child_fonts, &new_child->entry);
3872 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3874 ret = TRUE;
3875 break;
3879 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3880 * Sans Serif. This is how asian windows get default fallbacks for fonts
3882 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3883 font->charset != OEM_CHARSET &&
3884 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3885 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3887 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3889 TRACE("found entry in default fallback list\n");
3890 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3892 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3893 new_child->face = font_link_entry->face;
3894 new_child->font = NULL;
3895 list_add_tail(&font->child_fonts, &new_child->entry);
3896 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3898 ret = TRUE;
3899 break;
3903 return ret;
3906 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3908 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3910 if (pFT_Set_Charmap)
3912 FT_Int i;
3913 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3915 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3917 for (i = 0; i < ft_face->num_charmaps; i++)
3919 if (ft_face->charmaps[i]->encoding == encoding)
3921 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3922 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3924 switch (ft_face->charmaps[i]->platform_id)
3926 default:
3927 cmap_def = ft_face->charmaps[i];
3928 break;
3929 case 0: /* Apple Unicode */
3930 cmap0 = ft_face->charmaps[i];
3931 break;
3932 case 1: /* Macintosh */
3933 cmap1 = ft_face->charmaps[i];
3934 break;
3935 case 2: /* ISO */
3936 cmap2 = ft_face->charmaps[i];
3937 break;
3938 case 3: /* Microsoft */
3939 cmap3 = ft_face->charmaps[i];
3940 break;
3944 if (cmap3) /* prefer Microsoft cmap table */
3945 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3946 else if (cmap1)
3947 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3948 else if (cmap2)
3949 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3950 else if (cmap0)
3951 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3952 else if (cmap_def)
3953 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3955 return ft_err == FT_Err_Ok;
3958 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3962 /*************************************************************
3963 * freetype_CreateDC
3965 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3966 LPCWSTR output, const DEVMODEW *devmode )
3968 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3970 if (!physdev) return FALSE;
3971 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3972 return TRUE;
3976 /*************************************************************
3977 * freetype_DeleteDC
3979 static BOOL freetype_DeleteDC( PHYSDEV dev )
3981 struct freetype_physdev *physdev = get_freetype_dev( dev );
3982 HeapFree( GetProcessHeap(), 0, physdev );
3983 return TRUE;
3987 /*************************************************************
3988 * freetype_SelectFont
3990 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3992 struct freetype_physdev *physdev = get_freetype_dev( dev );
3993 GdiFont *ret;
3994 Face *face, *best, *best_bitmap;
3995 Family *family, *last_resort_family;
3996 struct list *family_elem_ptr, *face_elem_ptr;
3997 INT height, width = 0;
3998 unsigned int score = 0, new_score;
3999 signed int diff = 0, newdiff;
4000 BOOL bd, it, can_use_bitmap, want_vertical;
4001 LOGFONTW lf;
4002 CHARSETINFO csi;
4003 HFONTLIST *hflist;
4004 FMAT2 dcmat;
4005 FontSubst *psub = NULL;
4006 DC *dc = get_dc_ptr( dev->hdc );
4008 if (!hfont) /* notification that the font has been changed by another driver */
4010 dc->gdiFont = NULL;
4011 physdev->font = NULL;
4012 release_dc_ptr( dc );
4013 return 0;
4016 GetObjectW( hfont, sizeof(lf), &lf );
4017 lf.lfWidth = abs(lf.lfWidth);
4019 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4021 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4022 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4023 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4024 lf.lfEscapement);
4026 if(dc->GraphicsMode == GM_ADVANCED)
4027 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4028 else
4030 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4031 font scaling abilities. */
4032 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
4033 dcmat.eM21 = dcmat.eM12 = 0;
4036 /* Try to avoid not necessary glyph transformations */
4037 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4039 lf.lfHeight *= fabs(dcmat.eM11);
4040 lf.lfWidth *= fabs(dcmat.eM11);
4041 dcmat.eM11 = dcmat.eM22 = 1.0;
4044 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4045 dcmat.eM21, dcmat.eM22);
4047 GDI_CheckNotLock();
4048 EnterCriticalSection( &freetype_cs );
4050 /* check the cache first */
4051 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4052 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4053 goto done;
4056 if(list_empty(&font_list)) /* No fonts installed */
4058 TRACE("No fonts installed\n");
4059 goto done;
4062 TRACE("not in cache\n");
4063 ret = alloc_font();
4065 ret->font_desc.matrix = dcmat;
4066 ret->font_desc.lf = lf;
4067 ret->font_desc.can_use_bitmap = can_use_bitmap;
4068 calc_hash(&ret->font_desc);
4069 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4070 hflist->hfont = hfont;
4071 list_add_head(&ret->hfontlist, &hflist->entry);
4073 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4074 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4075 original value lfCharSet. Note this is a special case for
4076 Symbol and doesn't happen at least for "Wingdings*" */
4078 if(!strcmpiW(lf.lfFaceName, SymbolW))
4079 lf.lfCharSet = SYMBOL_CHARSET;
4081 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4082 switch(lf.lfCharSet) {
4083 case DEFAULT_CHARSET:
4084 csi.fs.fsCsb[0] = 0;
4085 break;
4086 default:
4087 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4088 csi.fs.fsCsb[0] = 0;
4089 break;
4093 family = NULL;
4094 if(lf.lfFaceName[0] != '\0') {
4095 SYSTEM_LINKS *font_link;
4096 CHILD_FONT *font_link_entry;
4097 LPWSTR FaceName = lf.lfFaceName;
4099 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4101 if(psub) {
4102 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4103 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4104 if (psub->to.charset != -1)
4105 lf.lfCharSet = psub->to.charset;
4108 /* We want a match on name and charset or just name if
4109 charset was DEFAULT_CHARSET. If the latter then
4110 we fixup the returned charset later in get_nearest_charset
4111 where we'll either use the charset of the current ansi codepage
4112 or if that's unavailable the first charset that the font supports.
4114 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4115 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4116 if (!strcmpiW(family->FamilyName, FaceName) ||
4117 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4119 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4120 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4121 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4122 if(face->scalable || can_use_bitmap)
4123 goto found;
4128 /* Search by full face name. */
4129 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4130 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4131 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4132 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4133 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4134 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
4136 if(face->scalable || can_use_bitmap)
4137 goto found_face;
4143 * Try check the SystemLink list first for a replacement font.
4144 * We may find good replacements there.
4146 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4148 if(!strcmpiW(font_link->font_name, FaceName) ||
4149 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4151 TRACE("found entry in system list\n");
4152 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4154 face = font_link_entry->face;
4155 family = face->family;
4156 if(csi.fs.fsCsb[0] &
4157 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4159 if(face->scalable || can_use_bitmap)
4160 goto found;
4167 psub = NULL; /* substitution is no more relevant */
4169 /* If requested charset was DEFAULT_CHARSET then try using charset
4170 corresponding to the current ansi codepage */
4171 if (!csi.fs.fsCsb[0])
4173 INT acp = GetACP();
4174 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4175 FIXME("TCI failed on codepage %d\n", acp);
4176 csi.fs.fsCsb[0] = 0;
4177 } else
4178 lf.lfCharSet = csi.ciCharset;
4181 want_vertical = (lf.lfFaceName[0] == '@');
4183 /* Face families are in the top 4 bits of lfPitchAndFamily,
4184 so mask with 0xF0 before testing */
4186 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4187 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4188 strcpyW(lf.lfFaceName, defFixed);
4189 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4190 strcpyW(lf.lfFaceName, defSerif);
4191 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4192 strcpyW(lf.lfFaceName, defSans);
4193 else
4194 strcpyW(lf.lfFaceName, defSans);
4195 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4196 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4197 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4198 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4199 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4200 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4201 if(face->scalable || can_use_bitmap)
4202 goto found;
4207 last_resort_family = NULL;
4208 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4209 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4210 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4211 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4212 if(face->vertical == want_vertical &&
4213 (csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))) {
4214 if(face->scalable)
4215 goto found;
4216 if(can_use_bitmap && !last_resort_family)
4217 last_resort_family = family;
4222 if(last_resort_family) {
4223 family = last_resort_family;
4224 csi.fs.fsCsb[0] = 0;
4225 goto found;
4228 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4229 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4230 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4231 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4232 if(face->scalable && face->vertical == want_vertical) {
4233 csi.fs.fsCsb[0] = 0;
4234 WARN("just using first face for now\n");
4235 goto found;
4237 if(can_use_bitmap && !last_resort_family)
4238 last_resort_family = family;
4241 if(!last_resort_family) {
4242 FIXME("can't find a single appropriate font - bailing\n");
4243 free_font(ret);
4244 ret = NULL;
4245 goto done;
4248 WARN("could only find a bitmap font - this will probably look awful!\n");
4249 family = last_resort_family;
4250 csi.fs.fsCsb[0] = 0;
4252 found:
4253 it = lf.lfItalic ? 1 : 0;
4254 bd = lf.lfWeight > 550 ? 1 : 0;
4256 height = lf.lfHeight;
4258 face = best = best_bitmap = NULL;
4259 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4261 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4263 BOOL italic, bold;
4265 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4266 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4267 new_score = (italic ^ it) + (bold ^ bd);
4268 if(!best || new_score <= score)
4270 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4271 italic, bold, it, bd);
4272 score = new_score;
4273 best = face;
4274 if(best->scalable && score == 0) break;
4275 if(!best->scalable)
4277 if(height > 0)
4278 newdiff = height - (signed int)(best->size.height);
4279 else
4280 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4281 if(!best_bitmap || new_score < score ||
4282 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4284 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4285 diff = newdiff;
4286 best_bitmap = best;
4287 if(score == 0 && diff == 0) break;
4293 if(best)
4294 face = best->scalable ? best : best_bitmap;
4295 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4296 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4298 found_face:
4299 height = lf.lfHeight;
4301 ret->fs = face->fs;
4303 if(csi.fs.fsCsb[0]) {
4304 ret->charset = lf.lfCharSet;
4305 ret->codepage = csi.ciACP;
4307 else
4308 ret->charset = get_nearest_charset(face, &ret->codepage);
4310 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4311 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4313 ret->aveWidth = height ? lf.lfWidth : 0;
4315 if(!face->scalable) {
4316 /* Windows uses integer scaling factors for bitmap fonts */
4317 INT scale, scaled_height;
4318 GdiFont *cachedfont;
4320 /* FIXME: rotation of bitmap fonts is ignored */
4321 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4322 if (ret->aveWidth)
4323 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4324 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4325 dcmat.eM11 = dcmat.eM22 = 1.0;
4326 /* As we changed the matrix, we need to search the cache for the font again,
4327 * otherwise we might explode the cache. */
4328 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4329 TRACE("Found cached font after non-scalable matrix rescale!\n");
4330 free_font( ret );
4331 ret = cachedfont;
4332 goto done;
4334 calc_hash(&ret->font_desc);
4336 if (height != 0) height = diff;
4337 height += face->size.height;
4339 scale = (height + face->size.height - 1) / face->size.height;
4340 scaled_height = scale * face->size.height;
4341 /* Only jump to the next height if the difference <= 25% original height */
4342 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4343 /* The jump between unscaled and doubled is delayed by 1 */
4344 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4345 ret->scale_y = scale;
4347 width = face->size.x_ppem >> 6;
4348 height = face->size.y_ppem >> 6;
4350 else
4351 ret->scale_y = 1.0;
4352 TRACE("font scale y: %f\n", ret->scale_y);
4354 ret->ft_face = OpenFontFace(ret, face, width, height);
4356 if (!ret->ft_face)
4358 free_font( ret );
4359 ret = NULL;
4360 goto done;
4363 ret->ntmFlags = face->ntmFlags;
4365 if (ret->charset == SYMBOL_CHARSET &&
4366 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4367 /* No ops */
4369 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4370 /* No ops */
4372 else {
4373 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4376 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4377 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4378 ret->underline = lf.lfUnderline ? 0xff : 0;
4379 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4380 create_child_font_list(ret);
4382 if (face->vertical) /* We need to try to load the GSUB table */
4384 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4385 if (length != GDI_ERROR)
4387 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4388 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4389 TRACE("Loaded GSUB table of %i bytes\n",length);
4393 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4395 add_to_cache(ret);
4396 done:
4397 if (ret)
4399 dc->gdiFont = ret;
4400 physdev->font = ret;
4402 LeaveCriticalSection( &freetype_cs );
4403 release_dc_ptr( dc );
4404 return ret ? hfont : 0;
4407 static void dump_gdi_font_list(void)
4409 GdiFont *gdiFont;
4410 struct list *elem_ptr;
4412 TRACE("---------- gdiFont Cache ----------\n");
4413 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4414 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4415 TRACE("gdiFont=%p %s %d\n",
4416 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4419 TRACE("---------- Unused gdiFont Cache ----------\n");
4420 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4421 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4422 TRACE("gdiFont=%p %s %d\n",
4423 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4426 TRACE("---------- Child gdiFont Cache ----------\n");
4427 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4428 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4429 TRACE("gdiFont=%p %s %d\n",
4430 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4434 /*************************************************************
4435 * WineEngDestroyFontInstance
4437 * free the gdiFont associated with this handle
4440 BOOL WineEngDestroyFontInstance(HFONT handle)
4442 GdiFont *gdiFont;
4443 HFONTLIST *hflist;
4444 BOOL ret = FALSE;
4445 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4446 int i = 0;
4448 GDI_CheckNotLock();
4449 EnterCriticalSection( &freetype_cs );
4451 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4453 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4454 while(hfontlist_elem_ptr) {
4455 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4456 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4457 if(hflist->hfont == handle) {
4458 TRACE("removing child font %p from child list\n", gdiFont);
4459 list_remove(&gdiFont->entry);
4460 LeaveCriticalSection( &freetype_cs );
4461 return TRUE;
4466 TRACE("destroying hfont=%p\n", handle);
4467 if(TRACE_ON(font))
4468 dump_gdi_font_list();
4470 font_elem_ptr = list_head(&gdi_font_list);
4471 while(font_elem_ptr) {
4472 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4473 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4475 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4476 while(hfontlist_elem_ptr) {
4477 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4478 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4479 if(hflist->hfont == handle) {
4480 list_remove(&hflist->entry);
4481 HeapFree(GetProcessHeap(), 0, hflist);
4482 ret = TRUE;
4485 if(list_empty(&gdiFont->hfontlist)) {
4486 TRACE("Moving to Unused list\n");
4487 list_remove(&gdiFont->entry);
4488 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4493 font_elem_ptr = list_head(&unused_gdi_font_list);
4494 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4495 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4496 while(font_elem_ptr) {
4497 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4498 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4499 TRACE("freeing %p\n", gdiFont);
4500 list_remove(&gdiFont->entry);
4501 free_font(gdiFont);
4503 LeaveCriticalSection( &freetype_cs );
4504 return ret;
4507 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4509 HRSRC rsrc;
4510 HGLOBAL hMem;
4511 WCHAR *p;
4512 int i;
4514 id += IDS_FIRST_SCRIPT;
4515 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4516 if (!rsrc) return 0;
4517 hMem = LoadResource( gdi32_module, rsrc );
4518 if (!hMem) return 0;
4520 p = LockResource( hMem );
4521 id &= 0x000f;
4522 while (id--) p += *p + 1;
4524 i = min(LF_FACESIZE - 1, *p);
4525 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4526 buffer[i] = 0;
4527 return i;
4531 /***************************************************
4532 * create_enum_charset_list
4534 * This function creates charset enumeration list because in DEFAULT_CHARSET
4535 * case, the ANSI codepage's charset takes precedence over other charsets.
4536 * This function works as a filter other than DEFAULT_CHARSET case.
4538 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4540 CHARSETINFO csi;
4541 DWORD n = 0;
4543 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4544 csi.fs.fsCsb[0] != 0) {
4545 list->element[n].mask = csi.fs.fsCsb[0];
4546 list->element[n].charset = csi.ciCharset;
4547 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4548 n++;
4550 else { /* charset is DEFAULT_CHARSET or invalid. */
4551 INT acp, i;
4553 /* Set the current codepage's charset as the first element. */
4554 acp = GetACP();
4555 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4556 csi.fs.fsCsb[0] != 0) {
4557 list->element[n].mask = csi.fs.fsCsb[0];
4558 list->element[n].charset = csi.ciCharset;
4559 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4560 n++;
4563 /* Fill out left elements. */
4564 for (i = 0; i < 32; i++) {
4565 FONTSIGNATURE fs;
4566 fs.fsCsb[0] = 1L << i;
4567 fs.fsCsb[1] = 0;
4568 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4569 continue; /* skip, already added. */
4570 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4571 continue; /* skip, this is an invalid fsCsb bit. */
4573 list->element[n].mask = fs.fsCsb[0];
4574 list->element[n].charset = csi.ciCharset;
4575 load_script_name( i, list->element[n].name );
4576 n++;
4579 list->total = n;
4581 return n;
4584 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4585 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4587 GdiFont *font;
4588 LONG width, height;
4590 if (face->cached_enum_data)
4592 TRACE("Cached\n");
4593 *pelf = face->cached_enum_data->elf;
4594 *pntm = face->cached_enum_data->ntm;
4595 *ptype = face->cached_enum_data->type;
4596 return;
4599 font = alloc_font();
4601 if(face->scalable) {
4602 height = -2048; /* 2048 is the most common em size */
4603 width = 0;
4604 } else {
4605 height = face->size.y_ppem >> 6;
4606 width = face->size.x_ppem >> 6;
4608 font->scale_y = 1.0;
4610 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4612 free_font(font);
4613 return;
4616 font->name = strdupW(face->family->FamilyName);
4617 font->ntmFlags = face->ntmFlags;
4619 if (get_outline_text_metrics(font))
4621 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4623 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4625 lstrcpynW(pelf->elfLogFont.lfFaceName,
4626 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4627 LF_FACESIZE);
4628 lstrcpynW(pelf->elfFullName,
4629 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4630 LF_FULLFACESIZE);
4631 lstrcpynW(pelf->elfStyle,
4632 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4633 LF_FACESIZE);
4635 else
4637 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4639 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4641 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4642 if (face->FullName)
4643 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4644 else
4645 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4646 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4649 pntm->ntmTm.ntmFlags = face->ntmFlags;
4650 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4651 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4652 pntm->ntmFontSig = face->fs;
4654 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4656 pelf->elfLogFont.lfEscapement = 0;
4657 pelf->elfLogFont.lfOrientation = 0;
4658 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4659 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4660 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4661 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4662 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4663 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4664 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4665 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4666 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4667 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4668 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4670 *ptype = 0;
4671 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4672 *ptype |= TRUETYPE_FONTTYPE;
4673 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4674 *ptype |= DEVICE_FONTTYPE;
4675 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4676 *ptype |= RASTER_FONTTYPE;
4678 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4679 if (face->cached_enum_data)
4681 face->cached_enum_data->elf = *pelf;
4682 face->cached_enum_data->ntm = *pntm;
4683 face->cached_enum_data->type = *ptype;
4686 free_font(font);
4689 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4691 struct list *face_elem_ptr;
4693 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4695 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4697 static const WCHAR spaceW[] = { ' ',0 };
4698 WCHAR full_family_name[LF_FULLFACESIZE];
4699 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4701 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4703 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4704 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4705 continue;
4708 strcpyW(full_family_name, family->FamilyName);
4709 strcatW(full_family_name, spaceW);
4710 strcatW(full_family_name, face->StyleName);
4711 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4714 return FALSE;
4717 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4719 static const WCHAR spaceW[] = { ' ',0 };
4720 WCHAR full_family_name[LF_FULLFACESIZE];
4722 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4724 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4726 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4727 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4728 return FALSE;
4731 strcpyW(full_family_name, face->family->FamilyName);
4732 strcatW(full_family_name, spaceW);
4733 strcatW(full_family_name, face->StyleName);
4734 return !strcmpiW(lf->lfFaceName, full_family_name);
4737 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4738 FONTENUMPROCW proc, LPARAM lparam)
4740 ENUMLOGFONTEXW elf;
4741 NEWTEXTMETRICEXW ntm;
4742 DWORD type = 0;
4743 int i;
4745 GetEnumStructs(face, &elf, &ntm, &type);
4746 for(i = 0; i < list->total; i++) {
4747 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4748 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4749 load_script_name( IDS_OEM_DOS, elf.elfScript );
4750 i = list->total; /* break out of loop after enumeration */
4751 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4752 continue;
4753 else {
4754 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4755 strcpyW(elf.elfScript, list->element[i].name);
4756 if (!elf.elfScript[0])
4757 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4759 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4760 debugstr_w(elf.elfLogFont.lfFaceName),
4761 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4762 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4763 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4764 ntm.ntmTm.ntmFlags);
4765 /* release section before callback (FIXME) */
4766 LeaveCriticalSection( &freetype_cs );
4767 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4768 EnterCriticalSection( &freetype_cs );
4770 return TRUE;
4773 /*************************************************************
4774 * freetype_EnumFonts
4776 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4778 Family *family;
4779 Face *face;
4780 struct list *family_elem_ptr, *face_elem_ptr;
4781 LOGFONTW lf;
4782 struct enum_charset_list enum_charsets;
4784 if (!plf)
4786 lf.lfCharSet = DEFAULT_CHARSET;
4787 lf.lfPitchAndFamily = 0;
4788 lf.lfFaceName[0] = 0;
4789 plf = &lf;
4792 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4794 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4796 GDI_CheckNotLock();
4797 EnterCriticalSection( &freetype_cs );
4798 if(plf->lfFaceName[0]) {
4799 FontSubst *psub;
4800 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4802 if(psub) {
4803 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4804 debugstr_w(psub->to.name));
4805 lf = *plf;
4806 strcpyW(lf.lfFaceName, psub->to.name);
4807 plf = &lf;
4810 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4811 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4812 if(family_matches(family, plf)) {
4813 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4814 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4815 if (!face_matches(face, plf)) continue;
4816 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4820 } else {
4821 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4822 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4823 face_elem_ptr = list_head(&family->faces);
4824 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4825 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4828 LeaveCriticalSection( &freetype_cs );
4829 return TRUE;
4832 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4834 pt->x.value = vec->x >> 6;
4835 pt->x.fract = (vec->x & 0x3f) << 10;
4836 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4837 pt->y.value = vec->y >> 6;
4838 pt->y.fract = (vec->y & 0x3f) << 10;
4839 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4840 return;
4843 /***************************************************
4844 * According to the MSDN documentation on WideCharToMultiByte,
4845 * certain codepages cannot set the default_used parameter.
4846 * This returns TRUE if the codepage can set that parameter, false else
4847 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4849 static BOOL codepage_sets_default_used(UINT codepage)
4851 switch (codepage)
4853 case CP_UTF7:
4854 case CP_UTF8:
4855 case CP_SYMBOL:
4856 return FALSE;
4857 default:
4858 return TRUE;
4863 * GSUB Table handling functions
4866 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4868 const GSUB_CoverageFormat1* cf1;
4870 cf1 = table;
4872 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4874 int count = GET_BE_WORD(cf1->GlyphCount);
4875 int i;
4876 TRACE("Coverage Format 1, %i glyphs\n",count);
4877 for (i = 0; i < count; i++)
4878 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4879 return i;
4880 return -1;
4882 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4884 const GSUB_CoverageFormat2* cf2;
4885 int i;
4886 int count;
4887 cf2 = (const GSUB_CoverageFormat2*)cf1;
4889 count = GET_BE_WORD(cf2->RangeCount);
4890 TRACE("Coverage Format 2, %i ranges\n",count);
4891 for (i = 0; i < count; i++)
4893 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4894 return -1;
4895 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4896 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4898 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4899 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4902 return -1;
4904 else
4905 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4907 return -1;
4910 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4912 const GSUB_ScriptList *script;
4913 const GSUB_Script *deflt = NULL;
4914 int i;
4915 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4917 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4918 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4920 const GSUB_Script *scr;
4921 int offset;
4923 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4924 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4926 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4927 return scr;
4928 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4929 deflt = scr;
4931 return deflt;
4934 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4936 int i;
4937 int offset;
4938 const GSUB_LangSys *Lang;
4940 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4942 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4944 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4945 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4947 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4948 return Lang;
4950 offset = GET_BE_WORD(script->DefaultLangSys);
4951 if (offset)
4953 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4954 return Lang;
4956 return NULL;
4959 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4961 int i;
4962 const GSUB_FeatureList *feature;
4963 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4965 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4966 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4968 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4969 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4971 const GSUB_Feature *feat;
4972 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4973 return feat;
4976 return NULL;
4979 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4981 int i;
4982 int offset;
4983 const GSUB_LookupList *lookup;
4984 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4986 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4987 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4989 const GSUB_LookupTable *look;
4990 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4991 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4992 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4993 if (GET_BE_WORD(look->LookupType) != 1)
4994 FIXME("We only handle SubType 1\n");
4995 else
4997 int j;
4999 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5001 const GSUB_SingleSubstFormat1 *ssf1;
5002 offset = GET_BE_WORD(look->SubTable[j]);
5003 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5004 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5006 int offset = GET_BE_WORD(ssf1->Coverage);
5007 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5008 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5010 TRACE(" Glyph 0x%x ->",glyph);
5011 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5012 TRACE(" 0x%x\n",glyph);
5015 else
5017 const GSUB_SingleSubstFormat2 *ssf2;
5018 INT index;
5019 INT offset;
5021 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5022 offset = GET_BE_WORD(ssf1->Coverage);
5023 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5024 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5025 TRACE(" Coverage index %i\n",index);
5026 if (index != -1)
5028 TRACE(" Glyph is 0x%x ->",glyph);
5029 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5030 TRACE("0x%x\n",glyph);
5036 return glyph;
5039 static const char* get_opentype_script(const GdiFont *font)
5042 * I am not sure if this is the correct way to generate our script tag
5045 switch (font->charset)
5047 case ANSI_CHARSET: return "latn";
5048 case BALTIC_CHARSET: return "latn"; /* ?? */
5049 case CHINESEBIG5_CHARSET: return "hani";
5050 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5051 case GB2312_CHARSET: return "hani";
5052 case GREEK_CHARSET: return "grek";
5053 case HANGUL_CHARSET: return "hang";
5054 case RUSSIAN_CHARSET: return "cyrl";
5055 case SHIFTJIS_CHARSET: return "kana";
5056 case TURKISH_CHARSET: return "latn"; /* ?? */
5057 case VIETNAMESE_CHARSET: return "latn";
5058 case JOHAB_CHARSET: return "latn"; /* ?? */
5059 case ARABIC_CHARSET: return "arab";
5060 case HEBREW_CHARSET: return "hebr";
5061 case THAI_CHARSET: return "thai";
5062 default: return "latn";
5066 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5068 const GSUB_Header *header;
5069 const GSUB_Script *script;
5070 const GSUB_LangSys *language;
5071 const GSUB_Feature *feature;
5073 if (!font->GSUB_Table)
5074 return glyph;
5076 header = font->GSUB_Table;
5078 script = GSUB_get_script_table(header, get_opentype_script(font));
5079 if (!script)
5081 TRACE("Script not found\n");
5082 return glyph;
5084 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5085 if (!language)
5087 TRACE("Language not found\n");
5088 return glyph;
5090 feature = GSUB_get_feature(header, language, "vrt2");
5091 if (!feature)
5092 feature = GSUB_get_feature(header, language, "vert");
5093 if (!feature)
5095 TRACE("vrt2/vert feature not found\n");
5096 return glyph;
5098 return GSUB_apply_feature(header, feature, glyph);
5101 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5103 FT_UInt glyphId;
5105 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5106 WCHAR wc = (WCHAR)glyph;
5107 BOOL default_used;
5108 BOOL *default_used_pointer;
5109 FT_UInt ret;
5110 char buf;
5111 default_used_pointer = NULL;
5112 default_used = FALSE;
5113 if (codepage_sets_default_used(font->codepage))
5114 default_used_pointer = &default_used;
5115 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5116 ret = 0;
5117 else
5118 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5119 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5120 return ret;
5123 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5125 if (glyph < 0x100) glyph += 0xf000;
5126 /* there is a number of old pre-Unicode "broken" TTFs, which
5127 do have symbols at U+00XX instead of U+f0XX */
5128 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5129 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5131 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5133 return glyphId;
5136 /*************************************************************
5137 * freetype_GetGlyphIndices
5139 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5141 struct freetype_physdev *physdev = get_freetype_dev( dev );
5142 int i;
5143 WORD default_char;
5144 BOOL got_default = FALSE;
5146 if (!physdev->font)
5148 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5149 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5152 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5154 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5155 got_default = TRUE;
5158 GDI_CheckNotLock();
5159 EnterCriticalSection( &freetype_cs );
5161 for(i = 0; i < count; i++)
5163 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5164 if (pgi[i] == 0)
5166 if (!got_default)
5168 if (FT_IS_SFNT(physdev->font->ft_face))
5170 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5171 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5173 else
5175 TEXTMETRICW textm;
5176 get_text_metrics(physdev->font, &textm);
5177 default_char = textm.tmDefaultChar;
5179 got_default = TRUE;
5181 pgi[i] = default_char;
5184 LeaveCriticalSection( &freetype_cs );
5185 return count;
5188 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5190 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5191 return !memcmp(matrix, &identity, sizeof(FMAT2));
5194 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5196 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5197 return !memcmp(matrix, &identity, sizeof(MAT2));
5200 static inline BYTE get_max_level( UINT format )
5202 switch( format )
5204 case GGO_GRAY2_BITMAP: return 4;
5205 case GGO_GRAY4_BITMAP: return 16;
5206 case GGO_GRAY8_BITMAP: return 64;
5208 return 255;
5211 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5213 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5214 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5215 const MAT2* lpmat)
5217 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5218 FT_Face ft_face = incoming_font->ft_face;
5219 GdiFont *font = incoming_font;
5220 FT_UInt glyph_index;
5221 DWORD width, height, pitch, needed = 0;
5222 FT_Bitmap ft_bitmap;
5223 FT_Error err;
5224 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5225 FT_Angle angle = 0;
5226 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5227 double widthRatio = 1.0;
5228 FT_Matrix transMat = identityMat;
5229 FT_Matrix transMatUnrotated;
5230 BOOL needsTransform = FALSE;
5231 BOOL tategaki = (font->GSUB_Table != NULL);
5232 UINT original_index;
5234 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5235 buflen, buf, lpmat);
5237 TRACE("font transform %f %f %f %f\n",
5238 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5239 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5241 if(format & GGO_GLYPH_INDEX) {
5242 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5243 original_index = glyph;
5244 format &= ~GGO_GLYPH_INDEX;
5245 } else {
5246 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5247 ft_face = font->ft_face;
5248 original_index = glyph_index;
5251 if(format & GGO_UNHINTED) {
5252 load_flags |= FT_LOAD_NO_HINTING;
5253 format &= ~GGO_UNHINTED;
5256 /* tategaki never appears to happen to lower glyph index */
5257 if (glyph_index < TATEGAKI_LOWER_BOUND )
5258 tategaki = FALSE;
5260 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5261 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5262 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5263 font->gmsize * sizeof(GM*));
5264 } else {
5265 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5266 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5268 *lpgm = FONT_GM(font,original_index)->gm;
5269 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5270 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5271 lpgm->gmCellIncX, lpgm->gmCellIncY);
5272 return 1; /* FIXME */
5276 if (!font->gm[original_index / GM_BLOCK_SIZE])
5277 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5279 /* Scaling factor */
5280 if (font->aveWidth)
5282 TEXTMETRICW tm;
5284 get_text_metrics(font, &tm);
5286 widthRatio = (double)font->aveWidth;
5287 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5289 else
5290 widthRatio = font->scale_y;
5292 /* Scaling transform */
5293 if (widthRatio != 1.0 || font->scale_y != 1.0)
5295 FT_Matrix scaleMat;
5296 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5297 scaleMat.xy = 0;
5298 scaleMat.yx = 0;
5299 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5301 pFT_Matrix_Multiply(&scaleMat, &transMat);
5302 needsTransform = TRUE;
5305 /* Slant transform */
5306 if (font->fake_italic) {
5307 FT_Matrix slantMat;
5309 slantMat.xx = (1 << 16);
5310 slantMat.xy = ((1 << 16) >> 2);
5311 slantMat.yx = 0;
5312 slantMat.yy = (1 << 16);
5313 pFT_Matrix_Multiply(&slantMat, &transMat);
5314 needsTransform = TRUE;
5317 /* Rotation transform */
5318 transMatUnrotated = transMat;
5319 if(font->orientation && !tategaki) {
5320 FT_Matrix rotationMat;
5321 FT_Vector vecAngle;
5322 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5323 pFT_Vector_Unit(&vecAngle, angle);
5324 rotationMat.xx = vecAngle.x;
5325 rotationMat.xy = -vecAngle.y;
5326 rotationMat.yx = -rotationMat.xy;
5327 rotationMat.yy = rotationMat.xx;
5329 pFT_Matrix_Multiply(&rotationMat, &transMat);
5330 needsTransform = TRUE;
5333 /* World transform */
5334 if (!is_identity_FMAT2(&font->font_desc.matrix))
5336 FT_Matrix worldMat;
5337 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5338 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5339 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5340 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5341 pFT_Matrix_Multiply(&worldMat, &transMat);
5342 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5343 needsTransform = TRUE;
5346 /* Extra transformation specified by caller */
5347 if (!is_identity_MAT2(lpmat))
5349 FT_Matrix extraMat;
5350 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5351 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5352 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5353 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5354 pFT_Matrix_Multiply(&extraMat, &transMat);
5355 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5356 needsTransform = TRUE;
5359 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5360 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5361 format == GGO_GRAY8_BITMAP))
5363 load_flags |= FT_LOAD_NO_BITMAP;
5366 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5368 if(err) {
5369 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5370 return GDI_ERROR;
5373 if(!needsTransform) {
5374 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5375 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5376 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5378 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5379 bottom = (ft_face->glyph->metrics.horiBearingY -
5380 ft_face->glyph->metrics.height) & -64;
5381 lpgm->gmCellIncX = adv;
5382 lpgm->gmCellIncY = 0;
5383 } else {
5384 INT xc, yc;
5385 FT_Vector vec;
5387 left = right = 0;
5389 for(xc = 0; xc < 2; xc++) {
5390 for(yc = 0; yc < 2; yc++) {
5391 vec.x = (ft_face->glyph->metrics.horiBearingX +
5392 xc * ft_face->glyph->metrics.width);
5393 vec.y = ft_face->glyph->metrics.horiBearingY -
5394 yc * ft_face->glyph->metrics.height;
5395 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5396 pFT_Vector_Transform(&vec, &transMat);
5397 if(xc == 0 && yc == 0) {
5398 left = right = vec.x;
5399 top = bottom = vec.y;
5400 } else {
5401 if(vec.x < left) left = vec.x;
5402 else if(vec.x > right) right = vec.x;
5403 if(vec.y < bottom) bottom = vec.y;
5404 else if(vec.y > top) top = vec.y;
5408 left = left & -64;
5409 right = (right + 63) & -64;
5410 bottom = bottom & -64;
5411 top = (top + 63) & -64;
5413 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5414 vec.x = ft_face->glyph->metrics.horiAdvance;
5415 vec.y = 0;
5416 pFT_Vector_Transform(&vec, &transMat);
5417 lpgm->gmCellIncX = (vec.x+63) >> 6;
5418 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5420 vec.x = ft_face->glyph->metrics.horiAdvance;
5421 vec.y = 0;
5422 pFT_Vector_Transform(&vec, &transMatUnrotated);
5423 adv = (vec.x+63) >> 6;
5426 lsb = left >> 6;
5427 bbx = (right - left) >> 6;
5428 lpgm->gmBlackBoxX = (right - left) >> 6;
5429 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5430 lpgm->gmptGlyphOrigin.x = left >> 6;
5431 lpgm->gmptGlyphOrigin.y = top >> 6;
5433 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5434 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5435 lpgm->gmCellIncX, lpgm->gmCellIncY);
5437 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5438 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5440 FONT_GM(font,original_index)->gm = *lpgm;
5441 FONT_GM(font,original_index)->adv = adv;
5442 FONT_GM(font,original_index)->lsb = lsb;
5443 FONT_GM(font,original_index)->bbx = bbx;
5444 FONT_GM(font,original_index)->init = TRUE;
5447 if(format == GGO_METRICS)
5449 return 1; /* FIXME */
5452 if(ft_face->glyph->format != ft_glyph_format_outline &&
5453 (format == GGO_NATIVE || format == GGO_BEZIER))
5455 TRACE("loaded a bitmap\n");
5456 return GDI_ERROR;
5459 switch(format) {
5460 case GGO_BITMAP:
5461 width = lpgm->gmBlackBoxX;
5462 height = lpgm->gmBlackBoxY;
5463 pitch = ((width + 31) >> 5) << 2;
5464 needed = pitch * height;
5466 if(!buf || !buflen) break;
5468 switch(ft_face->glyph->format) {
5469 case ft_glyph_format_bitmap:
5471 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5472 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5473 INT h = ft_face->glyph->bitmap.rows;
5474 while(h--) {
5475 memcpy(dst, src, w);
5476 src += ft_face->glyph->bitmap.pitch;
5477 dst += pitch;
5479 break;
5482 case ft_glyph_format_outline:
5483 ft_bitmap.width = width;
5484 ft_bitmap.rows = height;
5485 ft_bitmap.pitch = pitch;
5486 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5487 ft_bitmap.buffer = buf;
5489 if(needsTransform)
5490 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5492 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5494 /* Note: FreeType will only set 'black' bits for us. */
5495 memset(buf, 0, needed);
5496 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5497 break;
5499 default:
5500 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5501 return GDI_ERROR;
5503 break;
5505 case GGO_GRAY2_BITMAP:
5506 case GGO_GRAY4_BITMAP:
5507 case GGO_GRAY8_BITMAP:
5508 case WINE_GGO_GRAY16_BITMAP:
5510 unsigned int max_level, row, col;
5511 BYTE *start, *ptr;
5513 width = lpgm->gmBlackBoxX;
5514 height = lpgm->gmBlackBoxY;
5515 pitch = (width + 3) / 4 * 4;
5516 needed = pitch * height;
5518 if(!buf || !buflen) break;
5520 max_level = get_max_level( format );
5522 switch(ft_face->glyph->format) {
5523 case ft_glyph_format_bitmap:
5525 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5526 INT h = ft_face->glyph->bitmap.rows;
5527 INT x;
5528 memset( buf, 0, needed );
5529 while(h--) {
5530 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5531 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5532 src += ft_face->glyph->bitmap.pitch;
5533 dst += pitch;
5535 return needed;
5537 case ft_glyph_format_outline:
5539 ft_bitmap.width = width;
5540 ft_bitmap.rows = height;
5541 ft_bitmap.pitch = pitch;
5542 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5543 ft_bitmap.buffer = buf;
5545 if(needsTransform)
5546 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5548 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5550 memset(ft_bitmap.buffer, 0, buflen);
5552 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5554 if (max_level != 255)
5556 for (row = 0, start = buf; row < height; row++)
5558 for (col = 0, ptr = start; col < width; col++, ptr++)
5559 *ptr = (((int)*ptr) * max_level + 128) / 256;
5560 start += pitch;
5563 return needed;
5566 default:
5567 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5568 return GDI_ERROR;
5570 break;
5573 case WINE_GGO_HRGB_BITMAP:
5574 case WINE_GGO_HBGR_BITMAP:
5575 case WINE_GGO_VRGB_BITMAP:
5576 case WINE_GGO_VBGR_BITMAP:
5577 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5579 switch (ft_face->glyph->format)
5581 case FT_GLYPH_FORMAT_BITMAP:
5583 BYTE *src, *dst;
5584 INT src_pitch, x;
5586 width = lpgm->gmBlackBoxX;
5587 height = lpgm->gmBlackBoxY;
5588 pitch = width * 4;
5589 needed = pitch * height;
5591 if (!buf || !buflen) break;
5593 memset(buf, 0, buflen);
5594 dst = buf;
5595 src = ft_face->glyph->bitmap.buffer;
5596 src_pitch = ft_face->glyph->bitmap.pitch;
5598 height = min( height, ft_face->glyph->bitmap.rows );
5599 while ( height-- )
5601 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5603 if ( src[x / 8] & masks[x % 8] )
5604 ((unsigned int *)dst)[x] = ~0u;
5606 src += src_pitch;
5607 dst += pitch;
5610 break;
5613 case FT_GLYPH_FORMAT_OUTLINE:
5615 unsigned int *dst;
5616 BYTE *src;
5617 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5618 INT x_shift, y_shift;
5619 BOOL rgb;
5620 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5621 FT_Render_Mode render_mode =
5622 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5623 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5625 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5627 if ( render_mode == FT_RENDER_MODE_LCD)
5629 lpgm->gmBlackBoxX += 2;
5630 lpgm->gmptGlyphOrigin.x -= 1;
5632 else
5634 lpgm->gmBlackBoxY += 2;
5635 lpgm->gmptGlyphOrigin.y += 1;
5639 width = lpgm->gmBlackBoxX;
5640 height = lpgm->gmBlackBoxY;
5641 pitch = width * 4;
5642 needed = pitch * height;
5644 if (!buf || !buflen) break;
5646 memset(buf, 0, buflen);
5647 dst = buf;
5648 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5650 if ( needsTransform )
5651 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5653 if ( pFT_Library_SetLcdFilter )
5654 pFT_Library_SetLcdFilter( library, lcdfilter );
5655 pFT_Render_Glyph (ft_face->glyph, render_mode);
5657 src = ft_face->glyph->bitmap.buffer;
5658 src_pitch = ft_face->glyph->bitmap.pitch;
5659 src_width = ft_face->glyph->bitmap.width;
5660 src_height = ft_face->glyph->bitmap.rows;
5662 if ( render_mode == FT_RENDER_MODE_LCD)
5664 rgb_interval = 1;
5665 hmul = 3;
5666 vmul = 1;
5668 else
5670 rgb_interval = src_pitch;
5671 hmul = 1;
5672 vmul = 3;
5675 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5676 if ( x_shift < 0 ) x_shift = 0;
5677 if ( x_shift + (src_width / hmul) > width )
5678 x_shift = width - (src_width / hmul);
5680 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5681 if ( y_shift < 0 ) y_shift = 0;
5682 if ( y_shift + (src_height / vmul) > height )
5683 y_shift = height - (src_height / vmul);
5685 dst += x_shift + y_shift * ( pitch / 4 );
5686 while ( src_height )
5688 for ( x = 0; x < src_width / hmul; x++ )
5690 if ( rgb )
5692 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5693 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5694 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5695 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5697 else
5699 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5700 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5701 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5702 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5705 src += src_pitch * vmul;
5706 dst += pitch / 4;
5707 src_height -= vmul;
5710 break;
5713 default:
5714 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5715 return GDI_ERROR;
5718 break;
5720 #else
5721 return GDI_ERROR;
5722 #endif
5724 case GGO_NATIVE:
5726 int contour, point = 0, first_pt;
5727 FT_Outline *outline = &ft_face->glyph->outline;
5728 TTPOLYGONHEADER *pph;
5729 TTPOLYCURVE *ppc;
5730 DWORD pph_start, cpfx, type;
5732 if(buflen == 0) buf = NULL;
5734 if (needsTransform && buf) {
5735 pFT_Outline_Transform(outline, &transMat);
5738 for(contour = 0; contour < outline->n_contours; contour++) {
5739 pph_start = needed;
5740 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5741 first_pt = point;
5742 if(buf) {
5743 pph->dwType = TT_POLYGON_TYPE;
5744 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5746 needed += sizeof(*pph);
5747 point++;
5748 while(point <= outline->contours[contour]) {
5749 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5750 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5751 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5752 cpfx = 0;
5753 do {
5754 if(buf)
5755 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5756 cpfx++;
5757 point++;
5758 } while(point <= outline->contours[contour] &&
5759 (outline->tags[point] & FT_Curve_Tag_On) ==
5760 (outline->tags[point-1] & FT_Curve_Tag_On));
5761 /* At the end of a contour Windows adds the start point, but
5762 only for Beziers */
5763 if(point > outline->contours[contour] &&
5764 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5765 if(buf)
5766 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5767 cpfx++;
5768 } else if(point <= outline->contours[contour] &&
5769 outline->tags[point] & FT_Curve_Tag_On) {
5770 /* add closing pt for bezier */
5771 if(buf)
5772 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5773 cpfx++;
5774 point++;
5776 if(buf) {
5777 ppc->wType = type;
5778 ppc->cpfx = cpfx;
5780 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5782 if(buf)
5783 pph->cb = needed - pph_start;
5785 break;
5787 case GGO_BEZIER:
5789 /* Convert the quadratic Beziers to cubic Beziers.
5790 The parametric eqn for a cubic Bezier is, from PLRM:
5791 r(t) = at^3 + bt^2 + ct + r0
5792 with the control points:
5793 r1 = r0 + c/3
5794 r2 = r1 + (c + b)/3
5795 r3 = r0 + c + b + a
5797 A quadratic Bezier has the form:
5798 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5800 So equating powers of t leads to:
5801 r1 = 2/3 p1 + 1/3 p0
5802 r2 = 2/3 p1 + 1/3 p2
5803 and of course r0 = p0, r3 = p2
5806 int contour, point = 0, first_pt;
5807 FT_Outline *outline = &ft_face->glyph->outline;
5808 TTPOLYGONHEADER *pph;
5809 TTPOLYCURVE *ppc;
5810 DWORD pph_start, cpfx, type;
5811 FT_Vector cubic_control[4];
5812 if(buflen == 0) buf = NULL;
5814 if (needsTransform && buf) {
5815 pFT_Outline_Transform(outline, &transMat);
5818 for(contour = 0; contour < outline->n_contours; contour++) {
5819 pph_start = needed;
5820 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5821 first_pt = point;
5822 if(buf) {
5823 pph->dwType = TT_POLYGON_TYPE;
5824 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5826 needed += sizeof(*pph);
5827 point++;
5828 while(point <= outline->contours[contour]) {
5829 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5830 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5831 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5832 cpfx = 0;
5833 do {
5834 if(type == TT_PRIM_LINE) {
5835 if(buf)
5836 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5837 cpfx++;
5838 point++;
5839 } else {
5840 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5841 so cpfx = 3n */
5843 /* FIXME: Possible optimization in endpoint calculation
5844 if there are two consecutive curves */
5845 cubic_control[0] = outline->points[point-1];
5846 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5847 cubic_control[0].x += outline->points[point].x + 1;
5848 cubic_control[0].y += outline->points[point].y + 1;
5849 cubic_control[0].x >>= 1;
5850 cubic_control[0].y >>= 1;
5852 if(point+1 > outline->contours[contour])
5853 cubic_control[3] = outline->points[first_pt];
5854 else {
5855 cubic_control[3] = outline->points[point+1];
5856 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5857 cubic_control[3].x += outline->points[point].x + 1;
5858 cubic_control[3].y += outline->points[point].y + 1;
5859 cubic_control[3].x >>= 1;
5860 cubic_control[3].y >>= 1;
5863 /* r1 = 1/3 p0 + 2/3 p1
5864 r2 = 1/3 p2 + 2/3 p1 */
5865 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5866 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5867 cubic_control[2] = cubic_control[1];
5868 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5869 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5870 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5871 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5872 if(buf) {
5873 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5874 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5875 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5877 cpfx += 3;
5878 point++;
5880 } while(point <= outline->contours[contour] &&
5881 (outline->tags[point] & FT_Curve_Tag_On) ==
5882 (outline->tags[point-1] & FT_Curve_Tag_On));
5883 /* At the end of a contour Windows adds the start point,
5884 but only for Beziers and we've already done that.
5886 if(point <= outline->contours[contour] &&
5887 outline->tags[point] & FT_Curve_Tag_On) {
5888 /* This is the closing pt of a bezier, but we've already
5889 added it, so just inc point and carry on */
5890 point++;
5892 if(buf) {
5893 ppc->wType = type;
5894 ppc->cpfx = cpfx;
5896 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5898 if(buf)
5899 pph->cb = needed - pph_start;
5901 break;
5904 default:
5905 FIXME("Unsupported format %d\n", format);
5906 return GDI_ERROR;
5908 return needed;
5911 static BOOL get_bitmap_text_metrics(GdiFont *font)
5913 FT_Face ft_face = font->ft_face;
5914 FT_WinFNT_HeaderRec winfnt_header;
5915 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5916 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5917 font->potm->otmSize = size;
5919 #define TM font->potm->otmTextMetrics
5920 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5922 TM.tmHeight = winfnt_header.pixel_height;
5923 TM.tmAscent = winfnt_header.ascent;
5924 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5925 TM.tmInternalLeading = winfnt_header.internal_leading;
5926 TM.tmExternalLeading = winfnt_header.external_leading;
5927 TM.tmAveCharWidth = winfnt_header.avg_width;
5928 TM.tmMaxCharWidth = winfnt_header.max_width;
5929 TM.tmWeight = winfnt_header.weight;
5930 TM.tmOverhang = 0;
5931 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5932 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5933 TM.tmFirstChar = winfnt_header.first_char;
5934 TM.tmLastChar = winfnt_header.last_char;
5935 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5936 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5937 TM.tmItalic = winfnt_header.italic;
5938 TM.tmUnderlined = font->underline;
5939 TM.tmStruckOut = font->strikeout;
5940 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5941 TM.tmCharSet = winfnt_header.charset;
5943 else
5945 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5946 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5947 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5948 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5949 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5950 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5951 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5952 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5953 TM.tmOverhang = 0;
5954 TM.tmDigitizedAspectX = 96; /* FIXME */
5955 TM.tmDigitizedAspectY = 96; /* FIXME */
5956 TM.tmFirstChar = 1;
5957 TM.tmLastChar = 255;
5958 TM.tmDefaultChar = 32;
5959 TM.tmBreakChar = 32;
5960 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5961 TM.tmUnderlined = font->underline;
5962 TM.tmStruckOut = font->strikeout;
5963 /* NB inverted meaning of TMPF_FIXED_PITCH */
5964 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5965 TM.tmCharSet = font->charset;
5967 #undef TM
5969 return TRUE;
5973 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5975 double scale_x, scale_y;
5977 if (font->aveWidth)
5979 scale_x = (double)font->aveWidth;
5980 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5982 else
5983 scale_x = font->scale_y;
5985 scale_x *= fabs(font->font_desc.matrix.eM11);
5986 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5988 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5989 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5991 SCALE_Y(ptm->tmHeight);
5992 SCALE_Y(ptm->tmAscent);
5993 SCALE_Y(ptm->tmDescent);
5994 SCALE_Y(ptm->tmInternalLeading);
5995 SCALE_Y(ptm->tmExternalLeading);
5996 SCALE_Y(ptm->tmOverhang);
5998 SCALE_X(ptm->tmAveCharWidth);
5999 SCALE_X(ptm->tmMaxCharWidth);
6001 #undef SCALE_X
6002 #undef SCALE_Y
6005 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6007 double scale_x, scale_y;
6009 if (font->aveWidth)
6011 scale_x = (double)font->aveWidth;
6012 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6014 else
6015 scale_x = font->scale_y;
6017 scale_x *= fabs(font->font_desc.matrix.eM11);
6018 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6020 scale_font_metrics(font, &potm->otmTextMetrics);
6022 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6023 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6025 SCALE_Y(potm->otmAscent);
6026 SCALE_Y(potm->otmDescent);
6027 SCALE_Y(potm->otmLineGap);
6028 SCALE_Y(potm->otmsCapEmHeight);
6029 SCALE_Y(potm->otmsXHeight);
6030 SCALE_Y(potm->otmrcFontBox.top);
6031 SCALE_Y(potm->otmrcFontBox.bottom);
6032 SCALE_X(potm->otmrcFontBox.left);
6033 SCALE_X(potm->otmrcFontBox.right);
6034 SCALE_Y(potm->otmMacAscent);
6035 SCALE_Y(potm->otmMacDescent);
6036 SCALE_Y(potm->otmMacLineGap);
6037 SCALE_X(potm->otmptSubscriptSize.x);
6038 SCALE_Y(potm->otmptSubscriptSize.y);
6039 SCALE_X(potm->otmptSubscriptOffset.x);
6040 SCALE_Y(potm->otmptSubscriptOffset.y);
6041 SCALE_X(potm->otmptSuperscriptSize.x);
6042 SCALE_Y(potm->otmptSuperscriptSize.y);
6043 SCALE_X(potm->otmptSuperscriptOffset.x);
6044 SCALE_Y(potm->otmptSuperscriptOffset.y);
6045 SCALE_Y(potm->otmsStrikeoutSize);
6046 SCALE_Y(potm->otmsStrikeoutPosition);
6047 SCALE_Y(potm->otmsUnderscoreSize);
6048 SCALE_Y(potm->otmsUnderscorePosition);
6050 #undef SCALE_X
6051 #undef SCALE_Y
6054 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6056 if(!font->potm)
6058 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6060 /* Make sure that the font has sane width/height ratio */
6061 if (font->aveWidth)
6063 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6065 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6066 font->aveWidth = 0;
6070 *ptm = font->potm->otmTextMetrics;
6071 scale_font_metrics(font, ptm);
6072 return TRUE;
6075 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6077 int i;
6079 for(i = 0; i < ft_face->num_charmaps; i++)
6081 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6082 return TRUE;
6084 return FALSE;
6087 static BOOL get_outline_text_metrics(GdiFont *font)
6089 BOOL ret = FALSE;
6090 FT_Face ft_face = font->ft_face;
6091 UINT needed, lenfam, lensty;
6092 TT_OS2 *pOS2;
6093 TT_HoriHeader *pHori;
6094 TT_Postscript *pPost;
6095 FT_Fixed x_scale, y_scale;
6096 WCHAR *family_nameW, *style_nameW;
6097 static const WCHAR spaceW[] = {' ', '\0'};
6098 char *cp;
6099 INT ascent, descent;
6101 TRACE("font=%p\n", font);
6103 if(!FT_IS_SCALABLE(ft_face))
6104 return FALSE;
6106 needed = sizeof(*font->potm);
6108 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6109 family_nameW = strdupW(font->name);
6111 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6112 * sizeof(WCHAR);
6113 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6114 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6115 style_nameW, lensty/sizeof(WCHAR));
6117 /* These names should be read from the TT name table */
6119 /* length of otmpFamilyName */
6120 needed += lenfam;
6122 /* length of otmpFaceName */
6123 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6124 needed += lenfam; /* just the family name */
6125 } else {
6126 needed += lenfam + lensty; /* family + " " + style */
6129 /* length of otmpStyleName */
6130 needed += lensty;
6132 /* length of otmpFullName */
6133 needed += lenfam + lensty;
6136 x_scale = ft_face->size->metrics.x_scale;
6137 y_scale = ft_face->size->metrics.y_scale;
6139 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6140 if(!pOS2) {
6141 FIXME("Can't find OS/2 table - not TT font?\n");
6142 goto end;
6145 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6146 if(!pHori) {
6147 FIXME("Can't find HHEA table - not TT font?\n");
6148 goto end;
6151 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6153 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",
6154 pOS2->usWinAscent, pOS2->usWinDescent,
6155 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6156 ft_face->ascender, ft_face->descender, ft_face->height,
6157 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6158 ft_face->bbox.yMax, ft_face->bbox.yMin);
6160 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6161 font->potm->otmSize = needed;
6163 #define TM font->potm->otmTextMetrics
6165 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6166 ascent = pHori->Ascender;
6167 descent = -pHori->Descender;
6168 } else {
6169 ascent = pOS2->usWinAscent;
6170 descent = pOS2->usWinDescent;
6173 if(font->yMax) {
6174 TM.tmAscent = font->yMax;
6175 TM.tmDescent = -font->yMin;
6176 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6177 } else {
6178 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6179 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6180 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6181 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6184 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6186 /* MSDN says:
6187 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6189 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6190 ((ascent + descent) -
6191 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6193 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6194 if (TM.tmAveCharWidth == 0) {
6195 TM.tmAveCharWidth = 1;
6197 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6198 TM.tmWeight = FW_REGULAR;
6199 if (font->fake_bold)
6200 TM.tmWeight = FW_BOLD;
6201 else
6203 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6205 if (pOS2->usWeightClass > FW_MEDIUM)
6206 TM.tmWeight = pOS2->usWeightClass;
6208 else if (pOS2->usWeightClass <= FW_MEDIUM)
6209 TM.tmWeight = pOS2->usWeightClass;
6211 TM.tmOverhang = 0;
6212 TM.tmDigitizedAspectX = 300;
6213 TM.tmDigitizedAspectY = 300;
6214 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6215 * symbol range to 0 - f0ff
6218 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6220 TM.tmFirstChar = 0;
6221 switch(GetACP())
6223 case 1257: /* Baltic */
6224 TM.tmLastChar = 0xf8fd;
6225 break;
6226 default:
6227 TM.tmLastChar = 0xf0ff;
6229 TM.tmBreakChar = 0x20;
6230 TM.tmDefaultChar = 0x1f;
6232 else
6234 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6235 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6237 if(pOS2->usFirstCharIndex <= 1)
6238 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6239 else if (pOS2->usFirstCharIndex > 0xff)
6240 TM.tmBreakChar = 0x20;
6241 else
6242 TM.tmBreakChar = pOS2->usFirstCharIndex;
6243 TM.tmDefaultChar = TM.tmBreakChar - 1;
6245 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6246 TM.tmUnderlined = font->underline;
6247 TM.tmStruckOut = font->strikeout;
6249 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6250 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6251 (pOS2->version == 0xFFFFU ||
6252 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6253 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6254 else
6255 TM.tmPitchAndFamily = 0;
6257 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6259 case PAN_FAMILY_SCRIPT:
6260 TM.tmPitchAndFamily |= FF_SCRIPT;
6261 break;
6263 case PAN_FAMILY_DECORATIVE:
6264 TM.tmPitchAndFamily |= FF_DECORATIVE;
6265 break;
6267 case PAN_ANY:
6268 case PAN_NO_FIT:
6269 case PAN_FAMILY_TEXT_DISPLAY:
6270 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6271 /* which is clearly not what the panose spec says. */
6272 default:
6273 if(TM.tmPitchAndFamily == 0 || /* fixed */
6274 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6275 TM.tmPitchAndFamily = FF_MODERN;
6276 else
6278 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6280 case PAN_ANY:
6281 case PAN_NO_FIT:
6282 default:
6283 TM.tmPitchAndFamily |= FF_DONTCARE;
6284 break;
6286 case PAN_SERIF_COVE:
6287 case PAN_SERIF_OBTUSE_COVE:
6288 case PAN_SERIF_SQUARE_COVE:
6289 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6290 case PAN_SERIF_SQUARE:
6291 case PAN_SERIF_THIN:
6292 case PAN_SERIF_BONE:
6293 case PAN_SERIF_EXAGGERATED:
6294 case PAN_SERIF_TRIANGLE:
6295 TM.tmPitchAndFamily |= FF_ROMAN;
6296 break;
6298 case PAN_SERIF_NORMAL_SANS:
6299 case PAN_SERIF_OBTUSE_SANS:
6300 case PAN_SERIF_PERP_SANS:
6301 case PAN_SERIF_FLARED:
6302 case PAN_SERIF_ROUNDED:
6303 TM.tmPitchAndFamily |= FF_SWISS;
6304 break;
6307 break;
6310 if(FT_IS_SCALABLE(ft_face))
6311 TM.tmPitchAndFamily |= TMPF_VECTOR;
6313 if(FT_IS_SFNT(ft_face))
6315 if (font->ntmFlags & NTM_PS_OPENTYPE)
6316 TM.tmPitchAndFamily |= TMPF_DEVICE;
6317 else
6318 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6321 TM.tmCharSet = font->charset;
6323 font->potm->otmFiller = 0;
6324 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6325 font->potm->otmfsSelection = pOS2->fsSelection;
6326 font->potm->otmfsType = pOS2->fsType;
6327 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6328 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6329 font->potm->otmItalicAngle = 0; /* POST table */
6330 font->potm->otmEMSquare = ft_face->units_per_EM;
6331 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6332 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6333 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6334 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6335 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6336 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6337 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6338 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6339 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6340 font->potm->otmMacAscent = TM.tmAscent;
6341 font->potm->otmMacDescent = -TM.tmDescent;
6342 font->potm->otmMacLineGap = font->potm->otmLineGap;
6343 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6344 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6345 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6346 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6347 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6348 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6349 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6350 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6351 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6352 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6353 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6354 if(!pPost) {
6355 font->potm->otmsUnderscoreSize = 0;
6356 font->potm->otmsUnderscorePosition = 0;
6357 } else {
6358 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6359 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6361 #undef TM
6363 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6364 cp = (char*)font->potm + sizeof(*font->potm);
6365 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6366 strcpyW((WCHAR*)cp, family_nameW);
6367 cp += lenfam;
6368 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6369 strcpyW((WCHAR*)cp, style_nameW);
6370 cp += lensty;
6371 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6372 strcpyW((WCHAR*)cp, family_nameW);
6373 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6374 strcatW((WCHAR*)cp, spaceW);
6375 strcatW((WCHAR*)cp, style_nameW);
6376 cp += lenfam + lensty;
6377 } else
6378 cp += lenfam;
6379 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6380 strcpyW((WCHAR*)cp, family_nameW);
6381 strcatW((WCHAR*)cp, spaceW);
6382 strcatW((WCHAR*)cp, style_nameW);
6383 ret = TRUE;
6385 end:
6386 HeapFree(GetProcessHeap(), 0, style_nameW);
6387 HeapFree(GetProcessHeap(), 0, family_nameW);
6388 return ret;
6391 /*************************************************************
6392 * freetype_GetGlyphOutline
6394 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6395 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6397 struct freetype_physdev *physdev = get_freetype_dev( dev );
6398 DWORD ret;
6400 if (!physdev->font)
6402 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6403 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6406 GDI_CheckNotLock();
6407 EnterCriticalSection( &freetype_cs );
6408 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6409 LeaveCriticalSection( &freetype_cs );
6410 return ret;
6413 /*************************************************************
6414 * freetype_GetTextMetrics
6416 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6418 struct freetype_physdev *physdev = get_freetype_dev( dev );
6419 BOOL ret;
6421 if (!physdev->font)
6423 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6424 return dev->funcs->pGetTextMetrics( dev, metrics );
6427 GDI_CheckNotLock();
6428 EnterCriticalSection( &freetype_cs );
6429 ret = get_text_metrics( physdev->font, metrics );
6430 LeaveCriticalSection( &freetype_cs );
6431 return ret;
6434 /*************************************************************
6435 * freetype_GetOutlineTextMetrics
6437 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6439 struct freetype_physdev *physdev = get_freetype_dev( dev );
6440 UINT ret = 0;
6442 if (!physdev->font)
6444 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6445 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6448 TRACE("font=%p\n", physdev->font);
6450 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6452 GDI_CheckNotLock();
6453 EnterCriticalSection( &freetype_cs );
6455 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6457 if(cbSize >= physdev->font->potm->otmSize)
6459 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6460 scale_outline_font_metrics(physdev->font, potm);
6462 ret = physdev->font->potm->otmSize;
6464 LeaveCriticalSection( &freetype_cs );
6465 return ret;
6468 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6470 HFONTLIST *hfontlist;
6471 child->font = alloc_font();
6472 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6473 if(!child->font->ft_face)
6475 free_font(child->font);
6476 child->font = NULL;
6477 return FALSE;
6480 child->font->font_desc = font->font_desc;
6481 child->font->ntmFlags = child->face->ntmFlags;
6482 child->font->orientation = font->orientation;
6483 child->font->scale_y = font->scale_y;
6484 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6485 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6486 child->font->name = strdupW(child->face->family->FamilyName);
6487 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6488 child->font->base_font = font;
6489 list_add_head(&child_font_list, &child->font->entry);
6490 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6491 return TRUE;
6494 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6496 FT_UInt g;
6497 CHILD_FONT *child_font;
6499 if(font->base_font)
6500 font = font->base_font;
6502 *linked_font = font;
6504 if((*glyph = get_glyph_index(font, c)))
6506 *glyph = get_GSUB_vert_glyph(font, *glyph);
6507 return TRUE;
6510 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6512 if(!child_font->font)
6513 if(!load_child_font(font, child_font))
6514 continue;
6516 if(!child_font->font->ft_face)
6517 continue;
6518 g = get_glyph_index(child_font->font, c);
6519 g = get_GSUB_vert_glyph(child_font->font, g);
6520 if(g)
6522 *glyph = g;
6523 *linked_font = child_font->font;
6524 return TRUE;
6527 return FALSE;
6530 /*************************************************************
6531 * freetype_GetCharWidth
6533 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6535 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6536 UINT c;
6537 GLYPHMETRICS gm;
6538 FT_UInt glyph_index;
6539 GdiFont *linked_font;
6540 struct freetype_physdev *physdev = get_freetype_dev( dev );
6542 if (!physdev->font)
6544 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6545 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6548 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6550 GDI_CheckNotLock();
6551 EnterCriticalSection( &freetype_cs );
6552 for(c = firstChar; c <= lastChar; c++) {
6553 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6554 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6555 &gm, 0, NULL, &identity);
6556 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6558 LeaveCriticalSection( &freetype_cs );
6559 return TRUE;
6562 /*************************************************************
6563 * freetype_GetCharABCWidths
6565 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6567 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6568 UINT c;
6569 GLYPHMETRICS gm;
6570 FT_UInt glyph_index;
6571 GdiFont *linked_font;
6572 struct freetype_physdev *physdev = get_freetype_dev( dev );
6574 if (!physdev->font)
6576 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6577 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6580 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6582 GDI_CheckNotLock();
6583 EnterCriticalSection( &freetype_cs );
6585 for(c = firstChar; c <= lastChar; c++) {
6586 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6587 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6588 &gm, 0, NULL, &identity);
6589 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6590 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6591 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6592 FONT_GM(linked_font,glyph_index)->bbx;
6594 LeaveCriticalSection( &freetype_cs );
6595 return TRUE;
6598 /*************************************************************
6599 * freetype_GetCharABCWidthsI
6601 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6603 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6604 UINT c;
6605 GLYPHMETRICS gm;
6606 FT_UInt glyph_index;
6607 GdiFont *linked_font;
6608 struct freetype_physdev *physdev = get_freetype_dev( dev );
6610 if (!physdev->font)
6612 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6613 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6616 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6617 return FALSE;
6619 GDI_CheckNotLock();
6620 EnterCriticalSection( &freetype_cs );
6622 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6623 if (!pgi)
6624 for(c = firstChar; c < firstChar+count; c++) {
6625 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6626 &gm, 0, NULL, &identity);
6627 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6628 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6629 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6630 - FONT_GM(linked_font,c)->bbx;
6632 else
6633 for(c = 0; c < count; c++) {
6634 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6635 &gm, 0, NULL, &identity);
6636 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6637 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6638 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6639 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6642 LeaveCriticalSection( &freetype_cs );
6643 return TRUE;
6646 /*************************************************************
6647 * freetype_GetTextExtentExPoint
6649 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6650 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6652 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6653 INT idx;
6654 INT nfit = 0, ext;
6655 GLYPHMETRICS gm;
6656 TEXTMETRICW tm;
6657 FT_UInt glyph_index;
6658 GdiFont *linked_font;
6659 struct freetype_physdev *physdev = get_freetype_dev( dev );
6661 if (!physdev->font)
6663 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6664 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6667 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6669 GDI_CheckNotLock();
6670 EnterCriticalSection( &freetype_cs );
6672 size->cx = 0;
6673 get_text_metrics( physdev->font, &tm );
6674 size->cy = tm.tmHeight;
6676 for(idx = 0; idx < count; idx++) {
6677 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6678 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6679 &gm, 0, NULL, &identity);
6680 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6681 ext = size->cx;
6682 if (! pnfit || ext <= max_ext) {
6683 ++nfit;
6684 if (dxs)
6685 dxs[idx] = ext;
6689 if (pnfit)
6690 *pnfit = nfit;
6692 LeaveCriticalSection( &freetype_cs );
6693 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6694 return TRUE;
6697 /*************************************************************
6698 * freetype_GetTextExtentExPointI
6700 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6701 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6703 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6704 INT idx;
6705 INT nfit = 0, ext;
6706 GLYPHMETRICS gm;
6707 TEXTMETRICW tm;
6708 struct freetype_physdev *physdev = get_freetype_dev( dev );
6710 if (!physdev->font)
6712 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6713 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6716 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6718 GDI_CheckNotLock();
6719 EnterCriticalSection( &freetype_cs );
6721 size->cx = 0;
6722 get_text_metrics(physdev->font, &tm);
6723 size->cy = tm.tmHeight;
6725 for(idx = 0; idx < count; idx++) {
6726 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6727 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6728 ext = size->cx;
6729 if (! pnfit || ext <= max_ext) {
6730 ++nfit;
6731 if (dxs)
6732 dxs[idx] = ext;
6736 if (pnfit)
6737 *pnfit = nfit;
6739 LeaveCriticalSection( &freetype_cs );
6740 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6741 return TRUE;
6744 /*************************************************************
6745 * freetype_GetFontData
6747 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6749 struct freetype_physdev *physdev = get_freetype_dev( dev );
6751 if (!physdev->font)
6753 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6754 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6757 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6758 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6759 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6761 return get_font_data( physdev->font, table, offset, buf, cbData );
6764 /*************************************************************
6765 * freetype_GetTextFace
6767 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6769 INT n;
6770 struct freetype_physdev *physdev = get_freetype_dev( dev );
6772 if (!physdev->font)
6774 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6775 return dev->funcs->pGetTextFace( dev, count, str );
6778 n = strlenW(physdev->font->name) + 1;
6779 if (str)
6781 lstrcpynW(str, physdev->font->name, count);
6782 n = min(count, n);
6784 return n;
6787 /*************************************************************
6788 * freetype_GetTextCharsetInfo
6790 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6792 struct freetype_physdev *physdev = get_freetype_dev( dev );
6794 if (!physdev->font)
6796 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6797 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6799 if (fs) *fs = physdev->font->fs;
6800 return physdev->font->charset;
6803 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6805 GdiFont *font = dc->gdiFont, *linked_font;
6806 struct list *first_hfont;
6807 BOOL ret;
6809 GDI_CheckNotLock();
6810 EnterCriticalSection( &freetype_cs );
6811 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6812 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6813 if(font == linked_font)
6814 *new_hfont = dc->hFont;
6815 else
6817 first_hfont = list_head(&linked_font->hfontlist);
6818 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6820 LeaveCriticalSection( &freetype_cs );
6821 return ret;
6824 /* Retrieve a list of supported Unicode ranges for a given font.
6825 * Can be called with NULL gs to calculate the buffer size. Returns
6826 * the number of ranges found.
6828 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6830 DWORD num_ranges = 0;
6832 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6834 FT_UInt glyph_code;
6835 FT_ULong char_code, char_code_prev;
6837 glyph_code = 0;
6838 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6840 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6841 face->num_glyphs, glyph_code, char_code);
6843 if (!glyph_code) return 0;
6845 if (gs)
6847 gs->ranges[0].wcLow = (USHORT)char_code;
6848 gs->ranges[0].cGlyphs = 0;
6849 gs->cGlyphsSupported = 0;
6852 num_ranges = 1;
6853 while (glyph_code)
6855 if (char_code < char_code_prev)
6857 ERR("expected increasing char code from FT_Get_Next_Char\n");
6858 return 0;
6860 if (char_code - char_code_prev > 1)
6862 num_ranges++;
6863 if (gs)
6865 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6866 gs->ranges[num_ranges - 1].cGlyphs = 1;
6867 gs->cGlyphsSupported++;
6870 else if (gs)
6872 gs->ranges[num_ranges - 1].cGlyphs++;
6873 gs->cGlyphsSupported++;
6875 char_code_prev = char_code;
6876 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6879 else
6880 FIXME("encoding %u not supported\n", face->charmap->encoding);
6882 return num_ranges;
6885 /*************************************************************
6886 * freetype_GetFontUnicodeRanges
6888 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6890 struct freetype_physdev *physdev = get_freetype_dev( dev );
6891 DWORD size, num_ranges;
6893 if (!physdev->font)
6895 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6896 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6899 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6900 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6901 if (glyphset)
6903 glyphset->cbThis = size;
6904 glyphset->cRanges = num_ranges;
6905 glyphset->flAccel = 0;
6907 return size;
6910 /*************************************************************
6911 * freetype_FontIsLinked
6913 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6915 struct freetype_physdev *physdev = get_freetype_dev( dev );
6916 BOOL ret;
6918 if (!physdev->font)
6920 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6921 return dev->funcs->pFontIsLinked( dev );
6924 GDI_CheckNotLock();
6925 EnterCriticalSection( &freetype_cs );
6926 ret = !list_empty(&physdev->font->child_fonts);
6927 LeaveCriticalSection( &freetype_cs );
6928 return ret;
6931 static BOOL is_hinting_enabled(void)
6933 /* Use the >= 2.2.0 function if available */
6934 if(pFT_Get_TrueType_Engine_Type)
6936 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6937 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6939 #ifdef FT_DRIVER_HAS_HINTER
6940 else
6942 FT_Module mod;
6944 /* otherwise if we've been compiled with < 2.2.0 headers
6945 use the internal macro */
6946 mod = pFT_Get_Module(library, "truetype");
6947 if(mod && FT_DRIVER_HAS_HINTER(mod))
6948 return TRUE;
6950 #endif
6952 return FALSE;
6955 static BOOL is_subpixel_rendering_enabled( void )
6957 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6958 return pFT_Library_SetLcdFilter &&
6959 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6960 #else
6961 return FALSE;
6962 #endif
6965 /*************************************************************************
6966 * GetRasterizerCaps (GDI32.@)
6968 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6970 static int hinting = -1;
6971 static int subpixel = -1;
6973 if(hinting == -1)
6975 hinting = is_hinting_enabled();
6976 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6979 if ( subpixel == -1 )
6981 subpixel = is_subpixel_rendering_enabled();
6982 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6985 lprs->nSize = sizeof(RASTERIZER_STATUS);
6986 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6987 if ( subpixel )
6988 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6989 lprs->nLanguageID = 0;
6990 return TRUE;
6993 /*************************************************************
6994 * freetype_GdiRealizationInfo
6996 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6998 struct freetype_physdev *physdev = get_freetype_dev( dev );
6999 realization_info_t *info = ptr;
7001 if (!physdev->font)
7003 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7004 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7007 FIXME("(%p, %p): stub!\n", physdev->font, info);
7009 info->flags = 1;
7010 if(FT_IS_SCALABLE(physdev->font->ft_face))
7011 info->flags |= 2;
7013 info->cache_num = physdev->font->cache_num;
7014 info->unknown2 = -1;
7015 return TRUE;
7018 /*************************************************************************
7019 * Kerning support for TrueType fonts
7021 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7023 struct TT_kern_table
7025 USHORT version;
7026 USHORT nTables;
7029 struct TT_kern_subtable
7031 USHORT version;
7032 USHORT length;
7033 union
7035 USHORT word;
7036 struct
7038 USHORT horizontal : 1;
7039 USHORT minimum : 1;
7040 USHORT cross_stream: 1;
7041 USHORT override : 1;
7042 USHORT reserved1 : 4;
7043 USHORT format : 8;
7044 } bits;
7045 } coverage;
7048 struct TT_format0_kern_subtable
7050 USHORT nPairs;
7051 USHORT searchRange;
7052 USHORT entrySelector;
7053 USHORT rangeShift;
7056 struct TT_kern_pair
7058 USHORT left;
7059 USHORT right;
7060 short value;
7063 static DWORD parse_format0_kern_subtable(GdiFont *font,
7064 const struct TT_format0_kern_subtable *tt_f0_ks,
7065 const USHORT *glyph_to_char,
7066 KERNINGPAIR *kern_pair, DWORD cPairs)
7068 USHORT i, nPairs;
7069 const struct TT_kern_pair *tt_kern_pair;
7071 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7073 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7075 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7076 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7077 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7079 if (!kern_pair || !cPairs)
7080 return nPairs;
7082 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7084 nPairs = min(nPairs, cPairs);
7086 for (i = 0; i < nPairs; i++)
7088 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7089 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7090 /* this algorithm appears to better match what Windows does */
7091 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7092 if (kern_pair->iKernAmount < 0)
7094 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7095 kern_pair->iKernAmount -= font->ppem;
7097 else if (kern_pair->iKernAmount > 0)
7099 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7100 kern_pair->iKernAmount += font->ppem;
7102 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7104 TRACE("left %u right %u value %d\n",
7105 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7107 kern_pair++;
7109 TRACE("copied %u entries\n", nPairs);
7110 return nPairs;
7113 /*************************************************************
7114 * freetype_GetKerningPairs
7116 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7118 DWORD length;
7119 void *buf;
7120 const struct TT_kern_table *tt_kern_table;
7121 const struct TT_kern_subtable *tt_kern_subtable;
7122 USHORT i, nTables;
7123 USHORT *glyph_to_char;
7124 GdiFont *font;
7125 struct freetype_physdev *physdev = get_freetype_dev( dev );
7127 if (!(font = physdev->font))
7129 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7130 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7133 GDI_CheckNotLock();
7134 EnterCriticalSection( &freetype_cs );
7135 if (font->total_kern_pairs != (DWORD)-1)
7137 if (cPairs && kern_pair)
7139 cPairs = min(cPairs, font->total_kern_pairs);
7140 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7142 else cPairs = font->total_kern_pairs;
7144 LeaveCriticalSection( &freetype_cs );
7145 return cPairs;
7148 font->total_kern_pairs = 0;
7150 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7152 if (length == GDI_ERROR)
7154 TRACE("no kerning data in the font\n");
7155 LeaveCriticalSection( &freetype_cs );
7156 return 0;
7159 buf = HeapAlloc(GetProcessHeap(), 0, length);
7160 if (!buf)
7162 WARN("Out of memory\n");
7163 LeaveCriticalSection( &freetype_cs );
7164 return 0;
7167 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7169 /* build a glyph index to char code map */
7170 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7171 if (!glyph_to_char)
7173 WARN("Out of memory allocating a glyph index to char code map\n");
7174 HeapFree(GetProcessHeap(), 0, buf);
7175 LeaveCriticalSection( &freetype_cs );
7176 return 0;
7179 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7181 FT_UInt glyph_code;
7182 FT_ULong char_code;
7184 glyph_code = 0;
7185 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7187 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7188 font->ft_face->num_glyphs, glyph_code, char_code);
7190 while (glyph_code)
7192 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7194 /* FIXME: This doesn't match what Windows does: it does some fancy
7195 * things with duplicate glyph index to char code mappings, while
7196 * we just avoid overriding existing entries.
7198 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7199 glyph_to_char[glyph_code] = (USHORT)char_code;
7201 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7204 else
7206 ULONG n;
7208 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7209 for (n = 0; n <= 65535; n++)
7210 glyph_to_char[n] = (USHORT)n;
7213 tt_kern_table = buf;
7214 nTables = GET_BE_WORD(tt_kern_table->nTables);
7215 TRACE("version %u, nTables %u\n",
7216 GET_BE_WORD(tt_kern_table->version), nTables);
7218 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7220 for (i = 0; i < nTables; i++)
7222 struct TT_kern_subtable tt_kern_subtable_copy;
7224 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7225 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7226 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7228 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7229 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7230 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7232 /* According to the TrueType specification this is the only format
7233 * that will be properly interpreted by Windows and OS/2
7235 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7237 DWORD new_chunk, old_total = font->total_kern_pairs;
7239 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7240 glyph_to_char, NULL, 0);
7241 font->total_kern_pairs += new_chunk;
7243 if (!font->kern_pairs)
7244 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7245 font->total_kern_pairs * sizeof(*font->kern_pairs));
7246 else
7247 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7248 font->total_kern_pairs * sizeof(*font->kern_pairs));
7250 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7251 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7253 else
7254 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7256 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7259 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7260 HeapFree(GetProcessHeap(), 0, buf);
7262 if (cPairs && kern_pair)
7264 cPairs = min(cPairs, font->total_kern_pairs);
7265 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7267 else cPairs = font->total_kern_pairs;
7269 LeaveCriticalSection( &freetype_cs );
7270 return cPairs;
7273 static const struct gdi_dc_funcs freetype_funcs =
7275 NULL, /* pAbortDoc */
7276 NULL, /* pAbortPath */
7277 NULL, /* pAlphaBlend */
7278 NULL, /* pAngleArc */
7279 NULL, /* pArc */
7280 NULL, /* pArcTo */
7281 NULL, /* pBeginPath */
7282 NULL, /* pBlendImage */
7283 NULL, /* pChoosePixelFormat */
7284 NULL, /* pChord */
7285 NULL, /* pCloseFigure */
7286 NULL, /* pCopyBitmap */
7287 NULL, /* pCreateBitmap */
7288 NULL, /* pCreateCompatibleDC */
7289 freetype_CreateDC, /* pCreateDC */
7290 NULL, /* pDeleteBitmap */
7291 freetype_DeleteDC, /* pDeleteDC */
7292 NULL, /* pDeleteObject */
7293 NULL, /* pDescribePixelFormat */
7294 NULL, /* pDeviceCapabilities */
7295 NULL, /* pEllipse */
7296 NULL, /* pEndDoc */
7297 NULL, /* pEndPage */
7298 NULL, /* pEndPath */
7299 freetype_EnumFonts, /* pEnumFonts */
7300 NULL, /* pEnumICMProfiles */
7301 NULL, /* pExcludeClipRect */
7302 NULL, /* pExtDeviceMode */
7303 NULL, /* pExtEscape */
7304 NULL, /* pExtFloodFill */
7305 NULL, /* pExtSelectClipRgn */
7306 NULL, /* pExtTextOut */
7307 NULL, /* pFillPath */
7308 NULL, /* pFillRgn */
7309 NULL, /* pFlattenPath */
7310 freetype_FontIsLinked, /* pFontIsLinked */
7311 NULL, /* pFrameRgn */
7312 NULL, /* pGdiComment */
7313 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7314 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7315 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7316 freetype_GetCharWidth, /* pGetCharWidth */
7317 NULL, /* pGetDeviceCaps */
7318 NULL, /* pGetDeviceGammaRamp */
7319 freetype_GetFontData, /* pGetFontData */
7320 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7321 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7322 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7323 NULL, /* pGetICMProfile */
7324 NULL, /* pGetImage */
7325 freetype_GetKerningPairs, /* pGetKerningPairs */
7326 NULL, /* pGetNearestColor */
7327 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7328 NULL, /* pGetPixel */
7329 NULL, /* pGetPixelFormat */
7330 NULL, /* pGetSystemPaletteEntries */
7331 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7332 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7333 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7334 freetype_GetTextFace, /* pGetTextFace */
7335 freetype_GetTextMetrics, /* pGetTextMetrics */
7336 NULL, /* pGradientFill */
7337 NULL, /* pIntersectClipRect */
7338 NULL, /* pInvertRgn */
7339 NULL, /* pLineTo */
7340 NULL, /* pModifyWorldTransform */
7341 NULL, /* pMoveTo */
7342 NULL, /* pOffsetClipRgn */
7343 NULL, /* pOffsetViewportOrg */
7344 NULL, /* pOffsetWindowOrg */
7345 NULL, /* pPaintRgn */
7346 NULL, /* pPatBlt */
7347 NULL, /* pPie */
7348 NULL, /* pPolyBezier */
7349 NULL, /* pPolyBezierTo */
7350 NULL, /* pPolyDraw */
7351 NULL, /* pPolyPolygon */
7352 NULL, /* pPolyPolyline */
7353 NULL, /* pPolygon */
7354 NULL, /* pPolyline */
7355 NULL, /* pPolylineTo */
7356 NULL, /* pPutImage */
7357 NULL, /* pRealizeDefaultPalette */
7358 NULL, /* pRealizePalette */
7359 NULL, /* pRectangle */
7360 NULL, /* pResetDC */
7361 NULL, /* pRestoreDC */
7362 NULL, /* pRoundRect */
7363 NULL, /* pSaveDC */
7364 NULL, /* pScaleViewportExt */
7365 NULL, /* pScaleWindowExt */
7366 NULL, /* pSelectBitmap */
7367 NULL, /* pSelectBrush */
7368 NULL, /* pSelectClipPath */
7369 freetype_SelectFont, /* pSelectFont */
7370 NULL, /* pSelectPalette */
7371 NULL, /* pSelectPen */
7372 NULL, /* pSetArcDirection */
7373 NULL, /* pSetBkColor */
7374 NULL, /* pSetBkMode */
7375 NULL, /* pSetDCBrushColor */
7376 NULL, /* pSetDCPenColor */
7377 NULL, /* pSetDIBColorTable */
7378 NULL, /* pSetDIBitsToDevice */
7379 NULL, /* pSetDeviceClipping */
7380 NULL, /* pSetDeviceGammaRamp */
7381 NULL, /* pSetLayout */
7382 NULL, /* pSetMapMode */
7383 NULL, /* pSetMapperFlags */
7384 NULL, /* pSetPixel */
7385 NULL, /* pSetPixelFormat */
7386 NULL, /* pSetPolyFillMode */
7387 NULL, /* pSetROP2 */
7388 NULL, /* pSetRelAbs */
7389 NULL, /* pSetStretchBltMode */
7390 NULL, /* pSetTextAlign */
7391 NULL, /* pSetTextCharacterExtra */
7392 NULL, /* pSetTextColor */
7393 NULL, /* pSetTextJustification */
7394 NULL, /* pSetViewportExt */
7395 NULL, /* pSetViewportOrg */
7396 NULL, /* pSetWindowExt */
7397 NULL, /* pSetWindowOrg */
7398 NULL, /* pSetWorldTransform */
7399 NULL, /* pStartDoc */
7400 NULL, /* pStartPage */
7401 NULL, /* pStretchBlt */
7402 NULL, /* pStretchDIBits */
7403 NULL, /* pStrokeAndFillPath */
7404 NULL, /* pStrokePath */
7405 NULL, /* pSwapBuffers */
7406 NULL, /* pUnrealizePalette */
7407 NULL, /* pWidenPath */
7408 /* OpenGL not supported */
7411 #else /* HAVE_FREETYPE */
7413 /*************************************************************************/
7415 BOOL WineEngInit(void)
7417 return FALSE;
7419 BOOL WineEngDestroyFontInstance(HFONT hfont)
7421 return FALSE;
7424 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7426 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7427 return 1;
7430 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7432 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7433 return TRUE;
7436 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7438 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7439 return NULL;
7442 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7444 return FALSE;
7447 /*************************************************************************
7448 * GetRasterizerCaps (GDI32.@)
7450 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7452 lprs->nSize = sizeof(RASTERIZER_STATUS);
7453 lprs->wFlags = 0;
7454 lprs->nLanguageID = 0;
7455 return TRUE;
7458 #endif /* HAVE_FREETYPE */